Skip to content

Commit 063e8f1

Browse files
authored
Merge pull request #13815 from rfourquet/rand-bigrange-mergeversions
merge 2 versions (for GMP 5 & 6) of rand(::UnitRange{BigInt})
2 parents 9a22471 + 141a8f4 commit 063e8f1

File tree

2 files changed

+33
-44
lines changed

2 files changed

+33
-44
lines changed

base/gmp.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ mutable struct BigInt <: Integer
4646
alloc::Cint
4747
size::Cint
4848
d::Ptr{Limb}
49+
4950
function BigInt()
5051
b = new(zero(Cint), zero(Cint), C_NULL)
5152
MPZ.init!(b)
@@ -77,9 +78,10 @@ BigInt(x)
7778
function __init__()
7879
try
7980
if gmp_version().major != GMP_VERSION.major || gmp_bits_per_limb() != GMP_BITS_PER_LIMB
80-
error(string("The dynamically loaded GMP library (version $(gmp_version()) with __gmp_bits_per_limb == $(gmp_bits_per_limb()))\n",
81-
"does not correspond to the compile time version (version $GMP_VERSION with __gmp_bits_per_limb == $GMP_BITS_PER_LIMB).\n",
82-
"Please rebuild Julia."))
81+
msg = gmp_bits_per_limb() != GMP_BITS_PER_LIMB ? error : warn
82+
msg(string("The dynamically loaded GMP library (version $(gmp_version()) with __gmp_bits_per_limb == $(gmp_bits_per_limb()))\n",
83+
"does not correspond to the compile time version (version $GMP_VERSION with __gmp_bits_per_limb == $GMP_BITS_PER_LIMB).\n",
84+
"Please rebuild Julia."))
8385
end
8486

8587
ccall((:__gmp_set_memory_functions, :libgmp), Void,
@@ -114,6 +116,9 @@ gmpz(op::Symbol) = (Symbol(:__gmpz_, op), :libgmp)
114116
init!(x::BigInt) = (ccall((:__gmpz_init, :libgmp), Void, (mpz_t,), &x); x)
115117
init2!(x::BigInt, a) = (ccall((:__gmpz_init2, :libgmp), Void, (mpz_t, bitcnt_t), &x, a); x)
116118

119+
realloc2!(x, a) = (ccall((:__gmpz_realloc2, :libgmp), Void, (mpz_t, bitcnt_t), &x, a); x)
120+
realloc2(a) = realloc2!(BigInt(), a)
121+
117122
sizeinbase(a::BigInt, b) = Int(ccall((:__gmpz_sizeinbase, :libgmp), Csize_t, (mpz_t, Cint), &a, b))
118123

119124
for op in (:add, :sub, :mul, :fdiv_q, :tdiv_q, :fdiv_r, :tdiv_r, :gcd, :lcm, :and, :ior, :xor)
@@ -196,6 +201,9 @@ cmp_si(a::BigInt, b) = ccall((:__gmpz_cmp_si, :libgmp), Cint, (mpz_t, Clong), &a
196201
cmp_ui(a::BigInt, b) = ccall((:__gmpz_cmp_ui, :libgmp), Cint, (mpz_t, Culong), &a, b) % Int
197202
cmp_d(a::BigInt, b) = ccall((:__gmpz_cmp_d, :libgmp), Cint, (mpz_t, Cdouble), &a, b) % Int
198203

204+
mpn_cmp(a::Ptr{Limb}, b::Ptr{Limb}, c) = ccall((:__gmpn_cmp, :libgmp), Cint, (Ptr{Limb}, Ptr{Limb}, Clong), a, b, c)
205+
mpn_cmp(a::BigInt, b::BigInt, c) = mpn_cmp(a.d, b.d, c)
206+
199207
get_str!(x, a, b::BigInt) = (ccall((:__gmpz_get_str,:libgmp), Ptr{Cchar}, (Ptr{Cchar}, Cint, mpz_t), x, a, &b); x)
200208
set_str!(x::BigInt, a, b) = ccall((:__gmpz_set_str, :libgmp), Cint, (mpz_t, Ptr{UInt8}, Cint), &x, a, b) % Int
201209
get_d(a::BigInt) = ccall((:__gmpz_get_d, :libgmp), Cdouble, (mpz_t,), &a)

base/random.jl

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module Random
44

55
using Base.dSFMT
6-
using Base.GMP: GMP_VERSION, Limb, MPZ
6+
using Base.GMP: Limb, MPZ
77
import Base: copymutable, copy, copy!, ==
88

99
export srand,
@@ -592,23 +592,12 @@ for (T, U) in [(UInt8, UInt32), (UInt16, UInt32),
592592
end
593593
end
594594

595-
if GMP_VERSION.major >= 6
596-
struct RangeGeneratorBigInt <: RangeGenerator
597-
a::BigInt # first
598-
m::BigInt # range length - 1
599-
nlimbs::Int # number of limbs in generated BigInt's
600-
mask::Limb # applied to the highest limb
601-
end
602-
603-
else
604-
struct RangeGeneratorBigInt <: RangeGenerator
605-
a::BigInt # first
606-
m::BigInt # range length - 1
607-
limbs::Vector{Limb} # buffer to be copied into generated BigInt's
608-
mask::Limb # applied to the highest limb
609-
610-
RangeGeneratorBigInt(a, m, nlimbs, mask) = new(a, m, Vector{Limb}(nlimbs), mask)
611-
end
595+
struct RangeGeneratorBigInt <: RangeGenerator
596+
a::BigInt # first
597+
m::BigInt # range length - 1
598+
nlimbs::Int # number of limbs in generated BigInt's (z ∈ [0, m])
599+
nlimbsmax::Int # max number of limbs for z+a
600+
mask::Limb # applied to the highest limb
612601
end
613602

614603

@@ -619,7 +608,8 @@ function RangeGenerator(r::UnitRange{BigInt})
619608
nlimbs, highbits = divrem(nd, 8*sizeof(Limb))
620609
highbits > 0 && (nlimbs += 1)
621610
mask = highbits == 0 ? ~zero(Limb) : one(Limb)<<highbits - one(Limb)
622-
return RangeGeneratorBigInt(first(r), m, nlimbs, mask)
611+
nlimbsmax = max(nlimbs, abs(last(r).size), abs(first(r).size))
612+
return RangeGeneratorBigInt(first(r), m, nlimbs, nlimbsmax, mask)
623613
end
624614

625615

@@ -649,30 +639,21 @@ function rand{T<:Integer, U<:Unsigned}(rng::AbstractRNG, g::RangeGeneratorInt{T,
649639
(unsigned(g.a) + rem_knuth(x, g.k)) % T
650640
end
651641

652-
if GMP_VERSION.major >= 6
653-
# mpz_limbs_write and mpz_limbs_finish are available only in GMP version 6
654-
function rand(rng::AbstractRNG, g::RangeGeneratorBigInt)
655-
x = BigInt()
656-
while true
657-
# note: on CRAY computers, the second argument may be of type Cint (48 bits) and not Clong
658-
xd = MPZ.limbs_write!(x, g.nlimbs)
659-
limbs = unsafe_wrap(Array, xd, g.nlimbs)
660-
rand!(rng, limbs)
661-
limbs[end] &= g.mask
662-
MPZ.limbs_finish!(x, g.nlimbs)
663-
x <= g.m && return MPZ.add!(x, g.a)
664-
end
642+
function rand(rng::AbstractRNG, g::RangeGeneratorBigInt)
643+
x = MPZ.realloc2(g.nlimbsmax*8*sizeof(Limb))
644+
limbs = unsafe_wrap(Array, x.d, g.nlimbs)
645+
while true
646+
rand!(rng, limbs)
647+
@inbounds limbs[end] &= g.mask
648+
MPZ.mpn_cmp(x, g.m, g.nlimbs) <= 0 && break
665649
end
666-
else
667-
function rand(rng::AbstractRNG, g::RangeGeneratorBigInt)
668-
x = BigInt()
669-
while true
670-
rand!(rng, g.limbs)
671-
g.limbs[end] &= g.mask
672-
MPZ.import!(x, length(g.limbs), -1, sizeof(Limb), 0, 0, g.limbs)
673-
x <= g.m && return MPZ.add!(x, g.a)
674-
end
650+
# adjust x.size (normally done by mpz_limbs_finish, in GMP version >= 6)
651+
x.size = g.nlimbs
652+
while x.size > 0
653+
@inbounds limbs[x.size] != 0 && break
654+
x.size -= 1
675655
end
656+
MPZ.add!(x, g.a)
676657
end
677658

678659
rand(rng::AbstractRNG, r::UnitRange{<:Union{Signed,Unsigned,BigInt,Bool}}) = rand(rng, RangeGenerator(r))

0 commit comments

Comments
 (0)