From 81a0813a73eb803be1fd688802059b286263019a Mon Sep 17 00:00:00 2001 From: KlausC Date: Fri, 5 Apr 2024 18:59:52 +0200 Subject: [PATCH 01/14] power uses Float64 exponents for integers --- base/math.jl | 44 +++++++++++++++++++++++++++++++++++--------- test/math.jl | 14 ++++++++++++++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/base/math.jl b/base/math.jl index c3c15505c5f8f..ade93501dcbd3 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1255,6 +1255,10 @@ function modf(x::T) where T<:IEEEFloat return (rx, ix) end +@inline function use_power_by_squaring(n::Integer) + -2^13 <= n < 2^13 +end + # @constprop aggressive to help the compiler see the switch between the integer and float # variants for callers with constant `y` @constprop :aggressive function ^(x::Float64, y::Float64) @@ -1267,19 +1271,25 @@ end y = sign(y)*0x1.8p62 end yint = unsafe_trunc(Int64, y) # This is actually safe since julia freezes the result - y == yint && return @noinline x^yint - 2*xu==0 && return abs(y)*Inf*(!(y>0)) # if x==0 - x<0 && throw_exp_domainerror(x) # |y| is small enough that y isn't an integer - !isfinite(x) && return x*(y>0 || isnan(x)) # x is inf or NaN + yisint = y == yint + yisint && use_power_by_squaring(yint) && return @noinline x^yint + 2*xu==0 && return abs(y)*Inf*(!(y>0)) # if x === +0.0 or -0.0 (Inf * false === 0.0) + s = 1 + if x < 0 + !yisint && throw_exp_domainerror(x) # y isn't an integer + s = ifelse(isodd(yint), -1, 1) + end + !isfinite(x) && return copysign(x,s)*(y>0 || isnan(x)) # x is inf or NaN + return copysign(pow_body(abs(x), y), s) +end + +@inline function pow_body(x::Float64, y::Float64) + xu = reinterpret(UInt64, x) if xu < (UInt64(1)<<52) # x is subnormal xu = reinterpret(UInt64, x * 0x1p52) # normalize x xu &= ~sign_mask(Float64) xu -= UInt64(52) << 52 # mess with the exponent end - return pow_body(xu, y) -end - -@inline function pow_body(xu::UInt64, y::Float64) logxhi,logxlo = _log_ext(xu) xyhi, xylo = two_mul(logxhi,y) xylo = muladd(logxlo, y, xylo) @@ -1311,9 +1321,25 @@ end # compensated power by squaring @constprop :aggressive @inline function ^(x::Float64, n::Integer) n == 0 && return one(x) - return pow_body(x, n) + if use_power_by_squaring(n) + return pow_body(x, n) + else + s = ifelse(x < 0 && isodd(n), -1.0, 1.0) + x = abs(x) + y = Float64(n) + if y == n + return copysign(pow_body(x, y), s) + else + if n % Int64 != n + n = ifelse(n < 0, typemin(Int64), typemax(Int64)) + end + n1, n2 = divrem(n, Int64(1) << 53) + return pow_body(x, n1 * 0x1p53) * copysign(pow_body(x, Float64(n2)), s) + end + end end +# this method is only reliable for -2^20 < n < 2^20 (cf. #53881 #53886) @assume_effects :terminates_locally @noinline function pow_body(x::Float64, n::Integer) y = 1.0 xnlo = ynlo = 0.0 diff --git a/test/math.jl b/test/math.jl index f551bb3a5d4b7..a946c58db1573 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1459,6 +1459,20 @@ end # two cases where we have observed > 1 ULP in the past @test 0.0013653274095082324^-97.60372292227069 == 4.088393948750035e279 @test 8.758520413376658e-5^70.55863059215994 == 5.052076767078296e-287 + + # issue #53881 + @test prevfloat(1.0) ^ -Int64(2)^62 == 2.2844135865398217e222 + @test 2.0 ^ typemin(Int) == 0.0 + @test (-1.0) ^ typemin(Int) == 1.0 + Z = Int64(2) + @test prevfloat(1.0) ^ (-Z^54) ≈ 7.38905609893065 + @test prevfloat(1.0) ^ (-Z^62) ≈ 2.2844135865231613e222 + @test prevfloat(1.0) ^ (-Z^63) == Inf + @test prevfloat(1.0) ^ (Z^62-1) * prevfloat(1.0) ^ (-Z^62+1) == 1.0 + n, x = -1065564664, 0.9999997040311492 + @test abs(x^n - Float64(big(x)^n)) / eps(x^n) == 0 # ULPs + @test prevfloat(1.0) ^ (big(2)^100 + 1) == 0 + @test prevfloat(1.0) ^ 6705320061009595392 == nextfloat(0.0) end # Test that sqrt behaves correctly and doesn't exhibit fp80 double rounding. From 5c60c57fe7c8f5f5ab19265307f842775a7698e6 Mon Sep 17 00:00:00 2001 From: KlausC Date: Sat, 6 Apr 2024 09:43:10 +0200 Subject: [PATCH 02/14] use_pbs - better runtime prediction --- base/math.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/base/math.jl b/base/math.jl index ade93501dcbd3..5e252c1e492fc 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1256,7 +1256,9 @@ function modf(x::T) where T<:IEEEFloat end @inline function use_power_by_squaring(n::Integer) - -2^13 <= n < 2^13 + # -2^13 <= n < 2^13 + n = abs(n) + sizeof(n)*8 - Base.leading_zeros(n) + Base.count_ones(n) < 20 end # @constprop aggressive to help the compiler see the switch between the integer and float From c861bb0dd8d585f4ce659abd2d175c8a07f34458 Mon Sep 17 00:00:00 2001 From: KlausC Date: Sat, 6 Apr 2024 20:35:09 +0200 Subject: [PATCH 03/14] fixed lead_zeros bug introduced previously --- base/math.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/base/math.jl b/base/math.jl index 5e252c1e492fc..982681997a2b7 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1255,10 +1255,13 @@ function modf(x::T) where T<:IEEEFloat return (rx, ix) end +@inline function use_power_by_squaring(n::Union{Int32,Int64,Int128,UInt32,UInt64,UInt128}) + # top_set_bit is not available during bootstrap + x = abs(n) + 8sizeof(x) - leading_zeros(x) + count_ones(x) < 20 +end @inline function use_power_by_squaring(n::Integer) - # -2^13 <= n < 2^13 - n = abs(n) - sizeof(n)*8 - Base.leading_zeros(n) + Base.count_ones(n) < 20 + -2^13 <= n < 2^13 end # @constprop aggressive to help the compiler see the switch between the integer and float From 4ab70260b58cd03f5d3bb9de6d8a907e8207f856 Mon Sep 17 00:00:00 2001 From: KlausC Date: Wed, 10 Apr 2024 12:28:24 +0200 Subject: [PATCH 04/14] fixed corner cases and added tests --- base/math.jl | 13 +++++++++---- base/special/exp.jl | 2 +- test/math.jl | 16 ++++++++++------ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/base/math.jl b/base/math.jl index 982681997a2b7..fc357752374a9 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1277,7 +1277,7 @@ end end yint = unsafe_trunc(Int64, y) # This is actually safe since julia freezes the result yisint = y == yint - yisint && use_power_by_squaring(yint) && return @noinline x^yint + yisint && use_power_by_squaring(yint) && return @noinline pow_body(x, yint) 2*xu==0 && return abs(y)*Inf*(!(y>0)) # if x === +0.0 or -0.0 (Inf * false === 0.0) s = 1 if x < 0 @@ -1323,8 +1323,11 @@ end return T(exp2(log2(abs(widen(x))) * y)) end -# compensated power by squaring @constprop :aggressive @inline function ^(x::Float64, n::Integer) + x^clamp(n, Int64) +end +# compensated power by squaring +@constprop :aggressive @inline function ^(x::Float64, n::Int64) n == 0 && return one(x) if use_power_by_squaring(n) return pow_body(x, n) @@ -1338,8 +1341,9 @@ end if n % Int64 != n n = ifelse(n < 0, typemin(Int64), typemax(Int64)) end - n1, n2 = divrem(n, Int64(1) << 53) - return pow_body(x, n1 * 0x1p53) * copysign(pow_body(x, Float64(n2)), s) + n2 = n % 1024 + y = float(n - n2) + return pow_body(x, y) * copysign(pow_body(x, n2), s) end end end @@ -1347,6 +1351,7 @@ end # this method is only reliable for -2^20 < n < 2^20 (cf. #53881 #53886) @assume_effects :terminates_locally @noinline function pow_body(x::Float64, n::Integer) y = 1.0 + n == 0 && return y xnlo = ynlo = 0.0 n == 3 && return x*x*x # keep compatibility with literal_pow if n < 0 diff --git a/base/special/exp.jl b/base/special/exp.jl index 8e940a4d85ad9..312197339a086 100644 --- a/base/special/exp.jl +++ b/base/special/exp.jl @@ -250,7 +250,7 @@ end twopk = (k + UInt64(53)) << 52 return reinterpret(T, twopk + reinterpret(UInt64, small_part))*0x1p-53 end - #k == 1024 && return (small_part * 2.0) * 2.0^1023 + k == 1024 && return (small_part * 2.0) * 2.0^1023 end twopk = Int64(k) << 52 return reinterpret(T, twopk + reinterpret(Int64, small_part)) diff --git a/test/math.jl b/test/math.jl index a946c58db1573..8df07d97e2079 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1465,14 +1465,18 @@ end @test 2.0 ^ typemin(Int) == 0.0 @test (-1.0) ^ typemin(Int) == 1.0 Z = Int64(2) - @test prevfloat(1.0) ^ (-Z^54) ≈ 7.38905609893065 - @test prevfloat(1.0) ^ (-Z^62) ≈ 2.2844135865231613e222 - @test prevfloat(1.0) ^ (-Z^63) == Inf - @test prevfloat(1.0) ^ (Z^62-1) * prevfloat(1.0) ^ (-Z^62+1) == 1.0 + E = prevfloat(1.0) + @test E ^ (-Z^54) ≈ 7.38905609893065 + @test E ^ (-Z^62) ≈ 2.2844135865231613e222 + @test E ^ (-Z^63) == Inf + @test abs(E ^ (Z^62-1) * E ^ (-Z^62+1) - 1) <= eps(0.9) n, x = -1065564664, 0.9999997040311492 @test abs(x^n - Float64(big(x)^n)) / eps(x^n) == 0 # ULPs - @test prevfloat(1.0) ^ (big(2)^100 + 1) == 0 - @test prevfloat(1.0) ^ 6705320061009595392 == nextfloat(0.0) + @test E ^ (big(2)^100 + 1) == 0 + @test E ^ 6705320061009595392 == nextfloat(0.0) + n = Int(1024 / log2(E)) + @test E^n == Inf + @test E^float(n) == Inf end # Test that sqrt behaves correctly and doesn't exhibit fp80 double rounding. From bb7633c0a8217bc0b03e05b55ddc7c67a2f63eda Mon Sep 17 00:00:00 2001 From: KlausC Date: Wed, 10 Apr 2024 15:57:27 +0200 Subject: [PATCH 05/14] use_pbs threshold --- base/math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/math.jl b/base/math.jl index fc357752374a9..712c171cfcb78 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1258,7 +1258,7 @@ end @inline function use_power_by_squaring(n::Union{Int32,Int64,Int128,UInt32,UInt64,UInt128}) # top_set_bit is not available during bootstrap x = abs(n) - 8sizeof(x) - leading_zeros(x) + count_ones(x) < 20 + 2*(8sizeof(x) - leading_zeros(x)) + count_ones(x) + 6*(n<0) < 40 end @inline function use_power_by_squaring(n::Integer) -2^13 <= n < 2^13 From fed55b704b82683aaa39e391903931cf3b640deb Mon Sep 17 00:00:00 2001 From: KlausC Date: Thu, 11 Apr 2024 22:36:55 +0200 Subject: [PATCH 06/14] fixed effects in `^` --- base/math.jl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/base/math.jl b/base/math.jl index 712c171cfcb78..749d146199de3 100644 --- a/base/math.jl +++ b/base/math.jl @@ -37,7 +37,7 @@ end throw(DomainError(x, LazyString(f," was called with a real argument < -1 but will only return a complex result if called with a complex argument. Try ", f,"(Complex(x))."))) end -@noinline function throw_exp_domainerror(x) +@assume_effects :terminates_globally @noinline function throw_exp_domainerror(x) throw(DomainError(x, LazyString( "Exponentiation yielding a complex result requires a ", "complex argument.\nReplace x^y with (x+0im)^y, ", @@ -1277,7 +1277,10 @@ end end yint = unsafe_trunc(Int64, y) # This is actually safe since julia freezes the result yisint = y == yint - yisint && use_power_by_squaring(yint) && return @noinline pow_body(x, yint) + if yisint + yint == 0 && return 1.0 + use_power_by_squaring(yint) && return @noinline pow_body(x, yint) + end 2*xu==0 && return abs(y)*Inf*(!(y>0)) # if x === +0.0 or -0.0 (Inf * false === 0.0) s = 1 if x < 0 @@ -1288,7 +1291,7 @@ end return copysign(pow_body(abs(x), y), s) end -@inline function pow_body(x::Float64, y::Float64) +@assume_effects :total @noinline function pow_body(x::Float64, y::Float64) xu = reinterpret(UInt64, x) if xu < (UInt64(1)<<52) # x is subnormal xu = reinterpret(UInt64, x * 0x1p52) # normalize x @@ -1324,7 +1327,9 @@ end end @constprop :aggressive @inline function ^(x::Float64, n::Integer) - x^clamp(n, Int64) + T = Int64 + m = n >= typemax(T) ? typemax(T) : n <= typemin(T) ? typemin(T) : n + x^(m%Int64) end # compensated power by squaring @constprop :aggressive @inline function ^(x::Float64, n::Int64) From fd7fc04aed9686b0f374c8715d8fb1871006421e Mon Sep 17 00:00:00 2001 From: KlausC Date: Fri, 12 Apr 2024 09:45:08 +0200 Subject: [PATCH 07/14] fix tests for pow --- test/math.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/math.jl b/test/math.jl index 8df07d97e2079..96a51142ec887 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1469,12 +1469,12 @@ end @test E ^ (-Z^54) ≈ 7.38905609893065 @test E ^ (-Z^62) ≈ 2.2844135865231613e222 @test E ^ (-Z^63) == Inf - @test abs(E ^ (Z^62-1) * E ^ (-Z^62+1) - 1) <= eps(0.9) + @test abs(E ^ (Z^62-1) * E ^ (-Z^62+1) - 1) <= eps(1.0) n, x = -1065564664, 0.9999997040311492 @test abs(x^n - Float64(big(x)^n)) / eps(x^n) == 0 # ULPs @test E ^ (big(2)^100 + 1) == 0 @test E ^ 6705320061009595392 == nextfloat(0.0) - n = Int(1024 / log2(E)) + n = Int64(1024 / log2(E)) @test E^n == Inf @test E^float(n) == Inf end From 9f8e198af2710a5eb81a6a2e11add12d891f04fc Mon Sep 17 00:00:00 2001 From: KlausC Date: Fri, 12 Apr 2024 23:06:58 +0200 Subject: [PATCH 08/14] lest @assume_effects --- base/math.jl | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/base/math.jl b/base/math.jl index 749d146199de3..e0d0ef7b1b1f3 100644 --- a/base/math.jl +++ b/base/math.jl @@ -37,7 +37,7 @@ end throw(DomainError(x, LazyString(f," was called with a real argument < -1 but will only return a complex result if called with a complex argument. Try ", f,"(Complex(x))."))) end -@assume_effects :terminates_globally @noinline function throw_exp_domainerror(x) +@noinline function throw_exp_domainerror(x) throw(DomainError(x, LazyString( "Exponentiation yielding a complex result requires a ", "complex argument.\nReplace x^y with (x+0im)^y, ", @@ -1291,7 +1291,7 @@ end return copysign(pow_body(abs(x), y), s) end -@assume_effects :total @noinline function pow_body(x::Float64, y::Float64) +@assume_effects :foldable @noinline function pow_body(x::Float64, y::Float64) xu = reinterpret(UInt64, x) if xu < (UInt64(1)<<52) # x is subnormal xu = reinterpret(UInt64, x * 0x1p52) # normalize x @@ -1339,13 +1339,10 @@ end else s = ifelse(x < 0 && isodd(n), -1.0, 1.0) x = abs(x) - y = Float64(n) + y = float(n) if y == n return copysign(pow_body(x, y), s) else - if n % Int64 != n - n = ifelse(n < 0, typemin(Int64), typemax(Int64)) - end n2 = n % 1024 y = float(n - n2) return pow_body(x, y) * copysign(pow_body(x, n2), s) From ffe1c255546b9e8ef2d5383e4cb0ccc3ca772298 Mon Sep 17 00:00:00 2001 From: KlausC Date: Sat, 13 Apr 2024 10:14:49 +0200 Subject: [PATCH 09/14] simplified `use_power_by_squaring` --- base/math.jl | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/base/math.jl b/base/math.jl index e0d0ef7b1b1f3..8345c4f34fe41 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1255,13 +1255,8 @@ function modf(x::T) where T<:IEEEFloat return (rx, ix) end -@inline function use_power_by_squaring(n::Union{Int32,Int64,Int128,UInt32,UInt64,UInt128}) - # top_set_bit is not available during bootstrap - x = abs(n) - 2*(8sizeof(x) - leading_zeros(x)) + count_ones(x) + 6*(n<0) < 40 -end @inline function use_power_by_squaring(n::Integer) - -2^13 <= n < 2^13 + -2^13 <= n <= 2^15 end # @constprop aggressive to help the compiler see the switch between the integer and float From e9b33a26fc1b392923c85b62801b1a29cd25e5ad Mon Sep 17 00:00:00 2001 From: KlausC Date: Sat, 13 Apr 2024 13:43:56 +0200 Subject: [PATCH 10/14] adjusted nmin, nmax --- base/math.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/math.jl b/base/math.jl index 8345c4f34fe41..f512a545797ac 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1256,7 +1256,7 @@ function modf(x::T) where T<:IEEEFloat end @inline function use_power_by_squaring(n::Integer) - -2^13 <= n <= 2^15 + -2^12 <= n <= 3 * 2^13 end # @constprop aggressive to help the compiler see the switch between the integer and float From 06d0a7c222e843c7516d71018c5d5800a57ccd7c Mon Sep 17 00:00:00 2001 From: KlausC Date: Sat, 13 Apr 2024 13:53:34 +0200 Subject: [PATCH 11/14] use `clamp` --- base/math.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/base/math.jl b/base/math.jl index f512a545797ac..f506ca13cd773 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1322,11 +1322,8 @@ end end @constprop :aggressive @inline function ^(x::Float64, n::Integer) - T = Int64 - m = n >= typemax(T) ? typemax(T) : n <= typemin(T) ? typemin(T) : n - x^(m%Int64) + x^clamp(n, Int64) end -# compensated power by squaring @constprop :aggressive @inline function ^(x::Float64, n::Int64) n == 0 && return one(x) if use_power_by_squaring(n) @@ -1345,6 +1342,7 @@ end end end +# compensated power by squaring # this method is only reliable for -2^20 < n < 2^20 (cf. #53881 #53886) @assume_effects :terminates_locally @noinline function pow_body(x::Float64, n::Integer) y = 1.0 From 9f6d39d59ef731a95527dedee17928f44324b6c8 Mon Sep 17 00:00:00 2001 From: KlausC Date: Thu, 18 Apr 2024 18:32:55 +0200 Subject: [PATCH 12/14] try to inline `Base.Math.exp_impl` --- base/math.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/base/math.jl b/base/math.jl index 5afaa16988b64..2fc1ff27b2d25 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1292,7 +1292,7 @@ end return copysign(pow_body(abs(x), y), s) end -@assume_effects :foldable @noinline function pow_body(x::Float64, y::Float64) +@assume_effects :foldable @inline function pow_body(x::Float64, y::Float64) xu = reinterpret(UInt64, x) if xu < (UInt64(1)<<52) # x is subnormal xu = reinterpret(UInt64, x * 0x1p52) # normalize x @@ -1303,7 +1303,7 @@ end xyhi, xylo = two_mul(logxhi,y) xylo = muladd(logxlo, y, xylo) hi = xyhi+xylo - return Base.Math.exp_impl(hi, xylo-(hi-xyhi), Val(:ℯ)) + return @inline Base.Math.exp_impl(hi, xylo-(hi-xyhi), Val(:ℯ)) end @constprop :aggressive function ^(x::T, y::T) where T <: Union{Float16, Float32} From 2d6fdf56f697f7d63894b4c9b3ce64b4ee2e3129 Mon Sep 17 00:00:00 2001 From: KlausC Date: Thu, 18 Apr 2024 22:13:16 +0200 Subject: [PATCH 13/14] noinline pow_body, other compiler test --- base/math.jl | 2 +- test/compiler/codegen.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/base/math.jl b/base/math.jl index 2fc1ff27b2d25..9ce17a9bf77db 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1292,7 +1292,7 @@ end return copysign(pow_body(abs(x), y), s) end -@assume_effects :foldable @inline function pow_body(x::Float64, y::Float64) +@assume_effects :foldable @noinline function pow_body(x::Float64, y::Float64) xu = reinterpret(UInt64, x) if xu < (UInt64(1)<<52) # x is subnormal xu = reinterpret(UInt64, x * 0x1p52) # normalize x diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index 805e5c7acc817..3ad7c9bbb71d4 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -866,7 +866,7 @@ if Sys.ARCH === :x86_64 foo52079() = Core.Intrinsics.have_fma(Float64) if foo52079() == true let io = IOBuffer() - code_native(io,^,(Float64,Float64), dump_module=false) + code_native(io,Base.Math.exp_impl,(Float64,Float64,Val{:ℯ}), dump_module=false) str = String(take!(io)) @test !occursin("fma_emulated", str) @test occursin("vfmadd", str) From 4c7f788546aefb8626759355c5c3d714f5478394 Mon Sep 17 00:00:00 2001 From: KlausC Date: Sun, 21 Apr 2024 20:44:35 +0200 Subject: [PATCH 14/14] removed redundant code, mitigate test case --- base/math.jl | 1 - test/math.jl | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/base/math.jl b/base/math.jl index 9ce17a9bf77db..14242ba381cde 100644 --- a/base/math.jl +++ b/base/math.jl @@ -1352,7 +1352,6 @@ end # this method is only reliable for -2^20 < n < 2^20 (cf. #53881 #53886) @assume_effects :terminates_locally @noinline function pow_body(x::Float64, n::Integer) y = 1.0 - n == 0 && return y xnlo = ynlo = 0.0 n == 3 && return x*x*x # keep compatibility with literal_pow if n < 0 diff --git a/test/math.jl b/test/math.jl index f4118ff8ebde5..421c5387a522f 100644 --- a/test/math.jl +++ b/test/math.jl @@ -1472,7 +1472,8 @@ end @test 8.758520413376658e-5^70.55863059215994 == 5.052076767078296e-287 # issue #53881 - @test prevfloat(1.0) ^ -Int64(2)^62 == 2.2844135865398217e222 + c53881 = 2.2844135865398217e222 # check correctness within 2 ULPs + @test prevfloat(1.0) ^ -Int64(2)^62 ≈ c53881 atol=2eps(c53881) @test 2.0 ^ typemin(Int) == 0.0 @test (-1.0) ^ typemin(Int) == 1.0 Z = Int64(2)