I leave it to someone with more insights to comment on the efficiency of 
nested functions, but this seems at least to be substantially faster:

type State
    a::Uint64
    b::Uint64
    aa::Uint64
    bb::Uint64
    cc::Uint64
    RANDSIZL::Int
    RANDSIZ::Int
end

function ind(s::State, mm, x)
    return mm[1 + (x & ((s.RANDSIZ-1)<<3))>>3]
end

function rngstep(s::State, randrsl, mm, a_mix, m1, m2, r, i)
    x = mm[m1 + i]
    s.a = a_mix + mm[m2 + i]
    mm[m1 + i] = y = ind(s, mm, x) + s.a + s.b
    randrsl[r + i] = s.b = ind(s, mm, y >> s.RANDSIZL) + x
end

function isaac64(s::State, randrsl, mm)
    s.a = s.aa
    s.cc += 1
    s.b = s.bb + s.cc
    m1 = r = 0
    mid = m2 = s.RANDSIZ >> 1
    for i = 1:4:mid-2
        rngstep(s, randrsl, mm, ~(s.a $ (s.a << 21)), m1, m2, r, i)
        rngstep(s, randrsl, mm,   s.a $ (s.a >> 5),   m1, m2, r, i + 1)
        rngstep(s, randrsl, mm,   s.a $ (s.a << 12),  m1, m2, r, i + 2)
        rngstep(s, randrsl, mm,   s.a $ (s.a >> 33),  m1, m2, r, i + 3)
    end
    m2 = 0
    r = m1 = s.RANDSIZ >> 1
    for i = 1:4:mid-2
        rngstep(s, randrsl, mm, ~(s.a $ (s.a << 21)), m1, m2, r, i)
        rngstep(s, randrsl, mm,   s.a $ (s.a >> 5),   m1, m2, r, i + 1)
        rngstep(s, randrsl, mm,   s.a $ (s.a << 12),  m1, m2, r, i + 2)
        rngstep(s, randrsl, mm,   s.a $ (s.a >> 33),  m1, m2, r, i + 3)
    end
    s.bb = s.b
    s.aa = s.a;
end

macro mix()
    quote
        a -= e; f $= h >> 9;  h += a
        b -= f; g $= a << 9;  a += b
        c -= g; h $= b >> 23; b += c
        d -= h; a $= c << 15; c += d
        e -= a; b $= d >> 14; d += e
        f -= b; c $= e << 20; e += f
        g -= c; d $= f >> 17; f += g
        h -= d; e $= g << 14; g += h
    end
end

function randinit(randrsl, mm, RANDSIZL, RANDSIZ, flag=false)
    a = b = c = d = e = f = g = h = 0x9e3779b97f4a7c13
    for i = 1:4
        @mix
    end
    for i = 1:8:RANDSIZ
        if flag
            a += randrsl[i  ]
            b += randrsl[i+1]
            c += randrsl[i+2]
            d += randrsl[i+3]
            e += randrsl[i+4]
            f += randrsl[i+5]
            g += randrsl[i+6]
            h += randrsl[i+7]
        end
        @mix
        mm[i  ] = a
        mm[i+1] = b
        mm[i+2] = c
        mm[i+3] = d
        mm[i+4] = e
        mm[i+5] = f
        mm[i+6] = g
        mm[i+7] = h
    end
    if flag
        for i = 1:8:RANDSIZ
            a += mm[i  ]
            b += mm[i+1]
            c += mm[i+2]
            d += mm[i+3]
            e += mm[i+4]
            f += mm[i+5]
            g += mm[i+6]
            h += mm[i+7]
            @mix
            mm[i  ] = a
            mm[i+1] = b
            mm[i+2] = c
            mm[i+3] = d
            mm[i+4] = e
            mm[i+5] = f
            mm[i+6] = g
            mm[i+7] = h
        end
    end
    z = 0x0000000000000000
    s2 = State(z, z, z, z, z, RANDSIZL, RANDSIZ)
    isaac64(s2, randrsl, mm)
    return s2
end

function main(randrsl::Vector{Uint64}=Uint64[])
    RANDSIZL = 8
    RANDSIZ = length(randrsl)
    if RANDSIZ == 0
        RANDSIZ = 256
        resize!(randrsl, RANDSIZ)
        fill!(randrsl, uint64(0))
    elseif RANDSIZ % 8 != 0
        error("dimension of seeding array must be a factor of 8")
    end
    mm = zeros(Uint64, RANDSIZ)
    s = randinit(randrsl, mm, RANDSIZL, RANDSIZ, true)
    for i = 1:2
        isaac64(s, randrsl, mm)
    end
end

function timeit(f, n=10^4)
    f()
    t = time()
    for i = 1:n
        f()
    end
    @printf("avg running time: %llf \n", ((time() -t) / n ))
end


Den fredagen den 17:e oktober 2014 kl. 22:58:35 UTC+2 skrev alexander 
maznev:
>
> I was trying out Julia for the first time and did not seem to find a 
> CSPRNG available. Below is a port of Isaac64 (
> http://burtleburtle.net/bob/rand/isaacafa.html). My runtime meassurements 
> seem to be very poor - reading a little bit about Julia prior to trying the 
> language, and especially looking at the benchmarks I was under the 
> impression that run times should be relatively comparable with C. Would 
> appreciate some feedback, thanks. 
>
>
> function main(randrsl::Array{Uint64}=Uint64[]) #takes Uint64 array as a 
> seed
> #wrap everything to pass variables into sub-scopes implicitly
>     function isaac64()
>         function ind(mm,x)                #nesting ind() into rngstep 
> makes it another 2-3 times slower -!
>             return mm[int((x & ((RANDSIZ-1)<<3))/8)+1]
>         end
>         function rngstep(a_mix,m1,m2,r)
>             x = mm[m1+i]
>             a = (a_mix) + mm[m2+i]
>             mm[m1+i] = y = (ind(mm, x) + a + b)
>             randrsl[r+i] = b = (ind(mm, y>>RANDSIZL) + x)
>             i+=1
>         end
>         a=aa; cc+=1; b=bb+cc; x=0x0000000000::Uint64; 
>         m1=r=0;mid=m2=int(RANDSIZ/2); i=1;
>         while (i < (mid-2)) #do it without pointers
>             rngstep(~(a$(a<<21)), m1, m2, r) #sub-indexing an array 
> creates a new object, pass indexes as variables
>             rngstep(a$(a>>5), m1, m2, r)
>             rngstep(a$(a<<12), m1, m2, r)
>             rngstep(a$(a>>33), m1, m2, r)
>         end
>         i=1; m2=0; r=m1=(RANDSIZ/2);
>         while (i<(mid-2))
>             rngstep(~(a$(a<<21)),m1, m2, r)
>             rngstep(a$(a>>5), m1, m2, r)
>             rngstep(a$(a<<12), m1, m2, r)
>             rngstep(a$(a>>33), m1, m2, r)
>         end
>         bb = b; aa=a;
>     end
>
>     function randinit(flag=false)
>         function mix!()
>             a-=e; f$=h>>9; h+=a;    #$ for bitwise xor
>             b-=f; g$=a<<9;  a+=b;    #glad they didn't remove semi-columns
>             c-=g; h$=b>>23; b+=c;
>             d-=h; a$=c<<15; c+=d;
>             e-=a; b$=d>>14; d+=e;
>             f-=b; c$=e<<20; e+=f;
>             g-=c; d$=f>>17; f+=g;
>             h-=d; e$=g<<14; g+=h;
>         end
>         a=b=c=d=e=f=g=h= 0x9e3779b97f4a7c13::Uint64
>         for i in range(1,4)
>             mix!()
>         end
>         for i in range(1,8, int(RANDSIZ/8)) #dividing 256/8 produced a 
> float
>             if flag
>                 a+= randrsl[i ]; b+=randrsl[i+1]; c+=randrsl[i+2]; 
> d+=randrsl[i+3];
>                 e+=randrsl[i+4]; f+=randrsl[i+5]; g+=randrsl[i+6]; 
> h+=randrsl[i+7];
>             end
>             mix!()
>             mm[i  ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d;
>             mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h;
>         end
>         if flag
>             for i in range(1,8, int(RANDSIZ/8))
>                 a+=mm[i  ]; b+=mm[i+1]; c+=mm[i+2]; d+=mm[i+3];
>                 e+=mm[i+4]; f+=mm[i+5]; g+=mm[i+6]; h+=mm[i+7];
>             mix!()
>                 mm[i  ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d;
>                 mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h;
>             end
>         end
>             isaac64()
>             randcnt=RANDSIZ
>     end
>     #main scope variables
>     RANDSIZL=8; RANDSIZ = length(randrsl); #add a function to allow 32byte 
> input array
>     if RANDSIZ == 0
>         RANDSIZ = 256
>         for i in range(1,RANDSIZ)
>             push!(randrsl, 0)
>         end                    #end statement for each conditional
>     elseif RANDSIZ % 8 != 0            # would have prefered elif
>         error("dimension of seeding array must be a factor of 8")
>     end
>     aa=bb=cc=0x0000000000::Uint64  #really won't take 0::Uint64 ?
>     mm=Uint64[]
>     for i in range(1,RANDSIZ) #indexes start with 1
>         push!(mm, 0)
>     end
>     randinit(true)
>     for i in range(1,2)
>         isaac64()
>         for j in range(1,RANDSIZ)
>             @printf("%llx",randrsl[j]) #@printf for c string formatting
>         end
>     end
> end
> function timeit(f, n=10^4)
>     t = time()
>     for i in range(1,n)
>         f()
>     end
>     @printf("avg running time: %llf \n", ((time() -t) / n ))
>     end
> timeit(main)
>

Reply via email to