Skip to content

Commit 3627a85

Browse files
authored
fix nextpow, prevpow for types without typemax (JuliaLang#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 JuliaLang#57906
1 parent a3c48d7 commit 3627a85

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
@@ -570,7 +570,8 @@ function nextpow(a::Real, x::Real)
570570
n = ceil(Integer,log(a, x))
571571
# round-off error of log can go either direction, so need some checks
572572
p = a^(n-1)
573-
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
573+
hastypemax(typeof(p)) && x > typemax(p) &&
574+
throw(DomainError(x,"argument is beyond the range of type of the base"))
574575
p >= x && return p
575576
wp = a^n
576577
wp > p || throw(OverflowError("result is beyond the range of type of the base"))
@@ -611,9 +612,10 @@ function prevpow(a::T, x::Real) where T <: Real
611612
n = floor(Integer,log(a, x))
612613
# round-off error of log can go either direction, so need some checks
613614
p = a^n
614-
x > typemax(p) && throw(DomainError(x,"argument is beyond the range of type of the base"))
615+
hastypemax(typeof(p)) && x > typemax(p) &&
616+
throw(DomainError(x,"argument is beyond the range of type of the base"))
615617
if a isa Integer
616-
wp, overflow = mul_with_overflow(a, p)
618+
wp, overflow = mul_with_overflow(promote(a, p)...)
617619
wp <= x && !overflow && return wp
618620
else
619621
wp = a^(n+1)

test/intfuncs.jl

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,14 @@ end
326326
end
327327

328328
@testset "nextpow/prevpow" begin
329+
fs = (prevpow, nextpow)
330+
types = (Int8, BigInt, BigFloat)
331+
for f fs, P types, R types, p 1:20, r 2:5
332+
q = P(p)
333+
n = R(r)
334+
@test f(r, p) == f(n, q)
335+
end
336+
329337
@test nextpow(2, 3) == 4
330338
@test nextpow(2, 4) == 4
331339
@test nextpow(2, 7) == 8
@@ -339,7 +347,14 @@ end
339347
@test prevpow(10, 101.0) === 100
340348
@test prevpow(10.0, 101) === 100.0
341349
@test_throws DomainError prevpow(0, 3)
342-
@test_throws DomainError prevpow(0, 3)
350+
@test_throws DomainError prevpow(3, 0)
351+
352+
# "argument is beyond the range of type of the base"
353+
@test_throws DomainError prevpow(Int8(3), 243)
354+
@test_throws DomainError nextpow(Int8(3), 243)
355+
356+
# "result is beyond the range of type of the base"
357+
@test_throws OverflowError nextpow(Int8(3), 82)
343358
end
344359

345360
@testset "ndigits/ndigits0z" begin

0 commit comments

Comments
 (0)