1
1
module Random
2
2
3
- using Base. dSFMT
3
+ using Base: dSFMT, IntTypes
4
4
using Base. GMP: GMP_VERSION, Limb
5
5
6
6
export srand,
@@ -361,97 +361,85 @@ rem_knuth{T<:Unsigned}(a::T, b::T) = b != 0 ? a % b : a
361
361
# maximum multiple of k <= 2^bits(T) decremented by one,
362
362
# that is 0xFFFFFFFF if k = typemax(T) - typemin(T) with intentional underflow
363
363
maxmultiple (k:: UInt32 ) = (div (0x0000000100000000 ,k + (k == 0 ))* k - 1 ) % UInt32
364
- maxmultiple (k:: UInt64 ) = (div (0x00000000000000010000000000000000 , k + (k == 0 ))* k - 1 ) % UInt64
364
+
365
+ maxmultiple64 (k:: UInt64 ) = (div (0x00000000000000010000000000000000 , k + (k == 0 ))* k - 1 ) % UInt64
366
+
367
+ # maximum multiple of k within 1:2^32 or 1:2^64, depending on size
368
+ maxmultiple (k:: UInt64 ) = (div ((k >> 32 != 0 )* 0x0000000000000000FFFFFFFF00000000 + 0x0000000100000000 , k + (k == 0 ))* k - 1 ) % UInt64
369
+
365
370
# maximum multiple of k within 1:typemax(UInt128)
366
371
maxmultiple (k:: UInt128 ) = div (typemax (UInt128), k + (k == 0 ))* k - 1
367
- # maximum multiple of k within 1:2^32 or 1:2^64, depending on size
368
- maxmultiplemix (k:: UInt64 ) = (div ((k >> 32 != 0 )* 0x0000000000000000FFFFFFFF00000000 + 0x0000000100000000 , k + (k == 0 ))* k - 1 ) % UInt64
369
372
370
- abstract RangeGenerator
373
+ # utility to generate random numbers in a range
374
+ abstract RangeGenerator{T<: Integer }
371
375
372
- immutable RangeGeneratorInt{T<: Integer , U<: Unsigned } <: RangeGenerator
373
- a:: T # first element of the range
376
+ immutable RangeGeneratorInt{T<: Integer , U<: Union(UInt32, UInt64, UInt128) } <: RangeGenerator{T}
374
377
k:: U # range length or zero for full range
375
378
u:: U # rejection threshold
376
379
end
377
- # generators with 32, 128 bits entropy
378
- RangeGeneratorInt {T, U<:Union(UInt32, UInt128)} (a:: T , k:: U ) = RangeGeneratorInt {T, U} (a, k, maxmultiple (k))
379
- # mixed 32/64 bits entropy generator
380
- RangeGeneratorInt {T} (a:: T , k:: UInt64 ) = RangeGeneratorInt {T,UInt64} (a, k, maxmultiplemix (k))
381
380
382
-
383
- # generator for ranges
384
- RangeGenerator {T<:Unsigned} (r:: UnitRange{T} ) = isempty (r) ? error (" range must be non-empty" ) : RangeGeneratorInt (first (r), last (r) - first (r) + one (T))
385
-
386
- # specialized versions
387
- for (T, U) in [(UInt8, UInt32), (UInt16, UInt32),
388
- (Int8, UInt32), (Int16, UInt32), (Int32, UInt32), (Int64, UInt64), (Int128, UInt128),
389
- (Bool, UInt32)]
390
-
391
- @eval RangeGenerator (r:: UnitRange{$T} ) = isempty (r) ? error (" range must be non-empty" ) : RangeGeneratorInt (first (r), convert ($ U, unsigned (last (r) - first (r)) + one ($ U))) # overflow ok
392
- end
381
+ @inline RangeGenerator {T, U} (:: Type{T} , m:: U ) = (k= m+ one (U); RangeGeneratorInt {T, U} (k, maxmultiple (k)))
393
382
394
383
if GMP_VERSION. major >= 6
395
- immutable RangeGeneratorBigInt <: RangeGenerator
396
- a:: BigInt # first
384
+ immutable RangeGeneratorBigInt <: RangeGenerator{BigInt}
397
385
m:: BigInt # range length - 1
398
386
nlimbs:: Int # number of limbs in generated BigInt's
399
387
mask:: Limb # applied to the highest limb
400
388
end
401
389
402
390
else
403
- immutable RangeGeneratorBigInt <: RangeGenerator
404
- a:: BigInt # first
391
+ immutable RangeGeneratorBigInt <: RangeGenerator{BigInt}
405
392
m:: BigInt # range length - 1
406
393
limbs:: Vector{Limb} # buffer to be copied into generated BigInt's
407
394
mask:: Limb # applied to the highest limb
408
395
409
- RangeGeneratorBigInt (a, m, nlimbs, mask) = new (a, m, Array (Limb, nlimbs), mask)
396
+ RangeGeneratorBigInt (m, nlimbs, mask) = new (m, Array (Limb, nlimbs), mask)
410
397
end
411
398
end
412
399
413
-
414
-
415
- function RangeGenerator (r:: UnitRange{BigInt} )
416
- m = last (r) - first (r)
417
- m < 0 && error (" range must be non-empty" )
400
+ function RangeGenerator (:: Type{BigInt} , m:: BigInt )
418
401
nd = ndigits (m, 2 )
419
402
nlimbs, highbits = divrem (nd, 8 * sizeof (Limb))
420
403
highbits > 0 && (nlimbs += 1 )
421
404
mask = highbits == 0 ? ~ zero (Limb) : one (Limb)<< highbits - one (Limb)
422
- return RangeGeneratorBigInt (first (r), m, nlimbs, mask)
405
+ return RangeGeneratorBigInt (m, nlimbs, mask)
423
406
end
424
407
408
+ # RangeGenerator dispatch
425
409
426
- # this function uses 32 bit entropy for small ranges of length <= typemax(UInt32) + 1
427
- # RangeGeneratorInt is responsible for providing the right value of k
428
- function rand {T<:Union(UInt64, Int64)} (rng:: AbstractRNG , g:: RangeGeneratorInt{T,UInt64} )
429
- local x:: UInt64
430
- if (g. k - 1 ) >> 32 == 0
431
- x = rand (rng, UInt32)
432
- while x > g. u
433
- x = rand (rng, UInt32)
434
- end
435
- else
436
- x = rand (rng, UInt64)
437
- while x > g. u
438
- x = rand (rng, UInt64)
439
- end
440
- end
441
- return reinterpret (T, reinterpret (UInt64, g. a) + rem_knuth (x, g. k))
442
- end
410
+ @inline checknonempty (r) = isempty (r) && error (" collection must be non-empty" )
411
+ @inline RangeGenerator (r:: AbstractArray ) = (checknonempty (r); n = length (r); RangeGenerator (n- one (n)))
412
+ @inline RangeGenerator {T<:Union(IntTypes...,BigInt)} (r:: UnitRange{T} ) = (checknonempty (r); RangeGenerator (last (r)- first (r)))
413
+
414
+ @inline RangeGenerator {T<:Union(UInt32,UInt64,UInt128,BigInt)} (m:: T ) = RangeGenerator (T, m)
415
+ @inline RangeGenerator {T<:Union(Int32,Int64,Int128)} (m:: T ) = RangeGenerator (T, unsigned (m))
416
+ @inline RangeGenerator {T<:Union(Int8,UInt8,Int16,UInt16)} (m:: T ) = RangeGenerator (T, m % UInt32)
417
+
418
+ # rand on RangeGenerator
443
419
444
- function rand {T<:Integer, U<:Unsigned} (rng:: AbstractRNG , g:: RangeGeneratorInt{T,U} )
445
- x = rand (rng, U)
446
- while x > g. u
420
+ @inline rand {T} (rng:: AbstractRNG , g:: RangeGenerator{T} ) = rand (rng, g, one (T))
421
+
422
+ @inline function rand_lessthan {U} (rng:: AbstractRNG , u:: U )
423
+ while true
447
424
x = rand (rng, U)
425
+ x <= u && return x
448
426
end
449
- (unsigned (g. a) + rem_knuth (x, g. k)) % T
450
427
end
451
428
429
+ # this function uses 32 bit entropy for small ranges of length <= typemax(UInt32) + 1
430
+ # RangeGeneratorInt is responsible for providing the right value of k
431
+ @inline rand {T} (rng:: AbstractRNG , g:: RangeGeneratorInt{T,UInt64} , start:: T ) =
432
+ (g. k - 1 ) >> 32 == 0 ?
433
+ start + rand_lessthan (rng, g. u % UInt32) % UInt64 % g. k % T :
434
+ rand (rng, g, start, true )
435
+
436
+ @inline rand {T} (rng:: AbstractRNG , g:: RangeGeneratorInt{T} , start:: T , dummy= true ) =
437
+ start + rem_knuth (rand_lessthan (rng, g. u), g. k) % T
438
+
439
+
452
440
if GMP_VERSION. major >= 6
453
441
# mpz_limbs_write and mpz_limbs_finish are available only in GMP version 6
454
- function rand (rng:: AbstractRNG , g:: RangeGeneratorBigInt )
442
+ function rand (rng:: AbstractRNG , g:: RangeGeneratorBigInt , start :: BigInt )
455
443
x = BigInt ()
456
444
while true
457
445
# note: on CRAY computers, the second argument may be of type Cint (48 bits) and not Clong
@@ -462,11 +450,11 @@ if GMP_VERSION.major >= 6
462
450
ccall ((:__gmpz_limbs_finish , :libgmp ), Void, (Ptr{BigInt}, Clong), & x, g. nlimbs)
463
451
x <= g. m && break
464
452
end
465
- ccall ((:__gmpz_add , :libgmp ), Void, (Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}), & x, & x, & g . a )
453
+ ccall ((:__gmpz_add , :libgmp ), Void, (Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}), & x, & x, & start )
466
454
return x
467
455
end
468
456
else
469
- function rand (rng:: AbstractRNG , g:: RangeGeneratorBigInt )
457
+ function rand (rng:: AbstractRNG , g:: RangeGeneratorBigInt , start :: BigInt )
470
458
x = BigInt ()
471
459
while true
472
460
rand! (rng, g. limbs)
@@ -476,31 +464,21 @@ else
476
464
& x, length (g. limbs), - 1 , sizeof (Limb), 0 , 0 , & g. limbs)
477
465
x <= g. m && break
478
466
end
479
- ccall ((:__gmpz_add , :libgmp ), Void, (Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}), & x, & x, & g . a )
467
+ ccall ((:__gmpz_add , :libgmp ), Void, (Ptr{BigInt}, Ptr{BigInt}, Ptr{BigInt}), & x, & x, & start )
480
468
return x
481
469
end
482
470
end
483
471
484
- rand {T<:Union(Signed,Unsigned,BigInt,Bool,Char)} (rng:: AbstractRNG , r:: UnitRange{T} ) = rand (rng, RangeGenerator (r))
485
-
486
-
487
472
# Randomly draw a sample from an AbstractArray r
488
473
# (e.g. r is a range 0:2:8 or a vector [2, 3, 5, 7])
489
- rand (rng:: AbstractRNG , r:: AbstractArray ) = @inbounds return r[rand (rng, 1 : length (r))]
490
-
491
- function rand! (rng:: AbstractRNG , A:: AbstractArray , g:: RangeGenerator )
492
- for i = 1 : length (A)
493
- @inbounds A[i] = rand (rng, g)
494
- end
495
- return A
496
- end
474
+ @inline rand (rng:: AbstractRNG , r:: AbstractArray ) = rand (rng, r, RangeGenerator (r))
497
475
498
- rand! {T<:Union(Signed,Unsigned,BigInt,Bool,Char)} (rng:: AbstractRNG , A:: AbstractArray , r:: UnitRange{T} ) = rand! (rng, A, RangeGenerator (r))
476
+ @inline rand (rng:: AbstractRNG , r:: AbstractArray , g:: RangeGenerator ) = @inbounds return r[rand (rng, g)]
477
+ @inline rand {T<:Union(IntTypes...,BigInt)} (rng:: AbstractRNG , r:: UnitRange{T} , g:: RangeGenerator ) = rand (rng, g, first (r))
499
478
500
- function rand! (rng:: AbstractRNG , A:: AbstractArray , r:: AbstractArray )
501
- g = RangeGenerator (1 : (length (r)))
479
+ function rand! (rng:: AbstractRNG , A:: AbstractArray , r:: AbstractArray , g:: RangeGenerator = RangeGenerator (r))
502
480
for i = 1 : length (A)
503
- @inbounds A[i] = r[ rand (rng, g)]
481
+ @inbounds A[i] = rand (rng, r, g)
504
482
end
505
483
return A
506
484
end
0 commit comments