Skip to content

Commit e0d49ac

Browse files
authored
move rem2pi and pow to special (#59545)
This makes math.jl slightly simpler with no functional differences. While cleaning up, I also removed Base.Math.libm which appears to be completely unused (and is an alias to Base.libm_name)
2 parents f818842 + b306585 commit e0d49ac

File tree

3 files changed

+287
-286
lines changed

3 files changed

+287
-286
lines changed

base/math.jl

Lines changed: 3 additions & 286 deletions
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,7 @@ Stacktrace:
328328
"""
329329
log(b::Number, x::Number) = log(promote(b,x)...)
330330

331-
# type specific math functions
332-
333331
const libm = Base.libm_name
334-
335332
# functions with no domain error
336333
"""
337334
sinh(x)
@@ -1149,148 +1146,7 @@ function modf(x::T) where T<:IEEEFloat
11491146
return (rx, ix)
11501147
end
11511148

1152-
@inline function use_power_by_squaring(n::Integer)
1153-
-2^12 <= n <= 3 * 2^13
1154-
end
1155-
1156-
# @constprop aggressive to help the compiler see the switch between the integer and float
1157-
# variants for callers with constant `y`
1158-
@constprop :aggressive function ^(x::Float64, y::Float64)
1159-
xu = reinterpret(UInt64, x)
1160-
xu == reinterpret(UInt64, 1.0) && return 1.0
1161-
# Exponents greater than this will always overflow or underflow.
1162-
# Note that NaN can pass through this, but that will end up fine.
1163-
if !(abs(y)<0x1.8p62)
1164-
isnan(y) && return y
1165-
y = sign(y)*0x1.8p62
1166-
end
1167-
yint = unsafe_trunc(Int64, y) # This is actually safe since julia freezes the result
1168-
yisint = y == yint
1169-
if yisint
1170-
yint == 0 && return 1.0
1171-
use_power_by_squaring(yint) && return @noinline pow_body(x, yint)
1172-
end
1173-
2*xu==0 && return abs(y)*Inf*(!(y>0)) # if x === +0.0 or -0.0 (Inf * false === 0.0)
1174-
s = 1
1175-
if x < 0
1176-
!yisint && throw_exp_domainerror(x) # y isn't an integer
1177-
s = ifelse(isodd(yint), -1, 1)
1178-
end
1179-
!isfinite(x) && return copysign(x,s)*(y>0 || isnan(x)) # x is inf or NaN
1180-
return copysign(pow_body(abs(x), y), s)
1181-
end
1182-
1183-
@assume_effects :foldable @noinline function pow_body(x::Float64, y::Float64)
1184-
xu = reinterpret(UInt64, x)
1185-
if xu < (UInt64(1)<<52) # x is subnormal
1186-
xu = reinterpret(UInt64, x * 0x1p52) # normalize x
1187-
xu &= ~sign_mask(Float64)
1188-
xu -= UInt64(52) << 52 # mess with the exponent
1189-
end
1190-
logxhi,logxlo = _log_ext(xu)
1191-
xyhi, xylo = two_mul(logxhi,y)
1192-
xylo = muladd(logxlo, y, xylo)
1193-
hi = xyhi+xylo
1194-
return @inline Base.Math.exp_impl(hi, xylo-(hi-xyhi), Val(:ℯ))
1195-
end
1196-
1197-
# @constprop aggressive to help the compiler see the switch between the integer and float
1198-
# variants for callers with constant `y`
1199-
@constprop :aggressive function ^(x::T, y::T) where T <: Union{Float16, Float32}
1200-
x == 1 && return one(T)
1201-
# Exponents greater than this will always overflow or underflow.
1202-
# Note that NaN can pass through this, but that will end up fine.
1203-
max_exp = T == Float16 ? T(3<<14) : T(0x1.Ap30)
1204-
if !(abs(y)<max_exp)
1205-
isnan(y) && return y
1206-
y = sign(y)*max_exp
1207-
end
1208-
yint = unsafe_trunc(Int32, y) # This is actually safe since julia freezes the result
1209-
yisint = y == yint
1210-
if yisint
1211-
yint == 0 && return one(T)
1212-
use_power_by_squaring(yint) && return pow_body(x, yint)
1213-
end
1214-
s = 1
1215-
if x < 0
1216-
!yisint && throw_exp_domainerror(x) # y isn't an integer
1217-
s = ifelse(isodd(yint), -1, 1)
1218-
end
1219-
!isfinite(x) && return copysign(x,s)*(y>0 || isnan(x)) # x is inf or NaN
1220-
return copysign(pow_body(abs(x), y), s)
1221-
end
1222-
1223-
@inline function pow_body(x::T, y) where T <: Union{Float16, Float32}
1224-
return T(exp2(log2(abs(widen(x))) * y))
1225-
end
1226-
1227-
@inline function pow_body(x::Union{Float16, Float32}, n::Int32)
1228-
n == -2 && return (i=inv(x); i*i)
1229-
n == 3 && return x*x*x #keep compatibility with literal_pow
1230-
n < 0 && return oftype(x, Base.power_by_squaring(inv(widen(x)), -n))
1231-
return oftype(x, Base.power_by_squaring(widen(x), n))
1232-
end
12331149

1234-
@constprop :aggressive @inline function ^(x::Float64, n::Integer)
1235-
n = clamp(n, Int64)
1236-
n == 0 && return one(x)
1237-
if use_power_by_squaring(n)
1238-
return pow_body(x, n)
1239-
else
1240-
s = ifelse(x < 0 && isodd(n), -1.0, 1.0)
1241-
x = abs(x)
1242-
y = float(n)
1243-
if y == n
1244-
return copysign(pow_body(x, y), s)
1245-
else
1246-
n2 = n % 1024
1247-
y = float(n - n2)
1248-
return pow_body(x, y) * copysign(pow_body(x, n2), s)
1249-
end
1250-
end
1251-
end
1252-
1253-
# compensated power by squaring
1254-
# this method is only reliable for -2^20 < n < 2^20 (cf. #53881 #53886)
1255-
@assume_effects :terminates_locally @noinline function pow_body(x::Float64, n::Integer)
1256-
y = 1.0
1257-
xnlo = -0.0
1258-
ynlo = 0.0
1259-
n == 3 && return x*x*x # keep compatibility with literal_pow
1260-
if n < 0
1261-
rx = inv(x)
1262-
n==-2 && return rx*rx #keep compatibility with literal_pow
1263-
isfinite(x) && (xnlo = -fma(x, rx, -1.) * rx)
1264-
x = rx
1265-
n = -n
1266-
end
1267-
while n > 1
1268-
if n&1 > 0
1269-
err = muladd(y, xnlo, x*ynlo)
1270-
y, ynlo = two_mul(x,y)
1271-
ynlo += err
1272-
end
1273-
err = x*2*xnlo
1274-
x, xnlo = two_mul(x, x)
1275-
xnlo += err
1276-
n >>>= 1
1277-
end
1278-
err = muladd(y, xnlo, x*ynlo)
1279-
return ifelse(isfinite(x) & isfinite(err), muladd(x, y, err), x*y)
1280-
end
1281-
1282-
# @constprop aggressive to help the compiler see the switch between the integer and float
1283-
# variants for callers with constant `y`
1284-
@constprop :aggressive @inline function ^(x::T, n::Integer) where T <: Union{Float16, Float32}
1285-
n = clamp(n, Int32)
1286-
# Exponents greater than this will always overflow or underflow.
1287-
# Note that NaN can pass through this, but that will end up fine.
1288-
n == 0 && return one(x)
1289-
use_power_by_squaring(n) && return pow_body(x, n)
1290-
s = ifelse(x < 0 && isodd(n), -one(T), one(T))
1291-
x = abs(x)
1292-
return pow_body(x, widen(T)(n))
1293-
end
12941150

12951151
## rem2pi-related calculations ##
12961152

@@ -1305,19 +1161,6 @@ function add22condh(xh::Float64, xl::Float64, yh::Float64, yl::Float64)
13051161
return zh
13061162
end
13071163

1308-
# multiples of pi/2, as double-double (ie with "tail")
1309-
const pi1o2_h = 1.5707963267948966 # convert(Float64, pi * BigFloat(1/2))
1310-
const pi1o2_l = 6.123233995736766e-17 # convert(Float64, pi * BigFloat(1/2) - pi1o2_h)
1311-
1312-
const pi2o2_h = 3.141592653589793 # convert(Float64, pi * BigFloat(1))
1313-
const pi2o2_l = 1.2246467991473532e-16 # convert(Float64, pi * BigFloat(1) - pi2o2_h)
1314-
1315-
const pi3o2_h = 4.71238898038469 # convert(Float64, pi * BigFloat(3/2))
1316-
const pi3o2_l = 1.8369701987210297e-16 # convert(Float64, pi * BigFloat(3/2) - pi3o2_h)
1317-
1318-
const pi4o2_h = 6.283185307179586 # convert(Float64, pi * BigFloat(2))
1319-
const pi4o2_l = 2.4492935982947064e-16 # convert(Float64, pi * BigFloat(2) - pi4o2_h)
1320-
13211164
"""
13221165
rem2pi(x, r::RoundingMode)
13231166
@@ -1350,135 +1193,6 @@ julia> rem2pi(7pi/4, RoundDown)
13501193
```
13511194
"""
13521195
function rem2pi end
1353-
function rem2pi(x::Float64, ::RoundingMode{:Nearest})
1354-
isnan(x) && return x
1355-
isinf(x) && return NaN
1356-
1357-
abs(x) < pi && return x
1358-
1359-
n,y = rem_pio2_kernel(x)
1360-
1361-
if iseven(n)
1362-
if n & 2 == 2 # n % 4 == 2: add/subtract pi
1363-
if y.hi <= 0
1364-
return add22condh(y.hi,y.lo,pi2o2_h,pi2o2_l)
1365-
else
1366-
return add22condh(y.hi,y.lo,-pi2o2_h,-pi2o2_l)
1367-
end
1368-
else # n % 4 == 0: add 0
1369-
return y.hi+y.lo
1370-
end
1371-
else
1372-
if n & 2 == 2 # n % 4 == 3: subtract pi/2
1373-
return add22condh(y.hi,y.lo,-pi1o2_h,-pi1o2_l)
1374-
else # n % 4 == 1: add pi/2
1375-
return add22condh(y.hi,y.lo,pi1o2_h,pi1o2_l)
1376-
end
1377-
end
1378-
end
1379-
function rem2pi(x::Float64, ::RoundingMode{:ToZero})
1380-
isnan(x) && return x
1381-
isinf(x) && return NaN
1382-
1383-
ax = abs(x)
1384-
ax <= 2*Float64(pi,RoundDown) && return x
1385-
1386-
n,y = rem_pio2_kernel(ax)
1387-
1388-
if iseven(n)
1389-
if n & 2 == 2 # n % 4 == 2: add pi
1390-
z = add22condh(y.hi,y.lo,pi2o2_h,pi2o2_l)
1391-
else # n % 4 == 0: add 0 or 2pi
1392-
if y.hi > 0
1393-
z = y.hi+y.lo
1394-
else # negative: add 2pi
1395-
z = add22condh(y.hi,y.lo,pi4o2_h,pi4o2_l)
1396-
end
1397-
end
1398-
else
1399-
if n & 2 == 2 # n % 4 == 3: add 3pi/2
1400-
z = add22condh(y.hi,y.lo,pi3o2_h,pi3o2_l)
1401-
else # n % 4 == 1: add pi/2
1402-
z = add22condh(y.hi,y.lo,pi1o2_h,pi1o2_l)
1403-
end
1404-
end
1405-
copysign(z,x)
1406-
end
1407-
function rem2pi(x::Float64, ::RoundingMode{:Down})
1408-
isnan(x) && return x
1409-
isinf(x) && return NaN
1410-
1411-
if x < pi4o2_h
1412-
if x >= 0
1413-
return x
1414-
elseif x > -pi4o2_h
1415-
return add22condh(x,0.0,pi4o2_h,pi4o2_l)
1416-
end
1417-
end
1418-
1419-
n,y = rem_pio2_kernel(x)
1420-
1421-
if iseven(n)
1422-
if n & 2 == 2 # n % 4 == 2: add pi
1423-
return add22condh(y.hi,y.lo,pi2o2_h,pi2o2_l)
1424-
else # n % 4 == 0: add 0 or 2pi
1425-
if y.hi > 0
1426-
return y.hi+y.lo
1427-
else # negative: add 2pi
1428-
return add22condh(y.hi,y.lo,pi4o2_h,pi4o2_l)
1429-
end
1430-
end
1431-
else
1432-
if n & 2 == 2 # n % 4 == 3: add 3pi/2
1433-
return add22condh(y.hi,y.lo,pi3o2_h,pi3o2_l)
1434-
else # n % 4 == 1: add pi/2
1435-
return add22condh(y.hi,y.lo,pi1o2_h,pi1o2_l)
1436-
end
1437-
end
1438-
end
1439-
function rem2pi(x::Float64, ::RoundingMode{:Up})
1440-
isnan(x) && return x
1441-
isinf(x) && return NaN
1442-
1443-
if x > -pi4o2_h
1444-
if x <= 0
1445-
return x
1446-
elseif x < pi4o2_h
1447-
return add22condh(x,0.0,-pi4o2_h,-pi4o2_l)
1448-
end
1449-
end
1450-
1451-
n,y = rem_pio2_kernel(x)
1452-
1453-
if iseven(n)
1454-
if n & 2 == 2 # n % 4 == 2: sub pi
1455-
return add22condh(y.hi,y.lo,-pi2o2_h,-pi2o2_l)
1456-
else # n % 4 == 0: sub 0 or 2pi
1457-
if y.hi < 0
1458-
return y.hi+y.lo
1459-
else # positive: sub 2pi
1460-
return add22condh(y.hi,y.lo,-pi4o2_h,-pi4o2_l)
1461-
end
1462-
end
1463-
else
1464-
if n & 2 == 2 # n % 4 == 3: sub pi/2
1465-
return add22condh(y.hi,y.lo,-pi1o2_h,-pi1o2_l)
1466-
else # n % 4 == 1: sub 3pi/2
1467-
return add22condh(y.hi,y.lo,-pi3o2_h,-pi3o2_l)
1468-
end
1469-
end
1470-
end
1471-
1472-
rem2pi(x::Float32, r::RoundingMode) = Float32(rem2pi(Float64(x), r))
1473-
rem2pi(x::Float16, r::RoundingMode) = Float16(rem2pi(Float64(x), r))
1474-
rem2pi(x::Int32, r::RoundingMode) = rem2pi(Float64(x), r)
1475-
1476-
# general fallback
1477-
function rem2pi(x::Integer, r::RoundingMode)
1478-
fx = float(x)
1479-
fx == x || throw(ArgumentError(LazyString(typeof(x), " argument to rem2pi is too large: ", x)))
1480-
rem2pi(fx, r)
1481-
end
14821196

14831197
"""
14841198
mod2pi(x)
@@ -1558,7 +1272,10 @@ include("special/exp.jl")
15581272
include("special/hyperbolic.jl")
15591273
include("special/trig.jl")
15601274
include("special/rem_pio2.jl")
1275+
include("special/rem2pi.jl")
15611276
include("special/log.jl")
1277+
include("special/pow.jl")
1278+
15621279

15631280

15641281
# Float16 definitions

0 commit comments

Comments
 (0)