Skip to content

Commit 5722e39

Browse files
committed
unify and deduplicate floats
1 parent 34a8c73 commit 5722e39

File tree

6 files changed

+339
-1168
lines changed

6 files changed

+339
-1168
lines changed

library/coretests/tests/floats/mod.rs

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,25 @@ trait TestableFloat: Sized {
88
const APPROX: Self;
99
/// Allow looser tolerance for f32 on miri
1010
const POWI_APPROX: Self = Self::APPROX;
11+
/// Tolerance for `powf` tests; some types need looser bounds
12+
const POWF_APPROX: Self = Self::APPROX;
1113
/// Allow looser tolerance for f16
1214
const _180_TO_RADIANS_APPROX: Self = Self::APPROX;
1315
/// Allow for looser tolerance for f16
1416
const PI_TO_DEGREES_APPROX: Self = Self::APPROX;
17+
/// Tolerance for math tests
18+
const EXP_APPROX: Self = Self::APPROX;
19+
const LN_APPROX: Self = Self::APPROX;
20+
const LOG_APPROX: Self = Self::APPROX;
21+
const LOG2_APPROX: Self = Self::APPROX;
22+
const LOG10_APPROX: Self = Self::APPROX;
23+
const ASINH_APPROX: Self = Self::APPROX;
24+
const ACOSH_APPROX: Self = Self::APPROX;
25+
const ATANH_APPROX: Self = Self::APPROX;
26+
const GAMMA_APPROX: Self = Self::APPROX;
27+
const GAMMA_APPROX_LOOSE: Self = Self::APPROX;
28+
const LNGAMMA_APPROX: Self = Self::APPROX;
29+
const LNGAMMA_APPROX_LOOSE: Self = Self::APPROX;
1530
const ZERO: Self;
1631
const ONE: Self;
1732
const PI: Self;
@@ -45,8 +60,21 @@ trait TestableFloat: Sized {
4560
impl TestableFloat for f16 {
4661
type Int = u16;
4762
const APPROX: Self = 1e-3;
63+
const POWF_APPROX: Self = 5e-1;
4864
const _180_TO_RADIANS_APPROX: Self = 1e-2;
4965
const PI_TO_DEGREES_APPROX: Self = 0.125;
66+
const EXP_APPROX: Self = 1e-2;
67+
const LN_APPROX: Self = 1e-2;
68+
const LOG_APPROX: Self = 1e-2;
69+
const LOG2_APPROX: Self = 1e-2;
70+
const LOG10_APPROX: Self = 1e-2;
71+
const ASINH_APPROX: Self = 1e-2;
72+
const ACOSH_APPROX: Self = 1e-2;
73+
const ATANH_APPROX: Self = 1e-2;
74+
const GAMMA_APPROX: Self = 1e-2;
75+
const GAMMA_APPROX_LOOSE: Self = 1e-1;
76+
const LNGAMMA_APPROX: Self = 1e-2;
77+
const LNGAMMA_APPROX_LOOSE: Self = 1e-1;
5078
const ZERO: Self = 0.0;
5179
const ONE: Self = 1.0;
5280
const PI: Self = std::f16::consts::PI;
@@ -76,6 +104,19 @@ impl TestableFloat for f32 {
76104
/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides.
77105
/// They serve as a way to get an idea of the real precision of floating point operations on different platforms.
78106
const POWI_APPROX: Self = if cfg!(miri) { 1e-4 } else { Self::APPROX };
107+
const POWF_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-4 };
108+
const EXP_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
109+
const LN_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
110+
const LOG_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
111+
const LOG2_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
112+
const LOG10_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
113+
const ASINH_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
114+
const ACOSH_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
115+
const ATANH_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
116+
const GAMMA_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
117+
const GAMMA_APPROX_LOOSE: Self = if cfg!(miri) { 1e-2 } else { 1e-4 };
118+
const LNGAMMA_APPROX: Self = if cfg!(miri) { 1e-3 } else { 1e-6 };
119+
const LNGAMMA_APPROX_LOOSE: Self = if cfg!(miri) { 1e-2 } else { 1e-4 };
79120
const ZERO: Self = 0.0;
80121
const ONE: Self = 1.0;
81122
const PI: Self = std::f32::consts::PI;
@@ -101,6 +142,18 @@ impl TestableFloat for f32 {
101142
impl TestableFloat for f64 {
102143
type Int = u64;
103144
const APPROX: Self = 1e-6;
145+
const EXP_APPROX: Self = 1e-6;
146+
const LN_APPROX: Self = 1e-6;
147+
const LOG_APPROX: Self = 1e-6;
148+
const LOG2_APPROX: Self = 1e-6;
149+
const LOG10_APPROX: Self = 1e-6;
150+
const ASINH_APPROX: Self = 1e-6;
151+
const ACOSH_APPROX: Self = 1e-6;
152+
const ATANH_APPROX: Self = 1e-6;
153+
const GAMMA_APPROX: Self = 1e-6;
154+
const GAMMA_APPROX_LOOSE: Self = 1e-4;
155+
const LNGAMMA_APPROX: Self = 1e-6;
156+
const LNGAMMA_APPROX_LOOSE: Self = 1e-4;
104157
const ZERO: Self = 0.0;
105158
const ONE: Self = 1.0;
106159
const PI: Self = std::f64::consts::PI;
@@ -126,6 +179,18 @@ impl TestableFloat for f64 {
126179
impl TestableFloat for f128 {
127180
type Int = u128;
128181
const APPROX: Self = 1e-9;
182+
const EXP_APPROX: Self = 1e-12;
183+
const LN_APPROX: Self = 1e-12;
184+
const LOG_APPROX: Self = 1e-12;
185+
const LOG2_APPROX: Self = 1e-12;
186+
const LOG10_APPROX: Self = 1e-12;
187+
const ASINH_APPROX: Self = 1e-10;
188+
const ACOSH_APPROX: Self = 1e-10;
189+
const ATANH_APPROX: Self = 1e-10;
190+
const GAMMA_APPROX: Self = 1e-12;
191+
const GAMMA_APPROX_LOOSE: Self = 1e-10;
192+
const LNGAMMA_APPROX: Self = 1e-12;
193+
const LNGAMMA_APPROX_LOOSE: Self = 1e-10;
129194
const ZERO: Self = 0.0;
130195
const ONE: Self = 1.0;
131196
const PI: Self = std::f128::consts::PI;
@@ -1465,6 +1530,279 @@ float_test! {
14651530
}
14661531
}
14671532

1533+
float_test! {
1534+
name: powf,
1535+
attrs: {
1536+
const: #[cfg(false)],
1537+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1538+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1539+
},
1540+
test<Float> {
1541+
let nan: Float = Float::NAN;
1542+
let inf: Float = Float::INFINITY;
1543+
let neg_inf: Float = Float::NEG_INFINITY;
1544+
assert_biteq!((1.0 as Float).powf(1.0), 1.0);
1545+
assert_approx_eq!((3.4 as Float).powf(4.5), 246.40818323761893, Float::POWF_APPROX);
1546+
assert_approx_eq!((2.7 as Float).powf(-3.2), 0.04165200910852618, Float::POWF_APPROX);
1547+
assert_approx_eq!(((-3.1) as Float).powf(2.0), 9.61, Float::POWF_APPROX);
1548+
assert_approx_eq!((5.9 as Float).powf(-2.0), 0.028727377190462507, Float::POWF_APPROX);
1549+
assert_biteq!((8.3 as Float).powf(0.0), 1.0);
1550+
assert!(nan.powf(2.0).is_nan());
1551+
assert_biteq!(inf.powf(2.0), inf);
1552+
assert_biteq!(neg_inf.powf(3.0), neg_inf);
1553+
}
1554+
}
1555+
1556+
float_test! {
1557+
name: exp,
1558+
attrs: {
1559+
const: #[cfg(false)],
1560+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1561+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1562+
},
1563+
test<Float> {
1564+
assert_biteq!(1.0, (0.0 as Float).exp());
1565+
assert_approx_eq!(2.718281828459045, (1.0 as Float).exp(), Float::EXP_APPROX);
1566+
assert_approx_eq!(148.413159, (5.0 as Float).exp(), Float::EXP_APPROX);
1567+
1568+
let inf: Float = Float::INFINITY;
1569+
let neg_inf: Float = Float::NEG_INFINITY;
1570+
let nan: Float = Float::NAN;
1571+
assert_biteq!(inf, inf.exp());
1572+
assert_biteq!(0.0, neg_inf.exp());
1573+
assert!(nan.exp().is_nan());
1574+
}
1575+
}
1576+
1577+
float_test! {
1578+
name: exp2,
1579+
attrs: {
1580+
const: #[cfg(false)],
1581+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1582+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1583+
},
1584+
test<Float> {
1585+
assert_biteq!(32.0, (5.0 as Float).exp2());
1586+
assert_biteq!(1.0, (0.0 as Float).exp2());
1587+
1588+
let inf: Float = Float::INFINITY;
1589+
let neg_inf: Float = Float::NEG_INFINITY;
1590+
let nan: Float = Float::NAN;
1591+
assert_biteq!(inf, inf.exp2());
1592+
assert_biteq!(0.0, neg_inf.exp2());
1593+
assert!(nan.exp2().is_nan());
1594+
}
1595+
}
1596+
1597+
float_test! {
1598+
name: ln,
1599+
attrs: {
1600+
const: #[cfg(false)],
1601+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1602+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1603+
},
1604+
test<Float> {
1605+
let nan: Float = Float::NAN;
1606+
let inf: Float = Float::INFINITY;
1607+
let neg_inf: Float = Float::NEG_INFINITY;
1608+
assert_approx_eq!((1.0 as Float).exp().ln(), 1.0, Float::LN_APPROX);
1609+
assert!(nan.ln().is_nan());
1610+
assert_biteq!(inf.ln(), inf);
1611+
assert!(neg_inf.ln().is_nan());
1612+
assert!((-2.3 as Float).ln().is_nan());
1613+
assert_biteq!((-0.0 as Float).ln(), neg_inf);
1614+
assert_biteq!((0.0 as Float).ln(), neg_inf);
1615+
assert_approx_eq!((4.0 as Float).ln(), 1.3862943611198906, Float::LN_APPROX);
1616+
}
1617+
}
1618+
1619+
float_test! {
1620+
name: log_generic,
1621+
attrs: {
1622+
const: #[cfg(false)],
1623+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1624+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1625+
},
1626+
test<Float> {
1627+
let nan: Float = Float::NAN;
1628+
let inf: Float = Float::INFINITY;
1629+
let neg_inf: Float = Float::NEG_INFINITY;
1630+
assert_biteq!((10.0 as Float).log(10.0), 1.0);
1631+
assert_approx_eq!((2.3 as Float).log(3.5), 0.664858, Float::LOG_APPROX);
1632+
assert_approx_eq!((1.0 as Float).exp().log((1.0 as Float).exp()), 1.0, Float::LOG_APPROX);
1633+
assert!((1.0 as Float).log(1.0).is_nan());
1634+
assert!((1.0 as Float).log(-13.9).is_nan());
1635+
assert!(nan.log(2.3).is_nan());
1636+
assert_biteq!(inf.log(10.0), inf);
1637+
assert!(neg_inf.log(8.8).is_nan());
1638+
assert!((-2.3 as Float).log(0.1).is_nan());
1639+
assert_biteq!((-0.0 as Float).log(2.0), neg_inf);
1640+
assert_biteq!((0.0 as Float).log(7.0), neg_inf);
1641+
}
1642+
}
1643+
1644+
float_test! {
1645+
name: log2,
1646+
attrs: {
1647+
const: #[cfg(false)],
1648+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1649+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1650+
},
1651+
test<Float> {
1652+
let nan: Float = Float::NAN;
1653+
let inf: Float = Float::INFINITY;
1654+
let neg_inf: Float = Float::NEG_INFINITY;
1655+
assert_approx_eq!((10.0 as Float).log2(), 3.321928, Float::LOG2_APPROX);
1656+
assert_approx_eq!((2.3 as Float).log2(), 1.201634, Float::LOG2_APPROX);
1657+
assert_approx_eq!((1.0 as Float).exp().log2(), 1.442695, Float::LOG2_APPROX);
1658+
assert!(nan.log2().is_nan());
1659+
assert_biteq!(inf.log2(), inf);
1660+
assert!(neg_inf.log2().is_nan());
1661+
assert!((-2.3 as Float).log2().is_nan());
1662+
assert_biteq!((-0.0 as Float).log2(), neg_inf);
1663+
assert_biteq!((0.0 as Float).log2(), neg_inf);
1664+
}
1665+
}
1666+
1667+
float_test! {
1668+
name: log10,
1669+
attrs: {
1670+
const: #[cfg(false)],
1671+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1672+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1673+
},
1674+
test<Float> {
1675+
let nan: Float = Float::NAN;
1676+
let inf: Float = Float::INFINITY;
1677+
let neg_inf: Float = Float::NEG_INFINITY;
1678+
assert_biteq!((10.0 as Float).log10(), 1.0);
1679+
assert_approx_eq!((2.3 as Float).log10(), 0.361728, Float::LOG10_APPROX);
1680+
assert_approx_eq!((1.0 as Float).exp().log10(), 0.43429448, Float::LOG10_APPROX);
1681+
assert_biteq!((1.0 as Float).log10(), 0.0);
1682+
assert!(nan.log10().is_nan());
1683+
assert_biteq!(inf.log10(), inf);
1684+
assert!(neg_inf.log10().is_nan());
1685+
assert!((-2.3 as Float).log10().is_nan());
1686+
assert_biteq!((-0.0 as Float).log10(), neg_inf);
1687+
assert_biteq!((0.0 as Float).log10(), neg_inf);
1688+
}
1689+
}
1690+
1691+
float_test! {
1692+
name: asinh,
1693+
attrs: {
1694+
const: #[cfg(false)],
1695+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1696+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1697+
},
1698+
test<Float> {
1699+
assert_biteq!((0.0 as Float).asinh(), 0.0);
1700+
assert_biteq!((-0.0 as Float).asinh(), -0.0);
1701+
1702+
let inf: Float = Float::INFINITY;
1703+
let neg_inf: Float = Float::NEG_INFINITY;
1704+
let nan: Float = Float::NAN;
1705+
assert_biteq!(inf.asinh(), inf);
1706+
assert_biteq!(neg_inf.asinh(), neg_inf);
1707+
assert!(nan.asinh().is_nan());
1708+
assert!((-0.0 as Float).asinh().is_sign_negative());
1709+
assert_approx_eq!((2.0 as Float).asinh(), 1.4436354751788103, Float::ASINH_APPROX);
1710+
assert_approx_eq!((-2.0 as Float).asinh(), -1.4436354751788103, Float::ASINH_APPROX);
1711+
}
1712+
}
1713+
1714+
float_test! {
1715+
name: acosh,
1716+
attrs: {
1717+
const: #[cfg(false)],
1718+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1719+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1720+
},
1721+
test<Float> {
1722+
assert_biteq!((1.0 as Float).acosh(), 0.0);
1723+
assert!((0.999 as Float).acosh().is_nan());
1724+
1725+
let inf: Float = Float::INFINITY;
1726+
let neg_inf: Float = Float::NEG_INFINITY;
1727+
let nan: Float = Float::NAN;
1728+
assert_biteq!(inf.acosh(), inf);
1729+
assert!(neg_inf.acosh().is_nan());
1730+
assert!(nan.acosh().is_nan());
1731+
assert_approx_eq!((2.0 as Float).acosh(), 1.3169578969248167, Float::ACOSH_APPROX);
1732+
assert_approx_eq!((3.0 as Float).acosh(), 1.762747174039086, Float::ACOSH_APPROX);
1733+
}
1734+
}
1735+
1736+
float_test! {
1737+
name: atanh,
1738+
attrs: {
1739+
const: #[cfg(false)],
1740+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1741+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1742+
},
1743+
test<Float> {
1744+
assert_biteq!((0.0 as Float).atanh(), 0.0);
1745+
assert_biteq!((-0.0 as Float).atanh(), -0.0);
1746+
1747+
let inf: Float = Float::INFINITY;
1748+
let neg_inf: Float = Float::NEG_INFINITY;
1749+
assert_biteq!((1.0 as Float).atanh(), inf);
1750+
assert_biteq!((-1.0 as Float).atanh(), neg_inf);
1751+
1752+
let nan: Float = Float::NAN;
1753+
assert!(inf.atanh().is_nan());
1754+
assert!(neg_inf.atanh().is_nan());
1755+
assert!(nan.atanh().is_nan());
1756+
1757+
assert_approx_eq!((0.5 as Float).atanh(), 0.5493061443340548, Float::ATANH_APPROX);
1758+
assert_approx_eq!((-0.5 as Float).atanh(), -0.5493061443340548, Float::ATANH_APPROX);
1759+
}
1760+
}
1761+
1762+
float_test! {
1763+
name: gamma,
1764+
attrs: {
1765+
const: #[cfg(false)],
1766+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1767+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1768+
},
1769+
test<Float> {
1770+
assert_approx_eq!((1.0 as Float).gamma(), 1.0, Float::GAMMA_APPROX);
1771+
assert_approx_eq!((2.0 as Float).gamma(), 1.0, Float::GAMMA_APPROX);
1772+
assert_approx_eq!((3.0 as Float).gamma(), 2.0, Float::GAMMA_APPROX);
1773+
assert_approx_eq!((4.0 as Float).gamma(), 6.0, Float::GAMMA_APPROX);
1774+
assert_approx_eq!((5.0 as Float).gamma(), 24.0, Float::GAMMA_APPROX_LOOSE);
1775+
assert_approx_eq!((0.5 as Float).gamma(), Float::PI.sqrt(), Float::GAMMA_APPROX);
1776+
assert_approx_eq!((-0.5 as Float).gamma(), -2.0 * Float::PI.sqrt(), Float::GAMMA_APPROX_LOOSE);
1777+
assert_biteq!((0.0 as Float).gamma(), Float::INFINITY);
1778+
assert_biteq!((-0.0 as Float).gamma(), Float::NEG_INFINITY);
1779+
assert!((-1.0 as Float).gamma().is_nan());
1780+
assert!((-2.0 as Float).gamma().is_nan());
1781+
assert!(Float::NAN.gamma().is_nan());
1782+
assert!(Float::NEG_INFINITY.gamma().is_nan());
1783+
assert_biteq!(Float::INFINITY.gamma(), Float::INFINITY);
1784+
}
1785+
}
1786+
1787+
float_test! {
1788+
name: ln_gamma,
1789+
attrs: {
1790+
const: #[cfg(false)],
1791+
f16: #[cfg(all(not(miri), target_has_reliable_f16_math))],
1792+
f128: #[cfg(all(not(miri), target_has_reliable_f128_math))],
1793+
},
1794+
test<Float> {
1795+
assert_approx_eq!((1.0 as Float).ln_gamma().0, 0.0, Float::LNGAMMA_APPROX);
1796+
assert_eq!((1.0 as Float).ln_gamma().1, 1);
1797+
assert_approx_eq!((2.0 as Float).ln_gamma().0, 0.0, Float::LNGAMMA_APPROX);
1798+
assert_eq!((2.0 as Float).ln_gamma().1, 1);
1799+
assert_approx_eq!((3.0 as Float).ln_gamma().0, (2.0 as Float).ln(), Float::LNGAMMA_APPROX);
1800+
assert_eq!((3.0 as Float).ln_gamma().1, 1);
1801+
assert_approx_eq!((-0.5 as Float).ln_gamma().0, (2.0 as Float * Float::PI.sqrt()).ln(), Float::LNGAMMA_APPROX_LOOSE);
1802+
assert_eq!((-0.5 as Float).ln_gamma().1, -1);
1803+
}
1804+
}
1805+
14681806
float_test! {
14691807
name: to_degrees,
14701808
attrs: {
@@ -1582,3 +1920,4 @@ float_test! {
15821920
assert_biteq!((flt(-3.2)).mul_add(2.4, neg_inf), neg_inf);
15831921
}
15841922
}
1923+

0 commit comments

Comments
 (0)