JuliaでProject Euler(4)

Problem 4

https://projecteuler.net/problem=4

Pythonで次のように書く。

import sys

def digits(n):
    ds = []
    while n > 0:
        n, r = divmod(n, 10)
        ds.append(r)
    return ds

def is_palindromic(n):
    ds = digits(n)
    L = len(ds)
    return all(ds[k] == ds[L-k-1] for k in xrange((L+1)/2))

def e004(E):
    max_a = 10**E-1
    max_n = 0
    for a in xrange(max_a, 10**(E-1)-1, -1):
        for b in xrange(max_a, max(a, (max_n+a-1)/a)-1, -1):
            n = a*b
            if is_palindromic(n):
                max_n = n
                break
    return max_n

N = int(sys.argv[1])
print e004(N)

これをそのままJuliaに翻訳する。

function digits(n)
    a = []
    while n > 0
        r = n%10
        n = div(n, 10)
        push!(a, r)
    end
    return a
end

function is_palindromic(n)
    a = digits(n)
    L = length(a)
    for i in 1:div(L+1, 2)
        if a[i] != a[L-i+1]
            return false
        end
    end
    return true
end

function e004(E)
    local max_n = 0
    local max_a = 10^E-1
    for a in max_a:-1:10^(E-1)
        for b in max_a:-1:max(a, div(max_n+a-1, a))
            n = a*b
            if is_palindromic(n)
                max_n = n
                break
            end
        end
    end
    return max_n
end

N = parse(Int, ARGS[1])
println(e004(N))

配列のインデックスは、0ではなく1から始まります。まるで地動説から天動説に逆戻りしたかのようですね。

$ time pypy e004.py 8
9999000000009999

real    0m5.356s
user    0m5.281s
sys     0m0.047s

$ time julia e004.jl 8
9999000000009999

real    0m10.907s
user    0m10.922s
sys     0m0.594s

Juliaが遅いのは、たぶん最初のdigitsの中の、

a = []

で、これだと型が、

Array{Any,1}

で、1次元の配列で要素の型は何でもありとなる。
こういうときは、型を指定するとよい。

    a::Array{Int,1} = []
time julia e004a.jl 8
9999000000009999

real    0m8.420s
user    0m8.516s
sys     0m0.547s

あまり速くならない。
divmodが無いのが効いているのだろうか。

Edit:
PyPyでdivmodをやめたが、速度は変わらなかった。