@@ -1140,6 +1140,10 @@ function modf(x::T) where T<:IEEEFloat
11401140 return (rx, ix)
11411141end
11421142
1143+ @inline function use_power_by_squaring (n:: Integer )
1144+ - 2 ^ 12 <= n <= 3 * 2 ^ 13
1145+ end
1146+
11431147# @constprop aggressive to help the compiler see the switch between the integer and float
11441148# variants for callers with constant `y`
11451149@constprop :aggressive function ^ (x:: Float64 , y:: Float64 )
@@ -1152,24 +1156,33 @@ end
11521156 y = sign (y)* 0x1 .8 p62
11531157 end
11541158 yint = unsafe_trunc (Int64, y) # This is actually safe since julia freezes the result
1155- y == yint && return @noinline x^ yint
1156- 2 * xu== 0 && return abs (y)* Inf * (! (y> 0 )) # if x==0
1157- x< 0 && throw_exp_domainerror (x) # |y| is small enough that y isn't an integer
1158- ! isfinite (x) && return x* (y> 0 || isnan (x)) # x is inf or NaN
1159+ yisint = y == yint
1160+ if yisint
1161+ yint == 0 && return 1.0
1162+ use_power_by_squaring (yint) && return @noinline pow_body (x, yint)
1163+ end
1164+ 2 * xu== 0 && return abs (y)* Inf * (! (y> 0 )) # if x === +0.0 or -0.0 (Inf * false === 0.0)
1165+ s = 1
1166+ if x < 0
1167+ ! yisint && throw_exp_domainerror (x) # y isn't an integer
1168+ s = ifelse (isodd (yint), - 1 , 1 )
1169+ end
1170+ ! isfinite (x) && return copysign (x,s)* (y> 0 || isnan (x)) # x is inf or NaN
1171+ return copysign (pow_body (abs (x), y), s)
1172+ end
1173+
1174+ @assume_effects :foldable @noinline function pow_body (x:: Float64 , y:: Float64 )
1175+ xu = reinterpret (UInt64, x)
11591176 if xu < (UInt64 (1 )<< 52 ) # x is subnormal
11601177 xu = reinterpret (UInt64, x * 0x1 p52) # normalize x
11611178 xu &= ~ sign_mask (Float64)
11621179 xu -= UInt64 (52 ) << 52 # mess with the exponent
11631180 end
1164- return pow_body (xu, y)
1165- end
1166-
1167- @inline function pow_body (xu:: UInt64 , y:: Float64 )
11681181 logxhi,logxlo = _log_ext (xu)
11691182 xyhi, xylo = two_mul (logxhi,y)
11701183 xylo = muladd (logxlo, y, xylo)
11711184 hi = xyhi+ xylo
1172- return Base. Math. exp_impl (hi, xylo- (hi- xyhi), Val (:ℯ ))
1185+ return @inline Base. Math. exp_impl (hi, xylo- (hi- xyhi), Val (:ℯ ))
11731186end
11741187
11751188@constprop :aggressive function ^ (x:: T , y:: T ) where T <: Union{Float16, Float32}
@@ -1193,12 +1206,29 @@ end
11931206 return T (exp2 (log2 (abs (widen (x))) * y))
11941207end
11951208
1196- # compensated power by squaring
11971209@constprop :aggressive @inline function ^ (x:: Float64 , n:: Integer )
1210+ x^ clamp (n, Int64)
1211+ end
1212+ @constprop :aggressive @inline function ^ (x:: Float64 , n:: Int64 )
11981213 n == 0 && return one (x)
1199- return pow_body (x, n)
1214+ if use_power_by_squaring (n)
1215+ return pow_body (x, n)
1216+ else
1217+ s = ifelse (x < 0 && isodd (n), - 1.0 , 1.0 )
1218+ x = abs (x)
1219+ y = float (n)
1220+ if y == n
1221+ return copysign (pow_body (x, y), s)
1222+ else
1223+ n2 = n % 1024
1224+ y = float (n - n2)
1225+ return pow_body (x, y) * copysign (pow_body (x, n2), s)
1226+ end
1227+ end
12001228end
12011229
1230+ # compensated power by squaring
1231+ # this method is only reliable for -2^20 < n < 2^20 (cf. #53881 #53886)
12021232@assume_effects :terminates_locally @noinline function pow_body (x:: Float64 , n:: Integer )
12031233 y = 1.0
12041234 xnlo = ynlo = 0.0
0 commit comments