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)
>