|
1 | 1 | module IntegerMathUtils |
2 | 2 | export iroot, ispower, rootrem, find_exponent, is_probably_prime, kronecker |
3 | 3 |
|
4 | | -iroot(x::Integer, n::Integer) = iroot(x, Cint(n)) |
| 4 | +using Base: uabs, BitUnsigned64 |
5 | 5 |
|
6 | | -# TODO: Add more efficient implimentation |
7 | | -iroot(x::T, n::Cint) where {T<:Integer} = T(iroot(big(x), Cint(n))) |
| 6 | +@static if isdefined(Base, :top_set_bit) |
| 7 | + using Base: top_set_bit |
| 8 | +else |
| 9 | + top_set_bit(x::Base.BitInteger) = 8sizeof(x) - leading_zeros(x) |
| 10 | + top_set_bit(x::Integer) = ndigits(x, base=2) |
| 11 | +end |
8 | 12 |
|
9 | | -function iroot(x::BigInt, n::Cint) |
| 13 | +function iroot(x::BigInt, n::Integer) |
10 | 14 | n <= 0 && throw(DomainError(n, "Exponent must be > 0")) |
11 | | - x <= 0 && iseven(n) && throw(DomainError(n, "This is a math no-no")) |
| 15 | + x < 0 && iseven(n) && throw(DomainError(x, "Even roots require x >= 0")) |
12 | 16 | ans = BigInt() |
13 | | - @ccall :libgmp.__gmpz_root(ans::Ref{BigInt}, x::Ref{BigInt}, n::Cint)::Cint |
| 17 | + @ccall :libgmp.__gmpz_root(ans::Ref{BigInt}, x::Ref{BigInt}, n::Culong)::Cint |
14 | 18 | ans |
15 | 19 | end |
16 | 20 |
|
17 | | -# TODO: Add more efficient implimentation for smaller types |
18 | | -function rootrem(x::T, n::Integer) where {T<:Integer} |
19 | | - x = big(x) |
20 | | - n = Cint(n) |
| 21 | +function rootrem(x::BigInt, n::Integer) |
21 | 22 | n <= 0 && throw(DomainError(n, "Exponent must be > 0")) |
22 | | - x <= 0 && iseven(x) && throw(DomainError(n, "This is a math no-no")) |
| 23 | + x < 0 && iseven(n) && throw(DomainError(x, "Even roots require x >= 0")) |
23 | 24 | root = BigInt() |
24 | 25 | rem = BigInt() |
25 | | - @ccall :libgmp.__gmpz_rootrem(root::Ref{BigInt}, rem::Ref{BigInt}, x::Ref{BigInt}, n::Int)::Nothing |
26 | | - return (root, T(rem)) |
| 26 | + @ccall :libgmp.__gmpz_rootrem(root::Ref{BigInt}, rem::Ref{BigInt}, x::Ref{BigInt}, n::Culong)::Cvoid |
| 27 | + return (root, rem) |
27 | 28 | end |
28 | 29 |
|
29 | | -# TODO: Add more efficient implimentation for smaller types |
30 | | -ispower(x::Integer) = ispower(big(x)) |
31 | | - |
32 | 30 | function ispower(x::BigInt) |
33 | 31 | return 0 != @ccall :libgmp.__gmpz_perfect_power_p(x::Ref{BigInt})::Cint |
34 | 32 | end |
35 | 33 |
|
36 | | -# TODO: Add more efficient implimentation for smaller types |
| 34 | +# a^n in T via power-by-squaring, detecting overflow. Returns (value, overflowed) |
| 35 | +function pow_with_overflow(a::T, n::Integer) where T<:Base.BitInteger |
| 36 | + p = one(T) |
| 37 | + while n > 0 |
| 38 | + if isodd(n) |
| 39 | + p, o = Base.Checked.mul_with_overflow(p, a) |
| 40 | + o && return (p, true) |
| 41 | + end |
| 42 | + n >>= 1 |
| 43 | + n > 0 || break |
| 44 | + a, o = Base.Checked.mul_with_overflow(a, a) |
| 45 | + o && return (p, true) |
| 46 | + end |
| 47 | + return (p, false) |
| 48 | +end |
| 49 | +function _pow_leq(a::T, n::Integer, x::T) where T<:Base.BitInteger |
| 50 | + p, o = pow_with_overflow(a, n) |
| 51 | + return !o && p <= x |
| 52 | +end |
| 53 | +_pow_leq(a::T, n::Integer, x::T) where T<:Integer = a^n <= x |
| 54 | + |
| 55 | +# Float64-accurate estimate of x^(1/n) for x <= typemax(UInt128). |
| 56 | +# Because the root must be small, this is within +-1 of the true root when n>2. |
| 57 | +function _iroot_approx(x::T, n::Integer) where T<:Base.BitInteger |
| 58 | + trunc(T, exp(log(Float64(x)) / n)) |
| 59 | +end |
| 60 | + |
| 61 | +# A Float64-accurate estimate of x^(1/n) for x > typemax(UInt128) |
| 62 | +# Split x = hi*2^sh with hi its top 53 bits, estimate log2(root) = (log2(hi)+sh)/n |
| 63 | +# and place a 53-bit mantissa at the right exponent. |
| 64 | +function _iroot_float(x::T, n::Integer) where T<:Integer |
| 65 | + b = top_set_bit(x) |
| 66 | + sh = b - 53 |
| 67 | + L = (log2(Float64(x >> sh)) + sh) / n |
| 68 | + e = floor(Int, L) |
| 69 | + m53 = trunc(T, exp2(L - e) * exp2(53)) |
| 70 | + return e >= 53 ? (m53 << (e - 53)) : (m53 >> (53 - e)) |
| 71 | +end |
| 72 | + |
| 73 | +# One integer Newton step |
| 74 | +@inline function _iroot_newton(x::T, n::Integer, a::T) where T<:Integer |
| 75 | + return ((n - 1) * a + x ÷ a^(n - 1)) ÷ n |
| 76 | +end |
| 77 | + |
| 78 | +function _iroot_approx(x::T, n::Integer) where T<:Integer |
| 79 | + x <= typemax(UInt128) && return T(_iroot_approx(UInt128(x), n)) |
| 80 | + # one unconditional step lifts any seed to >= floor(root)-1 (by weighted AM-GM) |
| 81 | + a = _iroot_newton(x, n, _iroot_float(x, n)) |
| 82 | + while true # after which the iteration descends until return |
| 83 | + b = _iroot_newton(x, n, a) |
| 84 | + b >= a && return a |
| 85 | + a = b |
| 86 | + end |
| 87 | +end |
| 88 | + |
| 89 | +# floor(x^(1/n)) for x >= 0; n >= 2 (n == 2 only for non-bit Integer types, |
| 90 | +# machine ints take the Base.isqrt path in iroot) |
| 91 | +function _iroot_nonneg(x::T, n::Integer) where T<:Integer |
| 92 | + x <= one(T) && return x |
| 93 | + n >= top_set_bit(x) && return one(T) # 2^n > x |
| 94 | + a = _iroot_approx(x, n) |
| 95 | + if _pow_leq(a, n, x) |
| 96 | + while _pow_leq(a + one(T), n, x) |
| 97 | + a += one(T) |
| 98 | + end |
| 99 | + else |
| 100 | + a -= one(T) |
| 101 | + while !_pow_leq(a, n, x) |
| 102 | + a -= one(T) |
| 103 | + end |
| 104 | + end |
| 105 | + return a |
| 106 | +end |
| 107 | + |
| 108 | +# Base.isqrt is already optimal for machine ints; its generic Integer |
| 109 | +# fallback is Float64-based though, which is wrong for wide values. |
| 110 | +_isqrt(x::Base.BitInteger) = Base.isqrt(x) |
| 111 | +_isqrt(x::Integer) = _iroot_nonneg(x, 2) |
| 112 | + |
| 113 | +function iroot(x::T, n::Integer) where T<:Integer |
| 114 | + n <= 0 && throw(DomainError(n, "Exponent must be > 0")) |
| 115 | + x < 0 && iseven(n) && throw(DomainError(x, "Even roots require x >= 0")) |
| 116 | + n == 1 && return x |
| 117 | + n == 2 && return T(_isqrt(uabs(x))) # x >= 0 here |
| 118 | + r = T(_iroot_nonneg(uabs(x), n)) |
| 119 | + return x < 0 ? -r : r |
| 120 | +end |
| 121 | + |
| 122 | +function rootrem(x::Integer, n::Integer) |
| 123 | + a = iroot(x, n) |
| 124 | + return (a, x - a^n) |
| 125 | +end |
| 126 | + |
| 127 | +# Is m (>= 2) an exact k-th power (k odd, >= 3)? |
| 128 | +# Callers handle k == 2 via _isqrt directly |
| 129 | +# (its root can be large enough that the float error below exceeds 0.5). |
| 130 | +# The float root r = exp(lm/k) has provable worst-case error |
| 131 | +# E <= 1.5*r*(|ln r|+1)*2^-52; for k >= 3 and m < 2^128 this is << 0.5 |
| 132 | +# so round(r) is the only integer candidate |
| 133 | +function _kth_root_exact(m::T, k::Integer, logm::Float64) where T<:Base.BitInteger |
| 134 | + lr = logm / k |
| 135 | + r = exp(lr) |
| 136 | + tol = 2 * r * (abs(lr) + 1) * exp2(-52) |
| 137 | + b = round(r) |
| 138 | + abs(r - b) > tol && return false |
| 139 | + c = unsafe_trunc(T, b) |
| 140 | + p, o = pow_with_overflow(c, k) |
| 141 | + return !o && p == m |
| 142 | +end |
| 143 | +# Arbitrary-precision types: no reliable Float64, so verify via the native root. |
| 144 | +function _kth_root_exact(m::T, k::Integer, logm::Float64) where T<:Integer |
| 145 | + a = iroot(m, k) |
| 146 | + return a^k == m # a^k <= m, so no overflow |
| 147 | +end |
| 148 | + |
| 149 | +function ispower(x::Integer) |
| 150 | + ux = uabs(x) |
| 151 | + ux <= one(ux) && return true |
| 152 | + neg = x < 0 |
| 153 | + trailing_zeros(ux) == 1 && return false # 2 | x exactly once: not a power |
| 154 | + if !neg |
| 155 | + a = _isqrt(ux) |
| 156 | + a * a == ux && return true |
| 157 | + end |
| 158 | + lx = log(Float64(ux)) |
| 159 | + for k in 3:2:top_set_bit(ux) |
| 160 | + _kth_root_exact(ux, k, lx)[1] && return true |
| 161 | + end |
| 162 | + return false |
| 163 | +end |
| 164 | + |
37 | 165 | function find_exponent(x::Integer) |
38 | | - x <= 1 && return 1 |
39 | | - for exponent in ndigits(x, base=2):-1:2 |
40 | | - rootrem(x, exponent)[2] == 0 && return exponent |
| 166 | + ux = uabs(x) |
| 167 | + ux <= one(ux) && return 1 |
| 168 | + neg = x < 0 |
| 169 | + lx = log(Float64(ux)) |
| 170 | + for e in top_set_bit(ux):-1:3 |
| 171 | + neg && iseven(e) && continue |
| 172 | + _kth_root_exact(ux, e, lx)[1] && return e |
| 173 | + end |
| 174 | + if !neg |
| 175 | + a = _isqrt(ux) |
| 176 | + a * a == ux && return 2 |
41 | 177 | end |
42 | | - 1 |
| 178 | + return 1 |
43 | 179 | end |
44 | 180 |
|
45 | 181 | function is_probably_prime(x::Integer; reps=25) |
|
0 commit comments