Home > Back-end >  Julia code not finishing while Python code does
Julia code not finishing while Python code does

Time:09-11

I am very new to Julia and was trying to implement/rewrite some of my previous Python code as practice. I was using the Project Euler problem 25 as practice

In Python I have

def fibonacci(N):
    """Returns the Nth Fibonacci Number"""
    F = [0, 1] 
    i = 0
    while i <= N-2:
        F_new = F[i]   F[i 1]
        F.append(F_new)
        i  = 1
    return F[N]

N = 0 
x = 1000

while len(str(fibonacci(N))) <= x:
    if len(str(fibonacci(N))) == x:
        print(N)
        break     
    N = N   1

Which runs and gives me the correct answer in about 6.5 seconds. When trying to do this in Julia below

function fib(N)
    F = [0, 1]
    global i = 1
    while i <= N-2
        F_new = F[i]   F[i 1]
        append!(F, F_new)
        global i  = 1
    end
    return F[N]
end

N = 1
x = 1000

while length(string(fib(N))) <= x
    if length(string(fib(N))) == x
        print(N-1)
        break
    end
global N  = 1
end

The code seems to run "forever". However in the Julia code only when x<= 20 will the code finish and produce the correct answer. In the Julia code when x>20 the program never ends.

I'm not sure where something could go wrong if it runs for all values below 21? Could somebody explain where the error is happening and why?

CodePudding user response:

Python integers are by default unbounded in size and will grow as needed. Julia on the other hand will default to a signed 64 bit integer if on a 64 bit system. (See docs) This begins to overflow when trying to calculate values above around 19 digits long, hence why this starts around x=20. In order to get the same behavior in Julia, you should use the BigInt type for any values or arguments which can get above this size.

CodePudding user response:

In addition to the earlier answer, note that you should avoid globals if looking at performance, so this is much faster than your global i and x code:

function fib(N)
    F = [big"0", big"1"]
    for i in 1:N-2
        F_new = F[i]   F[i 1]
        push!(F, F_new)
    end
    return F[N]
end

function test(x = 1000)
    N = 1
    while length(string(fib(N))) <= x
        if length(string(fib(N))) == x
            print(N-1)
            break
        end
        N  = 1
    end
end

test()

CodePudding user response:

The main problem with your code is what @duckboycool has described. The second advice is to always write functions in Julia. Read the Julia performance tips page for a good start.

Note that you can make the function by @Bill 2X faster by removing the unnecessary if like this:

function test(x = 1000)
    N = 0
    while ndigits(fib(N)) < x
        N  = 1
    end
    return N
end

But if you really want a 16000X faster Julia version, then you can do this:

function euler25()
    limit = big(10)^999
    a, b = big(1), big(1)
    N = 2
    while b <= limit
        a, b = b, a   b
        N  = 1
    end
    return N
end

@btime euler25() = 4782
  377.700 μs (9573 allocations: 1.15 MiB)

This runs in 377 μs, because we avoid calculating fib(N) at every step from the beginning. And instead of comparing with the length of a string of the output at each iteration, we just compare with 10^999.

  • Related