Skip to content

Commit d959e0f

Browse files
nsajkoKristofferC
authored andcommitted
fix nextpow, prevpow for types without typemax (#49669)
Without this change `prevpow` and `nextpow` fail for, e.g., `BigInt`; incorrectly throwing a `MethodError`. For example, calls like `prevpow(3, big"10")` or `nextpow(3, big"10")` fail. The issue is that the code incorrectly assumes the existence of a `typemax` method. Another issue was a missing promote for the arguments of a `mul_with_overflow` call. Fixes #57906 (cherry picked from commit 3627a85)
1 parent 387d2d4 commit d959e0f

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

base/intfuncs.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,8 @@ function nextpow(a::Real, x::Real)
488488
n = ceil(Integer,log(a, x))
489489
# round-off error of log can go either direction, so need some checks
490490
p = a^(n-1)
491-
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
491+
hastypemax(typeof(p)) && x > typemax(p) &&
492+
throw(DomainError(x,"argument is beyond the range of type of the base"))
492493
p >= x && return p
493494
wp = a^n
494495
wp > p || throw(OverflowError("result is beyond the range of type of the base"))
@@ -529,9 +530,10 @@ function prevpow(a::T, x::Real) where T <: Real
529530
n = floor(Integer,log(a, x))
530531
# round-off error of log can go either direction, so need some checks
531532
p = a^n
532-
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
533+
hastypemax(typeof(p)) && x > typemax(p) &&
534+
throw(DomainError(x,"argument is beyond the range of type of the base"))
533535
if a isa Integer
534-
wp, overflow = mul_with_overflow(a, p)
536+
wp, overflow = mul_with_overflow(promote(a, p)...)
535537
wp <= x && !overflow && return wp
536538
else
537539
wp = a^(n+1)

test/intfuncs.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ end
278278
end
279279

280280
@testset "nextpow/prevpow" begin
281+
fs = (prevpow, nextpow)
282+
types = (Int8, BigInt, BigFloat)
283+
for f fs, P types, R types, p 1:20, r 2:5
284+
q = P(p)
285+
n = R(r)
286+
@test f(r, p) == f(n, q)
287+
end
288+
281289
@test nextpow(2, 3) == 4
282290
@test nextpow(2, 4) == 4
283291
@test nextpow(2, 7) == 8
@@ -291,7 +299,14 @@ end
291299
@test prevpow(10, 101.0) === 100
292300
@test prevpow(10.0, 101) === 100.0
293301
@test_throws DomainError prevpow(0, 3)
294-
@test_throws DomainError prevpow(0, 3)
302+
@test_throws DomainError prevpow(3, 0)
303+
304+
# "argument is beyond the range of type of the base"
305+
@test_throws DomainError prevpow(Int8(3), 243)
306+
@test_throws DomainError nextpow(Int8(3), 243)
307+
308+
# "result is beyond the range of type of the base"
309+
@test_throws OverflowError nextpow(Int8(3), 82)
295310
end
296311

297312
@testset "ndigits/ndigits0z" begin

0 commit comments

Comments
 (0)