Skip to content

Commit 832de1f

Browse files
committed
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]. Tracking issue: rust-lang#137578 [1]: rust-lang/compiler-builtins#763
1 parent f820b75 commit 832de1f

File tree

12 files changed

+1642
-800
lines changed

12 files changed

+1642
-800
lines changed

library/core/src/num/f128.rs

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

0 commit comments

Comments
 (0)