Skip to content

Commit 981e454

Browse files
authored
Fix checked_pow() perf: BigInts can never overflow, so don't need checked math. (#54484)
This commit makes `checked_pow(x::BigInt, y::Integer)` skip directly to `^(x,y)`. Same for (Integer, BigInt). This means we're again using the native C implementation for power, instead of interpreting it in julia via repeated multiplications. Thanks to @mcmcgrath13 for discovering the issue. Before: ```julia julia> @Btime ^($(BigInt(2)), 100) 56.134 ns (3 allocations: 80 bytes) 1267650600228229401496703205376 julia> @Btime Base.Checked.checked_pow($(BigInt(2)), 100) 326.895 ns (24 allocations: 392 bytes) 1267650600228229401496703205376 ``` After: ```julia julia> @Btime ^($(BigInt(2)), 100) 56.430 ns (3 allocations: 80 bytes) 1267650600228229401496703205376 julia> @Btime Base.Checked.checked_pow($(BigInt(2)), 100) 56.557 ns (3 allocations: 80 bytes) 1267650600228229401496703205376 ``` Co-authored-by: @mcmcgrath13
1 parent 018770d commit 981e454

File tree

2 files changed

+8
-0
lines changed

2 files changed

+8
-0
lines changed

base/gmp.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,11 @@ Base.add_with_overflow(a::BigInt, b::BigInt) = a + b, false
832832
Base.sub_with_overflow(a::BigInt, b::BigInt) = a - b, false
833833
Base.mul_with_overflow(a::BigInt, b::BigInt) = a * b, false
834834

835+
# checked_pow doesn't follow the same promotion rules as the others, above.
836+
Base.checked_pow(x::BigInt, p::Integer) = x^p
837+
Base.checked_pow(x::Integer, p::BigInt) = x^p
838+
Base.checked_pow(x::BigInt, p::BigInt) = x^p
839+
835840
Base.deepcopy_internal(x::BigInt, stackdict::IdDict) = get!(() -> MPZ.set(x), stackdict, x)::BigInt
836841

837842
## streamlined hashing for BigInt, by avoiding allocation from shifts ##

test/checked.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,9 @@ end
330330

331331
@test checked_pow(BigInt(2), 2) == BigInt(4)
332332
@test checked_pow(BigInt(2), 100) == BigInt(1267650600228229401496703205376)
333+
334+
# Perf test: Make sure BigInts allocs don't scale with the power:
335+
@test @allocations(checked_pow(BigInt(2), 2)) @allocations(checked_pow(BigInt(2), 10000)) rtol=0.9
333336
end
334337

335338
@testset "Additional tests" begin

0 commit comments

Comments
 (0)