From 22dfa30dd5ed39f40fd9abc9fef1e532978e48c6 Mon Sep 17 00:00:00 2001 From: Andy Dienes Date: Sun, 28 Sep 2025 14:39:22 -0400 Subject: [PATCH] fix powermod on unsigned power of half typemax --- base/intfuncs.jl | 22 ++++++++++++---------- test/intfuncs.jl | 3 +++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 667891ebb3c15..c8c221b997488 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -489,18 +489,20 @@ julia> powermod(5, 3, 19) function powermod(x::Integer, p::Integer, m::T) where T<:Integer p == 0 && return mod(one(m),m) # When the concrete type of p is signed and has the lowest value, - # `p != 0 && p == -p` is equivalent to `p == typemin(typeof(p))` for 2's complement representation. + # `p < 0 && p == -p` is equivalent to `p == typemin(typeof(p))` for 2's complement representation. # but will work for integer types like `BigInt` that don't have `typemin` defined # It needs special handling otherwise will cause overflow problem. - if p == -p - imod = invmod(x, m) - rhalf = powermod(imod, -(p÷2), m) - r::T = mod(widemul(rhalf, rhalf), m) - isodd(p) && (r = mod(widemul(r, imod), m)) - #else odd - return r - elseif p < 0 - return powermod(invmod(x, m), -p, m) + if p < 0 + if p == -p + imod = invmod(x, m) + rhalf = powermod(imod, -(p÷2), m) + r::T = mod(widemul(rhalf, rhalf), m) + isodd(p) && (r = mod(widemul(r, imod), m)) + #else odd + return r + else + return powermod(invmod(x, m), -p, m) + end end (m == 1 || m == -1) && return zero(m) b = oftype(m,mod(x,m)) # this also checks for divide by zero diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 6a6fee9c96208..c40c01ca3b6e8 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -359,6 +359,9 @@ end @test powermod(2, big(3), -5) == -2 @inferred powermod(2, -2, -5) @inferred powermod(big(2), -2, UInt(5)) + + @test powermod(-3, 0x80, 7) === 2 + @test powermod(0x03, 0x80, 0x07) === 0x02 end @testset "nextpow/prevpow" begin