Skip to content

Commit dbe4c37

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 inerent 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. [1]: rust-lang/compiler-builtins#763
1 parent 7d8c6e7 commit dbe4c37

File tree

12 files changed

+1748
-800
lines changed

12 files changed

+1748
-800
lines changed

library/core/src/num/f128.rs

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

0 commit comments

Comments
 (0)