2

I have a while loop that calculates the roots of my equation. It works perfectly when I am working with low numbers, for example 100, the precision is a little more than 250 decimal places (I need 250 decimal places of precision).

The problem is when I increase the amount of my loop. The higher the amount, after 100 roots are found, the precision gets lower and lower. When I make it to a thousand roots, the precision of the last root is only 6 decimal places.

This is my code:

setprecision(BigFloat, 250; base=10)

Mp = BigFloat("250.0")
L = BigFloat("1.0")
rp = BigFloat("1.0")


exp = Mp - 10
pk = 50
h = 1/10
ts = -2*pk
te = -h
v0 = -pk
vmax = 0
u0 = 0
umax = pk
k1 = (vmax -v0)/h
k2 = (umax -u0)/h
 
max = 100.0
function arctanh(x)
    if abs2(x) < 1
        res = BigFloat(log( ( 1 + x ) / (1 - x)  ))
    else
        res = BigFloat(sign(x) * log1p( ( 2 * abs(x) ) / (1 - abs2(x)) ))
    end
    return 0.5*res
end

function tor_2(r)
    a = BigFloat( rp / r )
    b = BigFloat(arctanh(a))
    res = BigFloat(L^2 * (-b / rp))
    return res
end

function find_root(f, a, b, precision)
    oldm = big(a)
    n = big(a)
    p = big(b)
    m = (n + p) / big(2)
    epsilon = big(10)^(-precision)

    while abs(f(m)) > epsilon && oldm != m
        oldm = m
        val = f(m)
        if val > 0
            p = m
        elseif val < 0
            n = m
        else
            break
        end
        m = (n + p) / BigFloat(2.0)
    end
    return m
 
end
t = @elapsed begin
    tort = [find_root(r -> tor_2(r) - test, rp + 10.0^-exp, max, Mp) for test in ts:h:te]
end

where tort[1]= 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000276779305347347506129736291395816937080609516467895441878785070622487206090198597561760179491324750990568982322199122021923608490714617064493293276254845275543133336, that is correct.

But, tort[1000]:10.033311132253989056880435010549127161920612410233012969744805223401820078850954716601912612057050747701277915837004398085186404284469580227204776685726634389654992756053090443362119682617587346589647165675974434032301224533470334376859854777986199219 is wrong.

The value was supposed to be: 10.03331113225398961014527049285149912673425410710831002117675758378789785273643535498548789545079535319530347609313690968614200882388184338974490564270302639426889010992841078245555898544027132450710912524700458841030045198039559947676313086937548943

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • For some reason - I don't know what - my code is losing precision when it is iterated several times. I would like to know what the problem is. At first I thought it was the BigFloat package, but apparently it's not. I am at a loss. – Willian Andrade Apr 28 '23 at 00:47
  • I think this is caused by floating point math. See for example [here](https://quant.stackexchange.com/a/63891/54838). – AKdemy Apr 28 '23 at 07:43

1 Answers1

2

I recommmend reading What Every Computer Scientist Should Know About Floating-Point Arithmetic, by David Goldberg and having a look at this answer.

I do not have time to go through the code in detail, but the following already gets you to a precision of 10.0333111322539896101452704928514991267342541071083100211767575837878978527364353549854878954507953531953034760931369096861420088238818433897449056427030263942688901099284107824555589854402713245071091252470045884103004519803955994767631308693754895186 which is correct up to the last two digits 10.0333111322539896101452704928514991267342541071083100211767575837878978527364353549854878954507953531953034760931369096861420088238818433897449056427030263942688901099284107824555589854402713245071091252470045884103004519803955994767631308693754895186 (it displays two more).

setprecision(BigFloat, 250; base=10)
    
    Mp = 250.0
    L = 1.0
    rp = 1
    
    
    exp = Mp - 10
    pk = 50
    h = 1//10
    ts = -2*pk
    te = -h
    v0 = -pk
    vmax = 0
    u0 = 0
    umax = pk
    k1 = (vmax -v0)//h
    k2 = (umax -u0)//h
     
    max = 100.0
    function arctanh(x)
        if abs2(x) < 1
            res = BigFloat(log( ( 1 + x ) / (1 - x)  ))
        else
            res = BigFloat(sign(x) * log1p( ( 2 * abs(x) ) / (1 - abs2(x)) ))
        end
        return 0.5*res
    end
    
    function tor_2(r)
        a = BigFloat( rp / r )
        b = BigFloat(arctanh(a))
        res = BigFloat(L^2 * (-b / rp))
        return res
    end
    
    function find_root(f, a, b, precision)
        oldm = big(a)
        n = big(a)
        p = big(b)
        m = (n + p) / big(2)
        epsilon = big(10)^(-precision)
    
        while abs(f(m)) > epsilon && oldm != m
            oldm = m
            val = f(m)
            if val > 0
                p = m
            elseif val < 0
                n = m
            else
                break
            end
            m = (n + p) / BigFloat(2.0)
        end
        return m
     
    end
    t = @elapsed begin
        tort = [find_root(r -> tor_2(r) - test, rp + 10.0^-exp, max, Mp) for test in ts:h:te]
    end

Quick explanation:

if you look at [test for test in ts:h:te] you see that you frequently divide by 5 or 10. However, these floating point numbers result in an inexact representation of rational numbers. In other words, 1/5 == 1//5 is false.

AKdemy
  • 215
  • 1
  • 2
  • 6