Skip to content

Commit 21e7f7a

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 d4d0876 commit 21e7f7a

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
@@ -526,7 +526,8 @@ function nextpow(a::Real, x::Real)
526526
n = ceil(Integer,log(a, x))
527527
# round-off error of log can go either direction, so need some checks
528528
p = a^(n-1)
529-
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
529+
hastypemax(typeof(p)) && x > typemax(p) &&
530+
throw(DomainError(x,"argument is beyond the range of type of the base"))
530531
p >= x && return p
531532
wp = a^n
532533
wp > p || throw(OverflowError("result is beyond the range of type of the base"))
@@ -567,9 +568,10 @@ function prevpow(a::T, x::Real) where T <: Real
567568
n = floor(Integer,log(a, x))
568569
# round-off error of log can go either direction, so need some checks
569570
p = a^n
570-
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
571+
hastypemax(typeof(p)) && x > typemax(p) &&
572+
throw(DomainError(x,"argument is beyond the range of type of the base"))
571573
if a isa Integer
572-
wp, overflow = mul_with_overflow(a, p)
574+
wp, overflow = mul_with_overflow(promote(a, p)...)
573575
wp <= x && !overflow && return wp
574576
else
575577
wp = a^(n+1)

test/intfuncs.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,14 @@ end
309309
end
310310

311311
@testset "nextpow/prevpow" begin
312+
fs = (prevpow, nextpow)
313+
types = (Int8, BigInt, BigFloat)
314+
for f fs, P types, R types, p 1:20, r 2:5
315+
q = P(p)
316+
n = R(r)
317+
@test f(r, p) == f(n, q)
318+
end
319+
312320
@test nextpow(2, 3) == 4
313321
@test nextpow(2, 4) == 4
314322
@test nextpow(2, 7) == 8
@@ -322,7 +330,14 @@ end
322330
@test prevpow(10, 101.0) === 100
323331
@test prevpow(10.0, 101) === 100.0
324332
@test_throws DomainError prevpow(0, 3)
325-
@test_throws DomainError prevpow(0, 3)
333+
@test_throws DomainError prevpow(3, 0)
334+
335+
# "argument is beyond the range of type of the base"
336+
@test_throws DomainError prevpow(Int8(3), 243)
337+
@test_throws DomainError nextpow(Int8(3), 243)
338+
339+
# "result is beyond the range of type of the base"
340+
@test_throws OverflowError nextpow(Int8(3), 82)
326341
end
327342

328343
@testset "ndigits/ndigits0z" begin

0 commit comments

Comments
 (0)