Skip to content

Commit c281f3c

Browse files
committed
Auto merge of rust-lang#138087 - tgross35:core-float-math, r=<try>
Initial implementation of `core_float_math` Since [1], `compiler-builtins` makes a certain set of math symbols weakly available on all platforms. This means we can begin exposing some of the related functions in `core`, so begin this process here. It is not possible to provide inherent methods in both `core` and `std` while giving them different stability gates, so standalone functions are added instead. This provides a way to experiment with the functionality while unstable; once it is time to stabilize, they can be converted to inherent. For `f16` and `f128`, everything is unstable so we can move the inherent methods. The following are included to start: * floor * ceil * round * round_ties_even * trunc * fract * mul_add * div_euclid * rem_euclid * powi * sqrt * abs_sub * cbrt These mirror the set of functions that we have in `compiler-builtins` since [1], with the exception of `powi` that has been there longer. Details for each of the changes is in the commit messages. Tracking issue: rust-lang#137578 [1]: rust-lang/compiler-builtins#763 try-job: aarch64-apple try-job: aarch64-gnu try-job: arm-android tru-job: armhf-gnu try-job: dist-various-1 try-job: dist-various-2 try-job: i686-msvc-1 try-job: test-various try-job: x86_64-apple-1 try-job: x86_64-msvc-ext2
2 parents 49e5e4e + 377d1ed commit c281f3c

File tree

26 files changed

+4726
-3800
lines changed

26 files changed

+4726
-3800
lines changed

library/core/src/num/f128.rs

+377
Original file line numberDiff line numberDiff line change
@@ -1415,3 +1415,380 @@ impl f128 {
14151415
intrinsics::frem_algebraic(self, rhs)
14161416
}
14171417
}
1418+
1419+
// Functions in this module fall into `core_float_math`
1420+
// FIXME(f16_f128): all doctests must be gated to platforms that have `long double` === `_Float128`
1421+
// due to https://github.com/llvm/llvm-project/issues/44744. aarch64 linux matches this.
1422+
// #[unstable(feature = "core_float_math", issue = "137578")]
1423+
#[cfg(not(test))]
1424+
impl f128 {
1425+
/// Returns the largest integer less than or equal to `self`.
1426+
///
1427+
/// This function always returns the precise result.
1428+
///
1429+
/// # Examples
1430+
///
1431+
/// ```
1432+
/// #![feature(f128)]
1433+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1434+
///
1435+
/// let f = 3.7_f128;
1436+
/// let g = 3.0_f128;
1437+
/// let h = -3.7_f128;
1438+
///
1439+
/// assert_eq!(f.floor(), 3.0);
1440+
/// assert_eq!(g.floor(), 3.0);
1441+
/// assert_eq!(h.floor(), -4.0);
1442+
/// # }
1443+
/// ```
1444+
#[inline]
1445+
#[rustc_allow_incoherent_impl]
1446+
#[unstable(feature = "f128", issue = "116909")]
1447+
#[must_use = "method returns a new number and does not mutate the original value"]
1448+
pub fn floor(self) -> f128 {
1449+
// SAFETY: intrinsic with no preconditions
1450+
unsafe { intrinsics::floorf128(self) }
1451+
}
1452+
1453+
/// Returns the smallest integer greater than or equal to `self`.
1454+
///
1455+
/// This function always returns the precise result.
1456+
///
1457+
/// # Examples
1458+
///
1459+
/// ```
1460+
/// #![feature(f128)]
1461+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1462+
///
1463+
/// let f = 3.01_f128;
1464+
/// let g = 4.0_f128;
1465+
///
1466+
/// assert_eq!(f.ceil(), 4.0);
1467+
/// assert_eq!(g.ceil(), 4.0);
1468+
/// # }
1469+
/// ```
1470+
#[inline]
1471+
#[doc(alias = "ceiling")]
1472+
#[rustc_allow_incoherent_impl]
1473+
#[unstable(feature = "f128", issue = "116909")]
1474+
#[must_use = "method returns a new number and does not mutate the original value"]
1475+
pub fn ceil(self) -> f128 {
1476+
// SAFETY: intrinsic with no preconditions
1477+
unsafe { intrinsics::ceilf128(self) }
1478+
}
1479+
1480+
/// Returns the nearest integer to `self`. If a value is half-way between two
1481+
/// integers, round away from `0.0`.
1482+
///
1483+
/// This function always returns the precise result.
1484+
///
1485+
/// # Examples
1486+
///
1487+
/// ```
1488+
/// #![feature(f128)]
1489+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1490+
///
1491+
/// let f = 3.3_f128;
1492+
/// let g = -3.3_f128;
1493+
/// let h = -3.7_f128;
1494+
/// let i = 3.5_f128;
1495+
/// let j = 4.5_f128;
1496+
///
1497+
/// assert_eq!(f.round(), 3.0);
1498+
/// assert_eq!(g.round(), -3.0);
1499+
/// assert_eq!(h.round(), -4.0);
1500+
/// assert_eq!(i.round(), 4.0);
1501+
/// assert_eq!(j.round(), 5.0);
1502+
/// # }
1503+
/// ```
1504+
#[inline]
1505+
#[rustc_allow_incoherent_impl]
1506+
#[unstable(feature = "f128", issue = "116909")]
1507+
#[must_use = "method returns a new number and does not mutate the original value"]
1508+
pub fn round(self) -> f128 {
1509+
// SAFETY: intrinsic with no preconditions
1510+
unsafe { intrinsics::roundf128(self) }
1511+
}
1512+
1513+
/// Returns the nearest integer to a number. Rounds half-way cases to the number
1514+
/// with an even least significant digit.
1515+
///
1516+
/// This function always returns the precise result.
1517+
///
1518+
/// # Examples
1519+
///
1520+
/// ```
1521+
/// #![feature(f128)]
1522+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1523+
///
1524+
/// let f = 3.3_f128;
1525+
/// let g = -3.3_f128;
1526+
/// let h = 3.5_f128;
1527+
/// let i = 4.5_f128;
1528+
///
1529+
/// assert_eq!(f.round_ties_even(), 3.0);
1530+
/// assert_eq!(g.round_ties_even(), -3.0);
1531+
/// assert_eq!(h.round_ties_even(), 4.0);
1532+
/// assert_eq!(i.round_ties_even(), 4.0);
1533+
/// # }
1534+
/// ```
1535+
#[inline]
1536+
#[rustc_allow_incoherent_impl]
1537+
#[unstable(feature = "f128", issue = "116909")]
1538+
#[must_use = "method returns a new number and does not mutate the original value"]
1539+
pub fn round_ties_even(self) -> f128 {
1540+
intrinsics::round_ties_even_f128(self)
1541+
}
1542+
1543+
/// Returns the integer part of `self`.
1544+
/// This means that non-integer numbers are always truncated towards zero.
1545+
///
1546+
/// This function always returns the precise result.
1547+
///
1548+
/// # Examples
1549+
///
1550+
/// ```
1551+
/// #![feature(f128)]
1552+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1553+
///
1554+
/// let f = 3.7_f128;
1555+
/// let g = 3.0_f128;
1556+
/// let h = -3.7_f128;
1557+
///
1558+
/// assert_eq!(f.trunc(), 3.0);
1559+
/// assert_eq!(g.trunc(), 3.0);
1560+
/// assert_eq!(h.trunc(), -3.0);
1561+
/// # }
1562+
/// ```
1563+
#[inline]
1564+
#[doc(alias = "truncate")]
1565+
#[rustc_allow_incoherent_impl]
1566+
#[unstable(feature = "f128", issue = "116909")]
1567+
#[must_use = "method returns a new number and does not mutate the original value"]
1568+
pub fn trunc(self) -> f128 {
1569+
// SAFETY: intrinsic with no preconditions
1570+
unsafe { intrinsics::truncf128(self) }
1571+
}
1572+
1573+
/// Returns the fractional part of `self`.
1574+
///
1575+
/// This function always returns the precise result.
1576+
///
1577+
/// # Examples
1578+
///
1579+
/// ```
1580+
/// #![feature(f128)]
1581+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1582+
///
1583+
/// let x = 3.6_f128;
1584+
/// let y = -3.6_f128;
1585+
/// let abs_difference_x = (x.fract() - 0.6).abs();
1586+
/// let abs_difference_y = (y.fract() - (-0.6)).abs();
1587+
///
1588+
/// assert!(abs_difference_x <= f128::EPSILON);
1589+
/// assert!(abs_difference_y <= f128::EPSILON);
1590+
/// # }
1591+
/// ```
1592+
#[inline]
1593+
#[rustc_allow_incoherent_impl]
1594+
#[unstable(feature = "f128", issue = "116909")]
1595+
#[must_use = "method returns a new number and does not mutate the original value"]
1596+
pub fn fract(self) -> f128 {
1597+
self - self.trunc()
1598+
}
1599+
1600+
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
1601+
/// error, yielding a more accurate result than an unfused multiply-add.
1602+
///
1603+
/// Using `mul_add` *may* be more performant than an unfused multiply-add if
1604+
/// the target architecture has a dedicated `fma` CPU instruction. However,
1605+
/// this is not always true, and will be heavily dependant on designing
1606+
/// algorithms with specific target hardware in mind.
1607+
///
1608+
/// # Precision
1609+
///
1610+
/// The result of this operation is guaranteed to be the rounded
1611+
/// infinite-precision result. It is specified by IEEE 754 as
1612+
/// `fusedMultiplyAdd` and guaranteed not to change.
1613+
///
1614+
/// # Examples
1615+
///
1616+
/// ```
1617+
/// #![feature(f128)]
1618+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1619+
///
1620+
/// let m = 10.0_f128;
1621+
/// let x = 4.0_f128;
1622+
/// let b = 60.0_f128;
1623+
///
1624+
/// assert_eq!(m.mul_add(x, b), 100.0);
1625+
/// assert_eq!(m * x + b, 100.0);
1626+
///
1627+
/// let one_plus_eps = 1.0_f128 + f128::EPSILON;
1628+
/// let one_minus_eps = 1.0_f128 - f128::EPSILON;
1629+
/// let minus_one = -1.0_f128;
1630+
///
1631+
/// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
1632+
/// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON);
1633+
/// // Different rounding with the non-fused multiply and add.
1634+
/// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
1635+
/// # }
1636+
/// ```
1637+
#[inline]
1638+
#[rustc_allow_incoherent_impl]
1639+
#[doc(alias = "fmaf128", alias = "fusedMultiplyAdd")]
1640+
#[unstable(feature = "f128", issue = "116909")]
1641+
#[must_use = "method returns a new number and does not mutate the original value"]
1642+
pub fn mul_add(self, a: f128, b: f128) -> f128 {
1643+
// SAFETY: intrinsic with no preconditions
1644+
unsafe { intrinsics::fmaf128(self, a, b) }
1645+
}
1646+
1647+
/// Calculates Euclidean division, the matching method for `rem_euclid`.
1648+
///
1649+
/// This computes the integer `n` such that
1650+
/// `self = n * rhs + self.rem_euclid(rhs)`.
1651+
/// In other words, the result is `self / rhs` rounded to the integer `n`
1652+
/// such that `self >= n * rhs`.
1653+
///
1654+
/// # Precision
1655+
///
1656+
/// The result of this operation is guaranteed to be the rounded
1657+
/// infinite-precision result.
1658+
///
1659+
/// # Examples
1660+
///
1661+
/// ```
1662+
/// #![feature(f128)]
1663+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1664+
///
1665+
/// let a: f128 = 7.0;
1666+
/// let b = 4.0;
1667+
/// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
1668+
/// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
1669+
/// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
1670+
/// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
1671+
/// # }
1672+
/// ```
1673+
#[inline]
1674+
#[rustc_allow_incoherent_impl]
1675+
#[unstable(feature = "f128", issue = "116909")]
1676+
#[must_use = "method returns a new number and does not mutate the original value"]
1677+
pub fn div_euclid(self, rhs: f128) -> f128 {
1678+
let q = (self / rhs).trunc();
1679+
if self % rhs < 0.0 {
1680+
return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
1681+
}
1682+
q
1683+
}
1684+
1685+
/// Calculates the least nonnegative remainder of `self (mod rhs)`.
1686+
///
1687+
/// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
1688+
/// most cases. However, due to a floating point round-off error it can
1689+
/// result in `r == rhs.abs()`, violating the mathematical definition, if
1690+
/// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
1691+
/// This result is not an element of the function's codomain, but it is the
1692+
/// closest floating point number in the real numbers and thus fulfills the
1693+
/// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
1694+
/// approximately.
1695+
///
1696+
/// # Precision
1697+
///
1698+
/// The result of this operation is guaranteed to be the rounded
1699+
/// infinite-precision result.
1700+
///
1701+
/// # Examples
1702+
///
1703+
/// ```
1704+
/// #![feature(f128)]
1705+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1706+
///
1707+
/// let a: f128 = 7.0;
1708+
/// let b = 4.0;
1709+
/// assert_eq!(a.rem_euclid(b), 3.0);
1710+
/// assert_eq!((-a).rem_euclid(b), 1.0);
1711+
/// assert_eq!(a.rem_euclid(-b), 3.0);
1712+
/// assert_eq!((-a).rem_euclid(-b), 1.0);
1713+
/// // limitation due to round-off error
1714+
/// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0);
1715+
/// # }
1716+
/// ```
1717+
#[inline]
1718+
#[rustc_allow_incoherent_impl]
1719+
#[doc(alias = "modulo", alias = "mod")]
1720+
#[unstable(feature = "f128", issue = "116909")]
1721+
#[must_use = "method returns a new number and does not mutate the original value"]
1722+
pub fn rem_euclid(self, rhs: f128) -> f128 {
1723+
let r = self % rhs;
1724+
if r < 0.0 { r + rhs.abs() } else { r }
1725+
}
1726+
1727+
/// Raises a number to an integer power.
1728+
///
1729+
/// Using this function is generally faster than using `powf`.
1730+
/// It might have a different sequence of rounding operations than `powf`,
1731+
/// so the results are not guaranteed to agree.
1732+
///
1733+
/// # Unspecified precision
1734+
///
1735+
/// The precision of this function is non-deterministic. This means it varies by platform,
1736+
/// Rust version, and can even differ within the same execution from one invocation to the next.
1737+
///
1738+
/// # Examples
1739+
///
1740+
/// ```
1741+
/// #![feature(f128)]
1742+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1743+
///
1744+
/// let x = 2.0_f128;
1745+
/// let abs_difference = (x.powi(2) - (x * x)).abs();
1746+
/// assert!(abs_difference <= f128::EPSILON);
1747+
///
1748+
/// assert_eq!(f128::powi(f128::NAN, 0), 1.0);
1749+
/// # }
1750+
/// ```
1751+
#[inline]
1752+
#[rustc_allow_incoherent_impl]
1753+
#[unstable(feature = "f128", issue = "116909")]
1754+
#[must_use = "method returns a new number and does not mutate the original value"]
1755+
pub fn powi(self, n: i32) -> f128 {
1756+
// SAFETY: intrinsic with no preconditions
1757+
unsafe { intrinsics::powif128(self, n) }
1758+
}
1759+
1760+
/// Returns the square root of a number.
1761+
///
1762+
/// Returns NaN if `self` is a negative number other than `-0.0`.
1763+
///
1764+
/// # Precision
1765+
///
1766+
/// The result of this operation is guaranteed to be the rounded
1767+
/// infinite-precision result. It is specified by IEEE 754 as `squareRoot`
1768+
/// and guaranteed not to change.
1769+
///
1770+
/// # Examples
1771+
///
1772+
/// ```
1773+
/// #![feature(f128)]
1774+
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
1775+
///
1776+
/// let positive = 4.0_f128;
1777+
/// let negative = -4.0_f128;
1778+
/// let negative_zero = -0.0_f128;
1779+
///
1780+
/// assert_eq!(positive.sqrt(), 2.0);
1781+
/// assert!(negative.sqrt().is_nan());
1782+
/// assert!(negative_zero.sqrt() == negative_zero);
1783+
/// # }
1784+
/// ```
1785+
#[inline]
1786+
#[doc(alias = "squareRoot")]
1787+
#[rustc_allow_incoherent_impl]
1788+
#[unstable(feature = "f128", issue = "116909")]
1789+
#[must_use = "method returns a new number and does not mutate the original value"]
1790+
pub fn sqrt(self) -> f128 {
1791+
// SAFETY: intrinsic with no preconditions
1792+
unsafe { intrinsics::sqrtf128(self) }
1793+
}
1794+
}

0 commit comments

Comments
 (0)