authorbors <bors@rust-lang.org> 2024-08-07 06:01:57 UTC
committerbors <bors@rust-lang.org> 2024-08-07 06:01:57 UTC
log6a2cd0d50c9b7e1243d948641758c76d1f22e25e
tree923d47c919f664b72637c9aabf2ece3c97ac6895
parent2f3dc46465c04d10cb74d34b1bd80c3ebfdc05bf
parent701bc03c52fd411f1b7f86072903602ad92a45e7

Auto merge of #128768 - tgross35:rollup-aaq1ny7, r=tgross35

Rollup of 7 pull requests Successful merges: - #128107 (Migrate `raw-dylib-alt-calling-convention`, `raw-dylib-c` and `redundant-libs` `run-make` tests to rmake) - #128362 (add test for symbol visibility of `#[naked]` functions) - #128417 (Add `f16` and `f128` math functions) - #128638 (run-make: enable msvc for `link-dedup`) - #128647 (Enable msvc for link-args-order) - #128649 (run-make: Enable msvc for `no-duplicate-libs` and `zero-extend-abi-param-passing`) - #128766 (Trivial grammar fix in const keyword docs) r? `@ghost` `@rustbot` modify labels: rollup

34 files changed, 4514 insertions(+), 226 deletions(-)

compiler/rustc_codegen_llvm/src/context.rs+4-4
......@@ -775,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> {
775775 ifn!("llvm.debugtrap", fn() -> void);
776776 ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
777777
778 ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16);
779 ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
780 ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
781 ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128);
778 ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16);
779 ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32);
780 ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64);
781 ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128);
782782
783783 ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
784784 ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
compiler/rustc_codegen_llvm/src/intrinsic.rs+4-4
......@@ -35,10 +35,10 @@ fn get_simple_intrinsic<'ll>(
3535 sym::sqrtf64 => "llvm.sqrt.f64",
3636 sym::sqrtf128 => "llvm.sqrt.f128",
3737
38 sym::powif16 => "llvm.powi.f16",
39 sym::powif32 => "llvm.powi.f32",
40 sym::powif64 => "llvm.powi.f64",
41 sym::powif128 => "llvm.powi.f128",
38 sym::powif16 => "llvm.powi.f16.i32",
39 sym::powif32 => "llvm.powi.f32.i32",
40 sym::powif64 => "llvm.powi.f64.i32",
41 sym::powif128 => "llvm.powi.f128.i32",
4242
4343 sym::sinf16 => "llvm.sin.f16",
4444 sym::sinf32 => "llvm.sin.f32",
library/core/src/intrinsics.rs+289
......@@ -1528,6 +1528,12 @@ extern "rust-intrinsic" {
15281528 #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"]
15291529 pub fn unaligned_volatile_store<T>(dst: *mut T, val: T);
15301530
1531 /// Returns the square root of an `f16`
1532 ///
1533 /// The stabilized version of this intrinsic is
1534 /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt)
1535 #[rustc_nounwind]
1536 pub fn sqrtf16(x: f16) -> f16;
15311537 /// Returns the square root of an `f32`
15321538 ///
15331539 /// The stabilized version of this intrinsic is
......@@ -1540,6 +1546,12 @@ extern "rust-intrinsic" {
15401546 /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt)
15411547 #[rustc_nounwind]
15421548 pub fn sqrtf64(x: f64) -> f64;
1549 /// Returns the square root of an `f128`
1550 ///
1551 /// The stabilized version of this intrinsic is
1552 /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt)
1553 #[rustc_nounwind]
1554 pub fn sqrtf128(x: f128) -> f128;
15431555
15441556 /// Raises an `f16` to an integer power.
15451557 ///
......@@ -1566,6 +1578,12 @@ extern "rust-intrinsic" {
15661578 #[rustc_nounwind]
15671579 pub fn powif128(a: f128, x: i32) -> f128;
15681580
1581 /// Returns the sine of an `f16`.
1582 ///
1583 /// The stabilized version of this intrinsic is
1584 /// [`f16::sin`](../../std/primitive.f16.html#method.sin)
1585 #[rustc_nounwind]
1586 pub fn sinf16(x: f16) -> f16;
15691587 /// Returns the sine of an `f32`.
15701588 ///
15711589 /// The stabilized version of this intrinsic is
......@@ -1578,7 +1596,19 @@ extern "rust-intrinsic" {
15781596 /// [`f64::sin`](../../std/primitive.f64.html#method.sin)
15791597 #[rustc_nounwind]
15801598 pub fn sinf64(x: f64) -> f64;
1599 /// Returns the sine of an `f128`.
1600 ///
1601 /// The stabilized version of this intrinsic is
1602 /// [`f128::sin`](../../std/primitive.f128.html#method.sin)
1603 #[rustc_nounwind]
1604 pub fn sinf128(x: f128) -> f128;
15811605
1606 /// Returns the cosine of an `f16`.
1607 ///
1608 /// The stabilized version of this intrinsic is
1609 /// [`f16::cos`](../../std/primitive.f16.html#method.cos)
1610 #[rustc_nounwind]
1611 pub fn cosf16(x: f16) -> f16;
15821612 /// Returns the cosine of an `f32`.
15831613 ///
15841614 /// The stabilized version of this intrinsic is
......@@ -1591,7 +1621,19 @@ extern "rust-intrinsic" {
15911621 /// [`f64::cos`](../../std/primitive.f64.html#method.cos)
15921622 #[rustc_nounwind]
15931623 pub fn cosf64(x: f64) -> f64;
1624 /// Returns the cosine of an `f128`.
1625 ///
1626 /// The stabilized version of this intrinsic is
1627 /// [`f128::cos`](../../std/primitive.f128.html#method.cos)
1628 #[rustc_nounwind]
1629 pub fn cosf128(x: f128) -> f128;
15941630
1631 /// Raises an `f16` to an `f16` power.
1632 ///
1633 /// The stabilized version of this intrinsic is
1634 /// [`f16::powf`](../../std/primitive.f16.html#method.powf)
1635 #[rustc_nounwind]
1636 pub fn powf16(a: f16, x: f16) -> f16;
15951637 /// Raises an `f32` to an `f32` power.
15961638 ///
15971639 /// The stabilized version of this intrinsic is
......@@ -1604,7 +1646,19 @@ extern "rust-intrinsic" {
16041646 /// [`f64::powf`](../../std/primitive.f64.html#method.powf)
16051647 #[rustc_nounwind]
16061648 pub fn powf64(a: f64, x: f64) -> f64;
1649 /// Raises an `f128` to an `f128` power.
1650 ///
1651 /// The stabilized version of this intrinsic is
1652 /// [`f128::powf`](../../std/primitive.f128.html#method.powf)
1653 #[rustc_nounwind]
1654 pub fn powf128(a: f128, x: f128) -> f128;
16071655
1656 /// Returns the exponential of an `f16`.
1657 ///
1658 /// The stabilized version of this intrinsic is
1659 /// [`f16::exp`](../../std/primitive.f16.html#method.exp)
1660 #[rustc_nounwind]
1661 pub fn expf16(x: f16) -> f16;
16081662 /// Returns the exponential of an `f32`.
16091663 ///
16101664 /// The stabilized version of this intrinsic is
......@@ -1617,7 +1671,19 @@ extern "rust-intrinsic" {
16171671 /// [`f64::exp`](../../std/primitive.f64.html#method.exp)
16181672 #[rustc_nounwind]
16191673 pub fn expf64(x: f64) -> f64;
1674 /// Returns the exponential of an `f128`.
1675 ///
1676 /// The stabilized version of this intrinsic is
1677 /// [`f128::exp`](../../std/primitive.f128.html#method.exp)
1678 #[rustc_nounwind]
1679 pub fn expf128(x: f128) -> f128;
16201680
1681 /// Returns 2 raised to the power of an `f16`.
1682 ///
1683 /// The stabilized version of this intrinsic is
1684 /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2)
1685 #[rustc_nounwind]
1686 pub fn exp2f16(x: f16) -> f16;
16211687 /// Returns 2 raised to the power of an `f32`.
16221688 ///
16231689 /// The stabilized version of this intrinsic is
......@@ -1630,7 +1696,19 @@ extern "rust-intrinsic" {
16301696 /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2)
16311697 #[rustc_nounwind]
16321698 pub fn exp2f64(x: f64) -> f64;
1699 /// Returns 2 raised to the power of an `f128`.
1700 ///
1701 /// The stabilized version of this intrinsic is
1702 /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2)
1703 #[rustc_nounwind]
1704 pub fn exp2f128(x: f128) -> f128;
16331705
1706 /// Returns the natural logarithm of an `f16`.
1707 ///
1708 /// The stabilized version of this intrinsic is
1709 /// [`f16::ln`](../../std/primitive.f16.html#method.ln)
1710 #[rustc_nounwind]
1711 pub fn logf16(x: f16) -> f16;
16341712 /// Returns the natural logarithm of an `f32`.
16351713 ///
16361714 /// The stabilized version of this intrinsic is
......@@ -1643,7 +1721,19 @@ extern "rust-intrinsic" {
16431721 /// [`f64::ln`](../../std/primitive.f64.html#method.ln)
16441722 #[rustc_nounwind]
16451723 pub fn logf64(x: f64) -> f64;
1724 /// Returns the natural logarithm of an `f128`.
1725 ///
1726 /// The stabilized version of this intrinsic is
1727 /// [`f128::ln`](../../std/primitive.f128.html#method.ln)
1728 #[rustc_nounwind]
1729 pub fn logf128(x: f128) -> f128;
16461730
1731 /// Returns the base 10 logarithm of an `f16`.
1732 ///
1733 /// The stabilized version of this intrinsic is
1734 /// [`f16::log10`](../../std/primitive.f16.html#method.log10)
1735 #[rustc_nounwind]
1736 pub fn log10f16(x: f16) -> f16;
16471737 /// Returns the base 10 logarithm of an `f32`.
16481738 ///
16491739 /// The stabilized version of this intrinsic is
......@@ -1656,7 +1746,19 @@ extern "rust-intrinsic" {
16561746 /// [`f64::log10`](../../std/primitive.f64.html#method.log10)
16571747 #[rustc_nounwind]
16581748 pub fn log10f64(x: f64) -> f64;
1749 /// Returns the base 10 logarithm of an `f128`.
1750 ///
1751 /// The stabilized version of this intrinsic is
1752 /// [`f128::log10`](../../std/primitive.f128.html#method.log10)
1753 #[rustc_nounwind]
1754 pub fn log10f128(x: f128) -> f128;
16591755
1756 /// Returns the base 2 logarithm of an `f16`.
1757 ///
1758 /// The stabilized version of this intrinsic is
1759 /// [`f16::log2`](../../std/primitive.f16.html#method.log2)
1760 #[rustc_nounwind]
1761 pub fn log2f16(x: f16) -> f16;
16601762 /// Returns the base 2 logarithm of an `f32`.
16611763 ///
16621764 /// The stabilized version of this intrinsic is
......@@ -1669,7 +1771,19 @@ extern "rust-intrinsic" {
16691771 /// [`f64::log2`](../../std/primitive.f64.html#method.log2)
16701772 #[rustc_nounwind]
16711773 pub fn log2f64(x: f64) -> f64;
1774 /// Returns the base 2 logarithm of an `f128`.
1775 ///
1776 /// The stabilized version of this intrinsic is
1777 /// [`f128::log2`](../../std/primitive.f128.html#method.log2)
1778 #[rustc_nounwind]
1779 pub fn log2f128(x: f128) -> f128;
16721780
1781 /// Returns `a * b + c` for `f16` values.
1782 ///
1783 /// The stabilized version of this intrinsic is
1784 /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add)
1785 #[rustc_nounwind]
1786 pub fn fmaf16(a: f16, b: f16, c: f16) -> f16;
16731787 /// Returns `a * b + c` for `f32` values.
16741788 ///
16751789 /// The stabilized version of this intrinsic is
......@@ -1682,7 +1796,19 @@ extern "rust-intrinsic" {
16821796 /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add)
16831797 #[rustc_nounwind]
16841798 pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;
1799 /// Returns `a * b + c` for `f128` values.
1800 ///
1801 /// The stabilized version of this intrinsic is
1802 /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add)
1803 #[rustc_nounwind]
1804 pub fn fmaf128(a: f128, b: f128, c: f128) -> f128;
16851805
1806 /// Returns the absolute value of an `f16`.
1807 ///
1808 /// The stabilized version of this intrinsic is
1809 /// [`f16::abs`](../../std/primitive.f16.html#method.abs)
1810 #[rustc_nounwind]
1811 pub fn fabsf16(x: f16) -> f16;
16861812 /// Returns the absolute value of an `f32`.
16871813 ///
16881814 /// The stabilized version of this intrinsic is
......@@ -1695,7 +1821,25 @@ extern "rust-intrinsic" {
16951821 /// [`f64::abs`](../../std/primitive.f64.html#method.abs)
16961822 #[rustc_nounwind]
16971823 pub fn fabsf64(x: f64) -> f64;
1824 /// Returns the absolute value of an `f128`.
1825 ///
1826 /// The stabilized version of this intrinsic is
1827 /// [`f128::abs`](../../std/primitive.f128.html#method.abs)
1828 #[rustc_nounwind]
1829 pub fn fabsf128(x: f128) -> f128;
16981830
1831 /// Returns the minimum of two `f16` values.
1832 ///
1833 /// Note that, unlike most intrinsics, this is safe to call;
1834 /// it does not require an `unsafe` block.
1835 /// Therefore, implementations must not require the user to uphold
1836 /// any safety invariants.
1837 ///
1838 /// The stabilized version of this intrinsic is
1839 /// [`f16::min`]
1840 #[rustc_safe_intrinsic]
1841 #[rustc_nounwind]
1842 pub fn minnumf16(x: f16, y: f16) -> f16;
16991843 /// Returns the minimum of two `f32` values.
17001844 ///
17011845 /// Note that, unlike most intrinsics, this is safe to call;
......@@ -1720,6 +1864,31 @@ extern "rust-intrinsic" {
17201864 #[rustc_safe_intrinsic]
17211865 #[rustc_nounwind]
17221866 pub fn minnumf64(x: f64, y: f64) -> f64;
1867 /// Returns the minimum of two `f128` values.
1868 ///
1869 /// Note that, unlike most intrinsics, this is safe to call;
1870 /// it does not require an `unsafe` block.
1871 /// Therefore, implementations must not require the user to uphold
1872 /// any safety invariants.
1873 ///
1874 /// The stabilized version of this intrinsic is
1875 /// [`f128::min`]
1876 #[rustc_safe_intrinsic]
1877 #[rustc_nounwind]
1878 pub fn minnumf128(x: f128, y: f128) -> f128;
1879
1880 /// Returns the maximum of two `f16` values.
1881 ///
1882 /// Note that, unlike most intrinsics, this is safe to call;
1883 /// it does not require an `unsafe` block.
1884 /// Therefore, implementations must not require the user to uphold
1885 /// any safety invariants.
1886 ///
1887 /// The stabilized version of this intrinsic is
1888 /// [`f16::max`]
1889 #[rustc_safe_intrinsic]
1890 #[rustc_nounwind]
1891 pub fn maxnumf16(x: f16, y: f16) -> f16;
17231892 /// Returns the maximum of two `f32` values.
17241893 ///
17251894 /// Note that, unlike most intrinsics, this is safe to call;
......@@ -1744,7 +1913,25 @@ extern "rust-intrinsic" {
17441913 #[rustc_safe_intrinsic]
17451914 #[rustc_nounwind]
17461915 pub fn maxnumf64(x: f64, y: f64) -> f64;
1916 /// Returns the maximum of two `f128` values.
1917 ///
1918 /// Note that, unlike most intrinsics, this is safe to call;
1919 /// it does not require an `unsafe` block.
1920 /// Therefore, implementations must not require the user to uphold
1921 /// any safety invariants.
1922 ///
1923 /// The stabilized version of this intrinsic is
1924 /// [`f128::max`]
1925 #[rustc_safe_intrinsic]
1926 #[rustc_nounwind]
1927 pub fn maxnumf128(x: f128, y: f128) -> f128;
17471928
1929 /// Copies the sign from `y` to `x` for `f16` values.
1930 ///
1931 /// The stabilized version of this intrinsic is
1932 /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
1933 #[rustc_nounwind]
1934 pub fn copysignf16(x: f16, y: f16) -> f16;
17481935 /// Copies the sign from `y` to `x` for `f32` values.
17491936 ///
17501937 /// The stabilized version of this intrinsic is
......@@ -1757,7 +1944,19 @@ extern "rust-intrinsic" {
17571944 /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign)
17581945 #[rustc_nounwind]
17591946 pub fn copysignf64(x: f64, y: f64) -> f64;
1947 /// Copies the sign from `y` to `x` for `f128` values.
1948 ///
1949 /// The stabilized version of this intrinsic is
1950 /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
1951 #[rustc_nounwind]
1952 pub fn copysignf128(x: f128, y: f128) -> f128;
17601953
1954 /// Returns the largest integer less than or equal to an `f16`.
1955 ///
1956 /// The stabilized version of this intrinsic is
1957 /// [`f16::floor`](../../std/primitive.f16.html#method.floor)
1958 #[rustc_nounwind]
1959 pub fn floorf16(x: f16) -> f16;
17611960 /// Returns the largest integer less than or equal to an `f32`.
17621961 ///
17631962 /// The stabilized version of this intrinsic is
......@@ -1770,7 +1969,19 @@ extern "rust-intrinsic" {
17701969 /// [`f64::floor`](../../std/primitive.f64.html#method.floor)
17711970 #[rustc_nounwind]
17721971 pub fn floorf64(x: f64) -> f64;
1972 /// Returns the largest integer less than or equal to an `f128`.
1973 ///
1974 /// The stabilized version of this intrinsic is
1975 /// [`f128::floor`](../../std/primitive.f128.html#method.floor)
1976 #[rustc_nounwind]
1977 pub fn floorf128(x: f128) -> f128;
17731978
1979 /// Returns the smallest integer greater than or equal to an `f16`.
1980 ///
1981 /// The stabilized version of this intrinsic is
1982 /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil)
1983 #[rustc_nounwind]
1984 pub fn ceilf16(x: f16) -> f16;
17741985 /// Returns the smallest integer greater than or equal to an `f32`.
17751986 ///
17761987 /// The stabilized version of this intrinsic is
......@@ -1783,7 +1994,19 @@ extern "rust-intrinsic" {
17831994 /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil)
17841995 #[rustc_nounwind]
17851996 pub fn ceilf64(x: f64) -> f64;
1997 /// Returns the smallest integer greater than or equal to an `f128`.
1998 ///
1999 /// The stabilized version of this intrinsic is
2000 /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil)
2001 #[rustc_nounwind]
2002 pub fn ceilf128(x: f128) -> f128;
17862003
2004 /// Returns the integer part of an `f16`.
2005 ///
2006 /// The stabilized version of this intrinsic is
2007 /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc)
2008 #[rustc_nounwind]
2009 pub fn truncf16(x: f16) -> f16;
17872010 /// Returns the integer part of an `f32`.
17882011 ///
17892012 /// The stabilized version of this intrinsic is
......@@ -1796,7 +2019,25 @@ extern "rust-intrinsic" {
17962019 /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc)
17972020 #[rustc_nounwind]
17982021 pub fn truncf64(x: f64) -> f64;
2022 /// Returns the integer part of an `f128`.
2023 ///
2024 /// The stabilized version of this intrinsic is
2025 /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc)
2026 #[rustc_nounwind]
2027 pub fn truncf128(x: f128) -> f128;
17992028
2029 /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust,
2030 /// so this rounds half-way cases to the number with an even least significant digit.
2031 ///
2032 /// May raise an inexact floating-point exception if the argument is not an integer.
2033 /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions
2034 /// cannot actually be utilized from Rust code.
2035 /// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`.
2036 ///
2037 /// The stabilized version of this intrinsic is
2038 /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even)
2039 #[rustc_nounwind]
2040 pub fn rintf16(x: f16) -> f16;
18002041 /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust,
18012042 /// so this rounds half-way cases to the number with an even least significant digit.
18022043 ///
......@@ -1821,7 +2062,25 @@ extern "rust-intrinsic" {
18212062 /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
18222063 #[rustc_nounwind]
18232064 pub fn rintf64(x: f64) -> f64;
2065 /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust,
2066 /// so this rounds half-way cases to the number with an even least significant digit.
2067 ///
2068 /// May raise an inexact floating-point exception if the argument is not an integer.
2069 /// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions
2070 /// cannot actually be utilized from Rust code.
2071 /// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`.
2072 ///
2073 /// The stabilized version of this intrinsic is
2074 /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even)
2075 #[rustc_nounwind]
2076 pub fn rintf128(x: f128) -> f128;
18242077
2078 /// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust,
2079 /// so this rounds half-way cases to the number with an even least significant digit.
2080 ///
2081 /// This intrinsic does not have a stable counterpart.
2082 #[rustc_nounwind]
2083 pub fn nearbyintf16(x: f16) -> f16;
18252084 /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust,
18262085 /// so this rounds half-way cases to the number with an even least significant digit.
18272086 ///
......@@ -1834,7 +2093,19 @@ extern "rust-intrinsic" {
18342093 /// This intrinsic does not have a stable counterpart.
18352094 #[rustc_nounwind]
18362095 pub fn nearbyintf64(x: f64) -> f64;
2096 /// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust,
2097 /// so this rounds half-way cases to the number with an even least significant digit.
2098 ///
2099 /// This intrinsic does not have a stable counterpart.
2100 #[rustc_nounwind]
2101 pub fn nearbyintf128(x: f128) -> f128;
18372102
2103 /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero.
2104 ///
2105 /// The stabilized version of this intrinsic is
2106 /// [`f16::round`](../../std/primitive.f16.html#method.round)
2107 #[rustc_nounwind]
2108 pub fn roundf16(x: f16) -> f16;
18382109 /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero.
18392110 ///
18402111 /// The stabilized version of this intrinsic is
......@@ -1847,7 +2118,19 @@ extern "rust-intrinsic" {
18472118 /// [`f64::round`](../../std/primitive.f64.html#method.round)
18482119 #[rustc_nounwind]
18492120 pub fn roundf64(x: f64) -> f64;
2121 /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero.
2122 ///
2123 /// The stabilized version of this intrinsic is
2124 /// [`f128::round`](../../std/primitive.f128.html#method.round)
2125 #[rustc_nounwind]
2126 pub fn roundf128(x: f128) -> f128;
18502127
2128 /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number
2129 /// with an even least significant digit.
2130 ///
2131 /// This intrinsic does not have a stable counterpart.
2132 #[rustc_nounwind]
2133 pub fn roundevenf16(x: f16) -> f16;
18512134 /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number
18522135 /// with an even least significant digit.
18532136 ///
......@@ -1860,6 +2143,12 @@ extern "rust-intrinsic" {
18602143 /// This intrinsic does not have a stable counterpart.
18612144 #[rustc_nounwind]
18622145 pub fn roundevenf64(x: f64) -> f64;
2146 /// Returns the nearest integer to an `f128`. Rounds half-way cases to the number
2147 /// with an even least significant digit.
2148 ///
2149 /// This intrinsic does not have a stable counterpart.
2150 #[rustc_nounwind]
2151 pub fn roundevenf128(x: f128) -> f128;
18632152
18642153 /// Float addition that allows optimizations based on algebraic rules.
18652154 /// May assume inputs are finite.
library/core/src/num/f128.rs+176
......@@ -686,6 +686,182 @@ impl f128 {
686686 self * RADS_PER_DEG
687687 }
688688
689 /// Returns the maximum of the two numbers, ignoring NaN.
690 ///
691 /// If one of the arguments is NaN, then the other argument is returned.
692 /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
693 /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
694 /// This also matches the behavior of libm’s fmax.
695 ///
696 /// ```
697 /// #![feature(f128)]
698 /// # // Using aarch64 because `reliable_f128_math` is needed
699 /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
700 ///
701 /// let x = 1.0f128;
702 /// let y = 2.0f128;
703 ///
704 /// assert_eq!(x.max(y), y);
705 /// # }
706 /// ```
707 #[inline]
708 #[unstable(feature = "f128", issue = "116909")]
709 #[must_use = "this returns the result of the comparison, without modifying either input"]
710 pub fn max(self, other: f128) -> f128 {
711 intrinsics::maxnumf128(self, other)
712 }
713
714 /// Returns the minimum of the two numbers, ignoring NaN.
715 ///
716 /// If one of the arguments is NaN, then the other argument is returned.
717 /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
718 /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
719 /// This also matches the behavior of libm’s fmin.
720 ///
721 /// ```
722 /// #![feature(f128)]
723 /// # // Using aarch64 because `reliable_f128_math` is needed
724 /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
725 ///
726 /// let x = 1.0f128;
727 /// let y = 2.0f128;
728 ///
729 /// assert_eq!(x.min(y), x);
730 /// # }
731 /// ```
732 #[inline]
733 #[unstable(feature = "f128", issue = "116909")]
734 #[must_use = "this returns the result of the comparison, without modifying either input"]
735 pub fn min(self, other: f128) -> f128 {
736 intrinsics::minnumf128(self, other)
737 }
738
739 /// Returns the maximum of the two numbers, propagating NaN.
740 ///
741 /// This returns NaN when *either* argument is NaN, as opposed to
742 /// [`f128::max`] which only returns NaN when *both* arguments are NaN.
743 ///
744 /// ```
745 /// #![feature(f128)]
746 /// #![feature(float_minimum_maximum)]
747 /// # // Using aarch64 because `reliable_f128_math` is needed
748 /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
749 ///
750 /// let x = 1.0f128;
751 /// let y = 2.0f128;
752 ///
753 /// assert_eq!(x.maximum(y), y);
754 /// assert!(x.maximum(f128::NAN).is_nan());
755 /// # }
756 /// ```
757 ///
758 /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
759 /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
760 /// Note that this follows the semantics specified in IEEE 754-2019.
761 ///
762 /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
763 /// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
764 #[inline]
765 #[unstable(feature = "f128", issue = "116909")]
766 // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
767 #[must_use = "this returns the result of the comparison, without modifying either input"]
768 pub fn maximum(self, other: f128) -> f128 {
769 if self > other {
770 self
771 } else if other > self {
772 other
773 } else if self == other {
774 if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
775 } else {
776 self + other
777 }
778 }
779
780 /// Returns the minimum of the two numbers, propagating NaN.
781 ///
782 /// This returns NaN when *either* argument is NaN, as opposed to
783 /// [`f128::min`] which only returns NaN when *both* arguments are NaN.
784 ///
785 /// ```
786 /// #![feature(f128)]
787 /// #![feature(float_minimum_maximum)]
788 /// # // Using aarch64 because `reliable_f128_math` is needed
789 /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
790 ///
791 /// let x = 1.0f128;
792 /// let y = 2.0f128;
793 ///
794 /// assert_eq!(x.minimum(y), x);
795 /// assert!(x.minimum(f128::NAN).is_nan());
796 /// # }
797 /// ```
798 ///
799 /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
800 /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
801 /// Note that this follows the semantics specified in IEEE 754-2019.
802 ///
803 /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
804 /// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
805 #[inline]
806 #[unstable(feature = "f128", issue = "116909")]
807 // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
808 #[must_use = "this returns the result of the comparison, without modifying either input"]
809 pub fn minimum(self, other: f128) -> f128 {
810 if self < other {
811 self
812 } else if other < self {
813 other
814 } else if self == other {
815 if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
816 } else {
817 // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
818 self + other
819 }
820 }
821
822 /// Calculates the middle point of `self` and `rhs`.
823 ///
824 /// This returns NaN when *either* argument is NaN or if a combination of
825 /// +inf and -inf is provided as arguments.
826 ///
827 /// # Examples
828 ///
829 /// ```
830 /// #![feature(f128)]
831 /// #![feature(num_midpoint)]
832 /// # // Using aarch64 because `reliable_f128_math` is needed
833 /// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
834 ///
835 /// assert_eq!(1f128.midpoint(4.0), 2.5);
836 /// assert_eq!((-5.5f128).midpoint(8.0), 1.25);
837 /// # }
838 /// ```
839 #[inline]
840 #[unstable(feature = "f128", issue = "116909")]
841 // #[unstable(feature = "num_midpoint", issue = "110840")]
842 pub fn midpoint(self, other: f128) -> f128 {
843 const LO: f128 = f128::MIN_POSITIVE * 2.;
844 const HI: f128 = f128::MAX / 2.;
845
846 let (a, b) = (self, other);
847 let abs_a = a.abs_private();
848 let abs_b = b.abs_private();
849
850 if abs_a <= HI && abs_b <= HI {
851 // Overflow is impossible
852 (a + b) / 2.
853 } else if abs_a < LO {
854 // Not safe to halve `a` (would underflow)
855 a + (b / 2.)
856 } else if abs_b < LO {
857 // Not safe to halve `b` (would underflow)
858 (a / 2.) + b
859 } else {
860 // Safe to halve `a` and `b`
861 (a / 2.) + (b / 2.)
862 }
863 }
864
689865 /// Rounds toward zero and converts to any primitive integer type,
690866 /// assuming that the value is finite and fits in that type.
691867 ///
library/core/src/num/f16.rs+171
......@@ -720,6 +720,177 @@ impl f16 {
720720 self * RADS_PER_DEG
721721 }
722722
723 /// Returns the maximum of the two numbers, ignoring NaN.
724 ///
725 /// If one of the arguments is NaN, then the other argument is returned.
726 /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
727 /// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
728 /// This also matches the behavior of libm’s fmax.
729 ///
730 /// ```
731 /// #![feature(f16)]
732 /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
733 ///
734 /// let x = 1.0f16;
735 /// let y = 2.0f16;
736 ///
737 /// assert_eq!(x.max(y), y);
738 /// # }
739 /// ```
740 #[inline]
741 #[unstable(feature = "f16", issue = "116909")]
742 #[must_use = "this returns the result of the comparison, without modifying either input"]
743 pub fn max(self, other: f16) -> f16 {
744 intrinsics::maxnumf16(self, other)
745 }
746
747 /// Returns the minimum of the two numbers, ignoring NaN.
748 ///
749 /// If one of the arguments is NaN, then the other argument is returned.
750 /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
751 /// this function handles all NaNs the same way and avoids minNum's problems with associativity.
752 /// This also matches the behavior of libm’s fmin.
753 ///
754 /// ```
755 /// #![feature(f16)]
756 /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
757 ///
758 /// let x = 1.0f16;
759 /// let y = 2.0f16;
760 ///
761 /// assert_eq!(x.min(y), x);
762 /// # }
763 /// ```
764 #[inline]
765 #[unstable(feature = "f16", issue = "116909")]
766 #[must_use = "this returns the result of the comparison, without modifying either input"]
767 pub fn min(self, other: f16) -> f16 {
768 intrinsics::minnumf16(self, other)
769 }
770
771 /// Returns the maximum of the two numbers, propagating NaN.
772 ///
773 /// This returns NaN when *either* argument is NaN, as opposed to
774 /// [`f16::max`] which only returns NaN when *both* arguments are NaN.
775 ///
776 /// ```
777 /// #![feature(f16)]
778 /// #![feature(float_minimum_maximum)]
779 /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
780 ///
781 /// let x = 1.0f16;
782 /// let y = 2.0f16;
783 ///
784 /// assert_eq!(x.maximum(y), y);
785 /// assert!(x.maximum(f16::NAN).is_nan());
786 /// # }
787 /// ```
788 ///
789 /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
790 /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
791 /// Note that this follows the semantics specified in IEEE 754-2019.
792 ///
793 /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
794 /// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
795 #[inline]
796 #[unstable(feature = "f16", issue = "116909")]
797 // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
798 #[must_use = "this returns the result of the comparison, without modifying either input"]
799 pub fn maximum(self, other: f16) -> f16 {
800 if self > other {
801 self
802 } else if other > self {
803 other
804 } else if self == other {
805 if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
806 } else {
807 self + other
808 }
809 }
810
811 /// Returns the minimum of the two numbers, propagating NaN.
812 ///
813 /// This returns NaN when *either* argument is NaN, as opposed to
814 /// [`f16::min`] which only returns NaN when *both* arguments are NaN.
815 ///
816 /// ```
817 /// #![feature(f16)]
818 /// #![feature(float_minimum_maximum)]
819 /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
820 ///
821 /// let x = 1.0f16;
822 /// let y = 2.0f16;
823 ///
824 /// assert_eq!(x.minimum(y), x);
825 /// assert!(x.minimum(f16::NAN).is_nan());
826 /// # }
827 /// ```
828 ///
829 /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
830 /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
831 /// Note that this follows the semantics specified in IEEE 754-2019.
832 ///
833 /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
834 /// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
835 #[inline]
836 #[unstable(feature = "f16", issue = "116909")]
837 // #[unstable(feature = "float_minimum_maximum", issue = "91079")]
838 #[must_use = "this returns the result of the comparison, without modifying either input"]
839 pub fn minimum(self, other: f16) -> f16 {
840 if self < other {
841 self
842 } else if other < self {
843 other
844 } else if self == other {
845 if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
846 } else {
847 // At least one input is NaN. Use `+` to perform NaN propagation and quieting.
848 self + other
849 }
850 }
851
852 /// Calculates the middle point of `self` and `rhs`.
853 ///
854 /// This returns NaN when *either* argument is NaN or if a combination of
855 /// +inf and -inf is provided as arguments.
856 ///
857 /// # Examples
858 ///
859 /// ```
860 /// #![feature(f16)]
861 /// #![feature(num_midpoint)]
862 /// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
863 ///
864 /// assert_eq!(1f16.midpoint(4.0), 2.5);
865 /// assert_eq!((-5.5f16).midpoint(8.0), 1.25);
866 /// # }
867 /// ```
868 #[inline]
869 #[unstable(feature = "f16", issue = "116909")]
870 // #[unstable(feature = "num_midpoint", issue = "110840")]
871 pub fn midpoint(self, other: f16) -> f16 {
872 const LO: f16 = f16::MIN_POSITIVE * 2.;
873 const HI: f16 = f16::MAX / 2.;
874
875 let (a, b) = (self, other);
876 let abs_a = a.abs_private();
877 let abs_b = b.abs_private();
878
879 if abs_a <= HI && abs_b <= HI {
880 // Overflow is impossible
881 (a + b) / 2.
882 } else if abs_a < LO {
883 // Not safe to halve `a` (would underflow)
884 a + (b / 2.)
885 } else if abs_b < LO {
886 // Not safe to halve `b` (would underflow)
887 (a / 2.) + b
888 } else {
889 // Safe to halve `a` and `b`
890 (a / 2.) + (b / 2.)
891 }
892 }
893
723894 /// Rounds toward zero and converts to any primitive integer type,
724895 /// assuming that the value is finite and fits in that type.
725896 ///
library/core/src/num/f32.rs+3-3
......@@ -1070,13 +1070,13 @@ impl f32 {
10701070 // Overflow is impossible
10711071 (a + b) / 2.
10721072 } else if abs_a < LO {
1073 // Not safe to halve a
1073 // Not safe to halve `a` (would underflow)
10741074 a + (b / 2.)
10751075 } else if abs_b < LO {
1076 // Not safe to halve b
1076 // Not safe to halve `b` (would underflow)
10771077 (a / 2.) + b
10781078 } else {
1079 // Not safe to halve a and b
1079 // Safe to halve `a` and `b`
10801080 (a / 2.) + (b / 2.)
10811081 }
10821082 }
library/core/src/num/f64.rs+3-3
......@@ -1064,13 +1064,13 @@ impl f64 {
10641064 // Overflow is impossible
10651065 (a + b) / 2.
10661066 } else if abs_a < LO {
1067 // Not safe to halve a
1067 // Not safe to halve `a` (would underflow)
10681068 a + (b / 2.)
10691069 } else if abs_b < LO {
1070 // Not safe to halve b
1070 // Not safe to halve `b` (would underflow)
10711071 (a / 2.) + b
10721072 } else {
1073 // Not safe to halve a and b
1073 // Safe to halve `a` and `b`
10741074 (a / 2.) + (b / 2.)
10751075 }
10761076 }
library/core/src/primitive_docs.rs+3
......@@ -1244,6 +1244,9 @@ mod prim_f64 {}
12441244/// actually implement it. For x86-64 and AArch64, ISA support is not even specified,
12451245/// so it will always be a software implementation significantly slower than `f64`.
12461246///
1247/// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On
1248/// x86 in particular, these functions do link but their results are always incorrect._
1249///
12471250/// *[See also the `std::f128::consts` module](crate::f128::consts).*
12481251///
12491252/// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
library/std/build.rs+37
......@@ -85,6 +85,11 @@ fn main() {
8585 println!("cargo:rustc-check-cfg=cfg(reliable_f16)");
8686 println!("cargo:rustc-check-cfg=cfg(reliable_f128)");
8787
88 // This is a step beyond only having the types and basic functions available. Math functions
89 // aren't consistently available or correct.
90 println!("cargo:rustc-check-cfg=cfg(reliable_f16_math)");
91 println!("cargo:rustc-check-cfg=cfg(reliable_f128_math)");
92
8893 let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) {
8994 // Selection failure until recent LLVM <https://github.com/llvm/llvm-project/issues/93894>
9095 // FIXME(llvm19): can probably be removed at the version bump
......@@ -130,10 +135,42 @@ fn main() {
130135 _ => false,
131136 };
132137
138 // These are currently empty, but will fill up as some platforms move from completely
139 // unreliable to reliable basics but unreliable math.
140
141 // LLVM is currenlty adding missing routines, <https://github.com/llvm/llvm-project/issues/93566>
142 let has_reliable_f16_math = has_reliable_f16
143 && match (target_arch.as_str(), target_os.as_str()) {
144 // Currently nothing special. Hooray!
145 // This will change as platforms gain better better support for standard ops but math
146 // lags behind.
147 _ => true,
148 };
149
150 let has_reliable_f128_math = has_reliable_f128
151 && match (target_arch.as_str(), target_os.as_str()) {
152 // LLVM lowers `fp128` math to `long double` symbols even on platforms where
153 // `long double` is not IEEE binary128. See
154 // <https://github.com/llvm/llvm-project/issues/44744>.
155 //
156 // This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
157 // (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
158 // (ld is 80-bit extended precision).
159 ("x86_64", _) => false,
160 (_, "linux") if target_pointer_width == 64 => true,
161 _ => false,
162 };
163
133164 if has_reliable_f16 {
134165 println!("cargo:rustc-cfg=reliable_f16");
135166 }
136167 if has_reliable_f128 {
137168 println!("cargo:rustc-cfg=reliable_f128");
138169 }
170 if has_reliable_f16_math {
171 println!("cargo:rustc-cfg=reliable_f16_math");
172 }
173 if has_reliable_f128_math {
174 println!("cargo:rustc-cfg=reliable_f128_math");
175 }
139176}
library/std/src/f128.rs+1290-10
......@@ -12,25 +12,180 @@ pub use core::f128::consts;
1212
1313#[cfg(not(test))]
1414use crate::intrinsics;
15#[cfg(not(test))]
16use crate::sys::cmath;
1517
1618#[cfg(not(test))]
1719impl f128 {
18 /// Raises a number to an integer power.
20 /// Returns the largest integer less than or equal to `self`.
1921 ///
20 /// Using this function is generally faster than using `powf`.
21 /// It might have a different sequence of rounding operations than `powf`,
22 /// so the results are not guaranteed to agree.
22 /// This function always returns the precise result.
2323 ///
24 /// # Unspecified precision
24 /// # Examples
2525 ///
26 /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
27 /// can even differ within the same execution from one invocation to the next.
26 /// ```
27 /// #![feature(f128)]
28 /// # #[cfg(reliable_f128_math)] {
29 ///
30 /// let f = 3.7_f128;
31 /// let g = 3.0_f128;
32 /// let h = -3.7_f128;
33 ///
34 /// assert_eq!(f.floor(), 3.0);
35 /// assert_eq!(g.floor(), 3.0);
36 /// assert_eq!(h.floor(), -4.0);
37 /// # }
38 /// ```
2839 #[inline]
2940 #[rustc_allow_incoherent_impl]
3041 #[unstable(feature = "f128", issue = "116909")]
3142 #[must_use = "method returns a new number and does not mutate the original value"]
32 pub fn powi(self, n: i32) -> f128 {
33 unsafe { intrinsics::powif128(self, n) }
43 pub fn floor(self) -> f128 {
44 unsafe { intrinsics::floorf128(self) }
45 }
46
47 /// Returns the smallest integer greater than or equal to `self`.
48 ///
49 /// This function always returns the precise result.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// #![feature(f128)]
55 /// # #[cfg(reliable_f128_math)] {
56 ///
57 /// let f = 3.01_f128;
58 /// let g = 4.0_f128;
59 ///
60 /// assert_eq!(f.ceil(), 4.0);
61 /// assert_eq!(g.ceil(), 4.0);
62 /// # }
63 /// ```
64 #[inline]
65 #[doc(alias = "ceiling")]
66 #[rustc_allow_incoherent_impl]
67 #[unstable(feature = "f128", issue = "116909")]
68 #[must_use = "method returns a new number and does not mutate the original value"]
69 pub fn ceil(self) -> f128 {
70 unsafe { intrinsics::ceilf128(self) }
71 }
72
73 /// Returns the nearest integer to `self`. If a value is half-way between two
74 /// integers, round away from `0.0`.
75 ///
76 /// This function always returns the precise result.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// #![feature(f128)]
82 /// # #[cfg(reliable_f128_math)] {
83 ///
84 /// let f = 3.3_f128;
85 /// let g = -3.3_f128;
86 /// let h = -3.7_f128;
87 /// let i = 3.5_f128;
88 /// let j = 4.5_f128;
89 ///
90 /// assert_eq!(f.round(), 3.0);
91 /// assert_eq!(g.round(), -3.0);
92 /// assert_eq!(h.round(), -4.0);
93 /// assert_eq!(i.round(), 4.0);
94 /// assert_eq!(j.round(), 5.0);
95 /// # }
96 /// ```
97 #[inline]
98 #[rustc_allow_incoherent_impl]
99 #[unstable(feature = "f128", issue = "116909")]
100 #[must_use = "method returns a new number and does not mutate the original value"]
101 pub fn round(self) -> f128 {
102 unsafe { intrinsics::roundf128(self) }
103 }
104
105 /// Returns the nearest integer to a number. Rounds half-way cases to the number
106 /// with an even least significant digit.
107 ///
108 /// This function always returns the precise result.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// #![feature(f128)]
114 /// # #[cfg(reliable_f128_math)] {
115 ///
116 /// let f = 3.3_f128;
117 /// let g = -3.3_f128;
118 /// let h = 3.5_f128;
119 /// let i = 4.5_f128;
120 ///
121 /// assert_eq!(f.round_ties_even(), 3.0);
122 /// assert_eq!(g.round_ties_even(), -3.0);
123 /// assert_eq!(h.round_ties_even(), 4.0);
124 /// assert_eq!(i.round_ties_even(), 4.0);
125 /// # }
126 /// ```
127 #[inline]
128 #[rustc_allow_incoherent_impl]
129 #[unstable(feature = "f128", issue = "116909")]
130 #[must_use = "method returns a new number and does not mutate the original value"]
131 pub fn round_ties_even(self) -> f128 {
132 unsafe { intrinsics::rintf128(self) }
133 }
134
135 /// Returns the integer part of `self`.
136 /// This means that non-integer numbers are always truncated towards zero.
137 ///
138 /// This function always returns the precise result.
139 ///
140 /// # Examples
141 ///
142 /// ```
143 /// #![feature(f128)]
144 /// # #[cfg(reliable_f128_math)] {
145 ///
146 /// let f = 3.7_f128;
147 /// let g = 3.0_f128;
148 /// let h = -3.7_f128;
149 ///
150 /// assert_eq!(f.trunc(), 3.0);
151 /// assert_eq!(g.trunc(), 3.0);
152 /// assert_eq!(h.trunc(), -3.0);
153 /// # }
154 /// ```
155 #[inline]
156 #[doc(alias = "truncate")]
157 #[rustc_allow_incoherent_impl]
158 #[unstable(feature = "f128", issue = "116909")]
159 #[must_use = "method returns a new number and does not mutate the original value"]
160 pub fn trunc(self) -> f128 {
161 unsafe { intrinsics::truncf128(self) }
162 }
163
164 /// Returns the fractional part of `self`.
165 ///
166 /// This function always returns the precise result.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// #![feature(f128)]
172 /// # #[cfg(reliable_f128_math)] {
173 ///
174 /// let x = 3.6_f128;
175 /// let y = -3.6_f128;
176 /// let abs_difference_x = (x.fract() - 0.6).abs();
177 /// let abs_difference_y = (y.fract() - (-0.6)).abs();
178 ///
179 /// assert!(abs_difference_x <= f128::EPSILON);
180 /// assert!(abs_difference_y <= f128::EPSILON);
181 /// # }
182 /// ```
183 #[inline]
184 #[rustc_allow_incoherent_impl]
185 #[unstable(feature = "f128", issue = "116909")]
186 #[must_use = "method returns a new number and does not mutate the original value"]
187 pub fn fract(self) -> f128 {
188 self - self.trunc()
34189 }
35190
36191 /// Computes the absolute value of `self`.
......@@ -41,7 +196,7 @@ impl f128 {
41196 ///
42197 /// ```
43198 /// #![feature(f128)]
44 /// # #[cfg(reliable_f128)] { // FIXME(f16_f128): reliable_f128
199 /// # #[cfg(reliable_f128)] {
45200 ///
46201 /// let x = 3.5_f128;
47202 /// let y = -3.5_f128;
......@@ -61,4 +216,1129 @@ impl f128 {
61216 // We don't do this now because LLVM has lowering bugs for f128 math.
62217 Self::from_bits(self.to_bits() & !(1 << 127))
63218 }
219
220 /// Returns a number that represents the sign of `self`.
221 ///
222 /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
223 /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
224 /// - NaN if the number is NaN
225 ///
226 /// # Examples
227 ///
228 /// ```
229 /// #![feature(f128)]
230 /// # #[cfg(reliable_f128_math)] {
231 ///
232 /// let f = 3.5_f128;
233 ///
234 /// assert_eq!(f.signum(), 1.0);
235 /// assert_eq!(f128::NEG_INFINITY.signum(), -1.0);
236 ///
237 /// assert!(f128::NAN.signum().is_nan());
238 /// # }
239 /// ```
240 #[inline]
241 #[rustc_allow_incoherent_impl]
242 #[unstable(feature = "f128", issue = "116909")]
243 #[must_use = "method returns a new number and does not mutate the original value"]
244 pub fn signum(self) -> f128 {
245 if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) }
246 }
247
248 /// Returns a number composed of the magnitude of `self` and the sign of
249 /// `sign`.
250 ///
251 /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
252 /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
253 /// `sign` is returned. Note, however, that conserving the sign bit on NaN
254 /// across arithmetical operations is not generally guaranteed.
255 /// See [explanation of NaN as a special value](primitive@f128) for more info.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// #![feature(f128)]
261 /// # #[cfg(reliable_f128_math)] {
262 ///
263 /// let f = 3.5_f128;
264 ///
265 /// assert_eq!(f.copysign(0.42), 3.5_f128);
266 /// assert_eq!(f.copysign(-0.42), -3.5_f128);
267 /// assert_eq!((-f).copysign(0.42), 3.5_f128);
268 /// assert_eq!((-f).copysign(-0.42), -3.5_f128);
269 ///
270 /// assert!(f128::NAN.copysign(1.0).is_nan());
271 /// # }
272 /// ```
273 #[inline]
274 #[rustc_allow_incoherent_impl]
275 #[unstable(feature = "f128", issue = "116909")]
276 #[must_use = "method returns a new number and does not mutate the original value"]
277 pub fn copysign(self, sign: f128) -> f128 {
278 unsafe { intrinsics::copysignf128(self, sign) }
279 }
280
281 /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
282 /// error, yielding a more accurate result than an unfused multiply-add.
283 ///
284 /// Using `mul_add` *may* be more performant than an unfused multiply-add if
285 /// the target architecture has a dedicated `fma` CPU instruction. However,
286 /// this is not always true, and will be heavily dependant on designing
287 /// algorithms with specific target hardware in mind.
288 ///
289 /// # Precision
290 ///
291 /// The result of this operation is guaranteed to be the rounded
292 /// infinite-precision result. It is specified by IEEE 754 as
293 /// `fusedMultiplyAdd` and guaranteed not to change.
294 ///
295 /// # Examples
296 ///
297 /// ```
298 /// #![feature(f128)]
299 /// # #[cfg(reliable_f128_math)] {
300 ///
301 /// let m = 10.0_f128;
302 /// let x = 4.0_f128;
303 /// let b = 60.0_f128;
304 ///
305 /// assert_eq!(m.mul_add(x, b), 100.0);
306 /// assert_eq!(m * x + b, 100.0);
307 ///
308 /// let one_plus_eps = 1.0_f128 + f128::EPSILON;
309 /// let one_minus_eps = 1.0_f128 - f128::EPSILON;
310 /// let minus_one = -1.0_f128;
311 ///
312 /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
313 /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f128::EPSILON * f128::EPSILON);
314 /// // Different rounding with the non-fused multiply and add.
315 /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
316 /// # }
317 /// ```
318 #[inline]
319 #[rustc_allow_incoherent_impl]
320 #[unstable(feature = "f128", issue = "116909")]
321 #[must_use = "method returns a new number and does not mutate the original value"]
322 pub fn mul_add(self, a: f128, b: f128) -> f128 {
323 unsafe { intrinsics::fmaf128(self, a, b) }
324 }
325
326 /// Calculates Euclidean division, the matching method for `rem_euclid`.
327 ///
328 /// This computes the integer `n` such that
329 /// `self = n * rhs + self.rem_euclid(rhs)`.
330 /// In other words, the result is `self / rhs` rounded to the integer `n`
331 /// such that `self >= n * rhs`.
332 ///
333 /// # Precision
334 ///
335 /// The result of this operation is guaranteed to be the rounded
336 /// infinite-precision result.
337 ///
338 /// # Examples
339 ///
340 /// ```
341 /// #![feature(f128)]
342 /// # #[cfg(reliable_f128_math)] {
343 ///
344 /// let a: f128 = 7.0;
345 /// let b = 4.0;
346 /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
347 /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
348 /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
349 /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
350 /// # }
351 /// ```
352 #[inline]
353 #[rustc_allow_incoherent_impl]
354 #[unstable(feature = "f128", issue = "116909")]
355 #[must_use = "method returns a new number and does not mutate the original value"]
356 pub fn div_euclid(self, rhs: f128) -> f128 {
357 let q = (self / rhs).trunc();
358 if self % rhs < 0.0 {
359 return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
360 }
361 q
362 }
363
364 /// Calculates the least nonnegative remainder of `self (mod rhs)`.
365 ///
366 /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
367 /// most cases. However, due to a floating point round-off error it can
368 /// result in `r == rhs.abs()`, violating the mathematical definition, if
369 /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
370 /// This result is not an element of the function's codomain, but it is the
371 /// closest floating point number in the real numbers and thus fulfills the
372 /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
373 /// approximately.
374 ///
375 /// # Precision
376 ///
377 /// The result of this operation is guaranteed to be the rounded
378 /// infinite-precision result.
379 ///
380 /// # Examples
381 ///
382 /// ```
383 /// #![feature(f128)]
384 /// # #[cfg(reliable_f128_math)] {
385 ///
386 /// let a: f128 = 7.0;
387 /// let b = 4.0;
388 /// assert_eq!(a.rem_euclid(b), 3.0);
389 /// assert_eq!((-a).rem_euclid(b), 1.0);
390 /// assert_eq!(a.rem_euclid(-b), 3.0);
391 /// assert_eq!((-a).rem_euclid(-b), 1.0);
392 /// // limitation due to round-off error
393 /// assert!((-f128::EPSILON).rem_euclid(3.0) != 0.0);
394 /// # }
395 /// ```
396 #[inline]
397 #[rustc_allow_incoherent_impl]
398 #[doc(alias = "modulo", alias = "mod")]
399 #[unstable(feature = "f128", issue = "116909")]
400 #[must_use = "method returns a new number and does not mutate the original value"]
401 pub fn rem_euclid(self, rhs: f128) -> f128 {
402 let r = self % rhs;
403 if r < 0.0 { r + rhs.abs() } else { r }
404 }
405
406 /// Raises a number to an integer power.
407 ///
408 /// Using this function is generally faster than using `powf`.
409 /// It might have a different sequence of rounding operations than `powf`,
410 /// so the results are not guaranteed to agree.
411 ///
412 /// # Unspecified precision
413 ///
414 /// The precision of this function is non-deterministic. This means it varies by platform,
415 /// Rust version, and can even differ within the same execution from one invocation to the next.
416 #[inline]
417 #[rustc_allow_incoherent_impl]
418 #[unstable(feature = "f128", issue = "116909")]
419 #[must_use = "method returns a new number and does not mutate the original value"]
420 pub fn powi(self, n: i32) -> f128 {
421 unsafe { intrinsics::powif128(self, n) }
422 }
423
424 /// Raises a number to a floating point power.
425 ///
426 /// # Unspecified precision
427 ///
428 /// The precision of this function is non-deterministic. This means it varies by platform,
429 /// Rust version, and can even differ within the same execution from one invocation to the next.
430 ///
431 /// # Examples
432 ///
433 /// ```
434 /// #![feature(f128)]
435 /// # #[cfg(reliable_f128_math)] {
436 ///
437 /// let x = 2.0_f128;
438 /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
439 ///
440 /// assert!(abs_difference <= f128::EPSILON);
441 /// # }
442 /// ```
443 #[inline]
444 #[rustc_allow_incoherent_impl]
445 #[unstable(feature = "f128", issue = "116909")]
446 #[must_use = "method returns a new number and does not mutate the original value"]
447 pub fn powf(self, n: f128) -> f128 {
448 unsafe { intrinsics::powf128(self, n) }
449 }
450
451 /// Returns the square root of a number.
452 ///
453 /// Returns NaN if `self` is a negative number other than `-0.0`.
454 ///
455 /// # Precision
456 ///
457 /// The result of this operation is guaranteed to be the rounded
458 /// infinite-precision result. It is specified by IEEE 754 as `squareRoot`
459 /// and guaranteed not to change.
460 ///
461 /// # Examples
462 ///
463 /// ```
464 /// #![feature(f128)]
465 /// # #[cfg(reliable_f128_math)] {
466 ///
467 /// let positive = 4.0_f128;
468 /// let negative = -4.0_f128;
469 /// let negative_zero = -0.0_f128;
470 ///
471 /// assert_eq!(positive.sqrt(), 2.0);
472 /// assert!(negative.sqrt().is_nan());
473 /// assert!(negative_zero.sqrt() == negative_zero);
474 /// # }
475 /// ```
476 #[inline]
477 #[rustc_allow_incoherent_impl]
478 #[unstable(feature = "f128", issue = "116909")]
479 #[must_use = "method returns a new number and does not mutate the original value"]
480 pub fn sqrt(self) -> f128 {
481 unsafe { intrinsics::sqrtf128(self) }
482 }
483
484 /// Returns `e^(self)`, (the exponential function).
485 ///
486 /// # Unspecified precision
487 ///
488 /// The precision of this function is non-deterministic. This means it varies by platform,
489 /// Rust version, and can even differ within the same execution from one invocation to the next.
490 ///
491 /// # Examples
492 ///
493 /// ```
494 /// #![feature(f128)]
495 /// # #[cfg(reliable_f128_math)] {
496 ///
497 /// let one = 1.0f128;
498 /// // e^1
499 /// let e = one.exp();
500 ///
501 /// // ln(e) - 1 == 0
502 /// let abs_difference = (e.ln() - 1.0).abs();
503 ///
504 /// assert!(abs_difference <= f128::EPSILON);
505 /// # }
506 /// ```
507 #[inline]
508 #[rustc_allow_incoherent_impl]
509 #[unstable(feature = "f128", issue = "116909")]
510 #[must_use = "method returns a new number and does not mutate the original value"]
511 pub fn exp(self) -> f128 {
512 unsafe { intrinsics::expf128(self) }
513 }
514
515 /// Returns `2^(self)`.
516 ///
517 /// # Unspecified precision
518 ///
519 /// The precision of this function is non-deterministic. This means it varies by platform,
520 /// Rust version, and can even differ within the same execution from one invocation to the next.
521 ///
522 /// # Examples
523 ///
524 /// ```
525 /// #![feature(f128)]
526 /// # #[cfg(reliable_f128_math)] {
527 ///
528 /// let f = 2.0f128;
529 ///
530 /// // 2^2 - 4 == 0
531 /// let abs_difference = (f.exp2() - 4.0).abs();
532 ///
533 /// assert!(abs_difference <= f128::EPSILON);
534 /// # }
535 /// ```
536 #[inline]
537 #[rustc_allow_incoherent_impl]
538 #[unstable(feature = "f128", issue = "116909")]
539 #[must_use = "method returns a new number and does not mutate the original value"]
540 pub fn exp2(self) -> f128 {
541 unsafe { intrinsics::exp2f128(self) }
542 }
543
544 /// Returns the natural logarithm of the number.
545 ///
546 /// # Unspecified precision
547 ///
548 /// The precision of this function is non-deterministic. This means it varies by platform,
549 /// Rust version, and can even differ within the same execution from one invocation to the next.
550 ///
551 /// # Examples
552 ///
553 /// ```
554 /// #![feature(f128)]
555 /// # #[cfg(reliable_f128_math)] {
556 ///
557 /// let one = 1.0f128;
558 /// // e^1
559 /// let e = one.exp();
560 ///
561 /// // ln(e) - 1 == 0
562 /// let abs_difference = (e.ln() - 1.0).abs();
563 ///
564 /// assert!(abs_difference <= f128::EPSILON);
565 /// # }
566 /// ```
567 #[inline]
568 #[rustc_allow_incoherent_impl]
569 #[unstable(feature = "f128", issue = "116909")]
570 #[must_use = "method returns a new number and does not mutate the original value"]
571 pub fn ln(self) -> f128 {
572 unsafe { intrinsics::logf128(self) }
573 }
574
575 /// Returns the logarithm of the number with respect to an arbitrary base.
576 ///
577 /// The result might not be correctly rounded owing to implementation details;
578 /// `self.log2()` can produce more accurate results for base 2, and
579 /// `self.log10()` can produce more accurate results for base 10.
580 ///
581 /// # Unspecified precision
582 ///
583 /// The precision of this function is non-deterministic. This means it varies by platform,
584 /// Rust version, and can even differ within the same execution from one invocation to the next.
585 ///
586 /// # Examples
587 ///
588 /// ```
589 /// #![feature(f128)]
590 /// # #[cfg(reliable_f128_math)] {
591 ///
592 /// let five = 5.0f128;
593 ///
594 /// // log5(5) - 1 == 0
595 /// let abs_difference = (five.log(5.0) - 1.0).abs();
596 ///
597 /// assert!(abs_difference <= f128::EPSILON);
598 /// # }
599 /// ```
600 #[inline]
601 #[rustc_allow_incoherent_impl]
602 #[unstable(feature = "f128", issue = "116909")]
603 #[must_use = "method returns a new number and does not mutate the original value"]
604 pub fn log(self, base: f128) -> f128 {
605 self.ln() / base.ln()
606 }
607
608 /// Returns the base 2 logarithm of the number.
609 ///
610 /// # Unspecified precision
611 ///
612 /// The precision of this function is non-deterministic. This means it varies by platform,
613 /// Rust version, and can even differ within the same execution from one invocation to the next.
614 ///
615 /// # Examples
616 ///
617 /// ```
618 /// #![feature(f128)]
619 /// # #[cfg(reliable_f128_math)] {
620 ///
621 /// let two = 2.0f128;
622 ///
623 /// // log2(2) - 1 == 0
624 /// let abs_difference = (two.log2() - 1.0).abs();
625 ///
626 /// assert!(abs_difference <= f128::EPSILON);
627 /// # }
628 /// ```
629 #[inline]
630 #[rustc_allow_incoherent_impl]
631 #[unstable(feature = "f128", issue = "116909")]
632 #[must_use = "method returns a new number and does not mutate the original value"]
633 pub fn log2(self) -> f128 {
634 unsafe { intrinsics::log2f128(self) }
635 }
636
637 /// Returns the base 10 logarithm of the number.
638 ///
639 /// # Unspecified precision
640 ///
641 /// The precision of this function is non-deterministic. This means it varies by platform,
642 /// Rust version, and can even differ within the same execution from one invocation to the next.
643 ///
644 /// # Examples
645 ///
646 /// ```
647 /// #![feature(f128)]
648 /// # #[cfg(reliable_f128_math)] {
649 ///
650 /// let ten = 10.0f128;
651 ///
652 /// // log10(10) - 1 == 0
653 /// let abs_difference = (ten.log10() - 1.0).abs();
654 ///
655 /// assert!(abs_difference <= f128::EPSILON);
656 /// # }
657 /// ```
658 #[inline]
659 #[rustc_allow_incoherent_impl]
660 #[unstable(feature = "f128", issue = "116909")]
661 #[must_use = "method returns a new number and does not mutate the original value"]
662 pub fn log10(self) -> f128 {
663 unsafe { intrinsics::log10f128(self) }
664 }
665
666 /// Returns the cube root of a number.
667 ///
668 /// # Unspecified precision
669 ///
670 /// The precision of this function is non-deterministic. This means it varies by platform,
671 /// Rust version, and can even differ within the same execution from one invocation to the next.
672 ///
673 ///
674 /// This function currently corresponds to the `cbrtf128` from libc on Unix
675 /// and Windows. Note that this might change in the future.
676 ///
677 /// # Examples
678 ///
679 /// ```
680 /// #![feature(f128)]
681 /// # #[cfg(reliable_f128_math)] {
682 ///
683 /// let x = 8.0f128;
684 ///
685 /// // x^(1/3) - 2 == 0
686 /// let abs_difference = (x.cbrt() - 2.0).abs();
687 ///
688 /// assert!(abs_difference <= f128::EPSILON);
689 /// # }
690 /// ```
691 #[inline]
692 #[rustc_allow_incoherent_impl]
693 #[unstable(feature = "f128", issue = "116909")]
694 #[must_use = "method returns a new number and does not mutate the original value"]
695 pub fn cbrt(self) -> f128 {
696 unsafe { cmath::cbrtf128(self) }
697 }
698
699 /// Compute the distance between the origin and a point (`x`, `y`) on the
700 /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a
701 /// right-angle triangle with other sides having length `x.abs()` and
702 /// `y.abs()`.
703 ///
704 /// # Unspecified precision
705 ///
706 /// The precision of this function is non-deterministic. This means it varies by platform,
707 /// Rust version, and can even differ within the same execution from one invocation to the next.
708 ///
709 ///
710 /// This function currently corresponds to the `hypotf128` from libc on Unix
711 /// and Windows. Note that this might change in the future.
712 ///
713 /// # Examples
714 ///
715 /// ```
716 /// #![feature(f128)]
717 /// # #[cfg(reliable_f128_math)] {
718 ///
719 /// let x = 2.0f128;
720 /// let y = 3.0f128;
721 ///
722 /// // sqrt(x^2 + y^2)
723 /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
724 ///
725 /// assert!(abs_difference <= f128::EPSILON);
726 /// # }
727 /// ```
728 #[inline]
729 #[rustc_allow_incoherent_impl]
730 #[unstable(feature = "f128", issue = "116909")]
731 #[must_use = "method returns a new number and does not mutate the original value"]
732 pub fn hypot(self, other: f128) -> f128 {
733 unsafe { cmath::hypotf128(self, other) }
734 }
735
736 /// Computes the sine of a number (in radians).
737 ///
738 /// # Unspecified precision
739 ///
740 /// The precision of this function is non-deterministic. This means it varies by platform,
741 /// Rust version, and can even differ within the same execution from one invocation to the next.
742 ///
743 /// # Examples
744 ///
745 /// ```
746 /// #![feature(f128)]
747 /// # #[cfg(reliable_f128_math)] {
748 ///
749 /// let x = std::f128::consts::FRAC_PI_2;
750 ///
751 /// let abs_difference = (x.sin() - 1.0).abs();
752 ///
753 /// assert!(abs_difference <= f128::EPSILON);
754 /// # }
755 /// ```
756 #[inline]
757 #[rustc_allow_incoherent_impl]
758 #[unstable(feature = "f128", issue = "116909")]
759 #[must_use = "method returns a new number and does not mutate the original value"]
760 pub fn sin(self) -> f128 {
761 unsafe { intrinsics::sinf128(self) }
762 }
763
764 /// Computes the cosine of a number (in radians).
765 ///
766 /// # Unspecified precision
767 ///
768 /// The precision of this function is non-deterministic. This means it varies by platform,
769 /// Rust version, and can even differ within the same execution from one invocation to the next.
770 ///
771 /// # Examples
772 ///
773 /// ```
774 /// #![feature(f128)]
775 /// # #[cfg(reliable_f128_math)] {
776 ///
777 /// let x = 2.0 * std::f128::consts::PI;
778 ///
779 /// let abs_difference = (x.cos() - 1.0).abs();
780 ///
781 /// assert!(abs_difference <= f128::EPSILON);
782 /// # }
783 /// ```
784 #[inline]
785 #[rustc_allow_incoherent_impl]
786 #[unstable(feature = "f128", issue = "116909")]
787 #[must_use = "method returns a new number and does not mutate the original value"]
788 pub fn cos(self) -> f128 {
789 unsafe { intrinsics::cosf128(self) }
790 }
791
792 /// Computes the tangent of a number (in radians).
793 ///
794 /// # Unspecified precision
795 ///
796 /// The precision of this function is non-deterministic. This means it varies by platform,
797 /// Rust version, and can even differ within the same execution from one invocation to the next.
798 ///
799 /// This function currently corresponds to the `tanf128` from libc on Unix and
800 /// Windows. Note that this might change in the future.
801 ///
802 /// # Examples
803 ///
804 /// ```
805 /// #![feature(f128)]
806 /// # #[cfg(reliable_f128_math)] {
807 ///
808 /// let x = std::f128::consts::FRAC_PI_4;
809 /// let abs_difference = (x.tan() - 1.0).abs();
810 ///
811 /// assert!(abs_difference <= f128::EPSILON);
812 /// # }
813 /// ```
814 #[inline]
815 #[rustc_allow_incoherent_impl]
816 #[unstable(feature = "f128", issue = "116909")]
817 #[must_use = "method returns a new number and does not mutate the original value"]
818 pub fn tan(self) -> f128 {
819 unsafe { cmath::tanf128(self) }
820 }
821
822 /// Computes the arcsine of a number. Return value is in radians in
823 /// the range [-pi/2, pi/2] or NaN if the number is outside the range
824 /// [-1, 1].
825 ///
826 /// # Unspecified precision
827 ///
828 /// The precision of this function is non-deterministic. This means it varies by platform,
829 /// Rust version, and can even differ within the same execution from one invocation to the next.
830 ///
831 /// This function currently corresponds to the `asinf128` from libc on Unix
832 /// and Windows. Note that this might change in the future.
833 ///
834 /// # Examples
835 ///
836 /// ```
837 /// #![feature(f128)]
838 /// # #[cfg(reliable_f128_math)] {
839 ///
840 /// let f = std::f128::consts::FRAC_PI_2;
841 ///
842 /// // asin(sin(pi/2))
843 /// let abs_difference = (f.sin().asin() - std::f128::consts::FRAC_PI_2).abs();
844 ///
845 /// assert!(abs_difference <= f128::EPSILON);
846 /// # }
847 /// ```
848 #[inline]
849 #[doc(alias = "arcsin")]
850 #[rustc_allow_incoherent_impl]
851 #[unstable(feature = "f128", issue = "116909")]
852 #[must_use = "method returns a new number and does not mutate the original value"]
853 pub fn asin(self) -> f128 {
854 unsafe { cmath::asinf128(self) }
855 }
856
857 /// Computes the arccosine of a number. Return value is in radians in
858 /// the range [0, pi] or NaN if the number is outside the range
859 /// [-1, 1].
860 ///
861 /// # Unspecified precision
862 ///
863 /// The precision of this function is non-deterministic. This means it varies by platform,
864 /// Rust version, and can even differ within the same execution from one invocation to the next.
865 ///
866 /// This function currently corresponds to the `acosf128` from libc on Unix
867 /// and Windows. Note that this might change in the future.
868 ///
869 /// # Examples
870 ///
871 /// ```
872 /// #![feature(f128)]
873 /// # #[cfg(reliable_f128_math)] {
874 ///
875 /// let f = std::f128::consts::FRAC_PI_4;
876 ///
877 /// // acos(cos(pi/4))
878 /// let abs_difference = (f.cos().acos() - std::f128::consts::FRAC_PI_4).abs();
879 ///
880 /// assert!(abs_difference <= f128::EPSILON);
881 /// # }
882 /// ```
883 #[inline]
884 #[doc(alias = "arccos")]
885 #[rustc_allow_incoherent_impl]
886 #[unstable(feature = "f128", issue = "116909")]
887 #[must_use = "method returns a new number and does not mutate the original value"]
888 pub fn acos(self) -> f128 {
889 unsafe { cmath::acosf128(self) }
890 }
891
892 /// Computes the arctangent of a number. Return value is in radians in the
893 /// range [-pi/2, pi/2];
894 ///
895 /// # Unspecified precision
896 ///
897 /// The precision of this function is non-deterministic. This means it varies by platform,
898 /// Rust version, and can even differ within the same execution from one invocation to the next.
899 ///
900 /// This function currently corresponds to the `atanf128` from libc on Unix
901 /// and Windows. Note that this might change in the future.
902 ///
903 /// # Examples
904 ///
905 /// ```
906 /// #![feature(f128)]
907 /// # #[cfg(reliable_f128_math)] {
908 ///
909 /// let f = 1.0f128;
910 ///
911 /// // atan(tan(1))
912 /// let abs_difference = (f.tan().atan() - 1.0).abs();
913 ///
914 /// assert!(abs_difference <= f128::EPSILON);
915 /// # }
916 /// ```
917 #[inline]
918 #[doc(alias = "arctan")]
919 #[rustc_allow_incoherent_impl]
920 #[unstable(feature = "f128", issue = "116909")]
921 #[must_use = "method returns a new number and does not mutate the original value"]
922 pub fn atan(self) -> f128 {
923 unsafe { cmath::atanf128(self) }
924 }
925
926 /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
927 ///
928 /// * `x = 0`, `y = 0`: `0`
929 /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
930 /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
931 /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
932 ///
933 /// # Unspecified precision
934 ///
935 /// The precision of this function is non-deterministic. This means it varies by platform,
936 /// Rust version, and can even differ within the same execution from one invocation to the next.
937 ///
938 /// This function currently corresponds to the `atan2f128` from libc on Unix
939 /// and Windows. Note that this might change in the future.
940 ///
941 /// # Examples
942 ///
943 /// ```
944 /// #![feature(f128)]
945 /// # #[cfg(reliable_f128_math)] {
946 ///
947 /// // Positive angles measured counter-clockwise
948 /// // from positive x axis
949 /// // -pi/4 radians (45 deg clockwise)
950 /// let x1 = 3.0f128;
951 /// let y1 = -3.0f128;
952 ///
953 /// // 3pi/4 radians (135 deg counter-clockwise)
954 /// let x2 = -3.0f128;
955 /// let y2 = 3.0f128;
956 ///
957 /// let abs_difference_1 = (y1.atan2(x1) - (-std::f128::consts::FRAC_PI_4)).abs();
958 /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f128::consts::FRAC_PI_4)).abs();
959 ///
960 /// assert!(abs_difference_1 <= f128::EPSILON);
961 /// assert!(abs_difference_2 <= f128::EPSILON);
962 /// # }
963 /// ```
964 #[inline]
965 #[rustc_allow_incoherent_impl]
966 #[unstable(feature = "f128", issue = "116909")]
967 #[must_use = "method returns a new number and does not mutate the original value"]
968 pub fn atan2(self, other: f128) -> f128 {
969 unsafe { cmath::atan2f128(self, other) }
970 }
971
972 /// Simultaneously computes the sine and cosine of the number, `x`. Returns
973 /// `(sin(x), cos(x))`.
974 ///
975 /// # Unspecified precision
976 ///
977 /// The precision of this function is non-deterministic. This means it varies by platform,
978 /// Rust version, and can even differ within the same execution from one invocation to the next.
979 ///
980 /// This function currently corresponds to the `(f128::sin(x),
981 /// f128::cos(x))`. Note that this might change in the future.
982 ///
983 /// # Examples
984 ///
985 /// ```
986 /// #![feature(f128)]
987 /// # #[cfg(reliable_f128_math)] {
988 ///
989 /// let x = std::f128::consts::FRAC_PI_4;
990 /// let f = x.sin_cos();
991 ///
992 /// let abs_difference_0 = (f.0 - x.sin()).abs();
993 /// let abs_difference_1 = (f.1 - x.cos()).abs();
994 ///
995 /// assert!(abs_difference_0 <= f128::EPSILON);
996 /// assert!(abs_difference_1 <= f128::EPSILON);
997 /// # }
998 /// ```
999 #[inline]
1000 #[doc(alias = "sincos")]
1001 #[rustc_allow_incoherent_impl]
1002 #[unstable(feature = "f128", issue = "116909")]
1003 pub fn sin_cos(self) -> (f128, f128) {
1004 (self.sin(), self.cos())
1005 }
1006
1007 /// Returns `e^(self) - 1` in a way that is accurate even if the
1008 /// number is close to zero.
1009 ///
1010 /// # Unspecified precision
1011 ///
1012 /// The precision of this function is non-deterministic. This means it varies by platform,
1013 /// Rust version, and can even differ within the same execution from one invocation to the next.
1014 ///
1015 /// This function currently corresponds to the `expm1f128` from libc on Unix
1016 /// and Windows. Note that this might change in the future.
1017 ///
1018 /// # Examples
1019 ///
1020 /// ```
1021 /// #![feature(f128)]
1022 /// # #[cfg(reliable_f128_math)] {
1023 ///
1024 /// let x = 1e-8_f128;
1025 ///
1026 /// // for very small x, e^x is approximately 1 + x + x^2 / 2
1027 /// let approx = x + x * x / 2.0;
1028 /// let abs_difference = (x.exp_m1() - approx).abs();
1029 ///
1030 /// assert!(abs_difference < 1e-10);
1031 /// # }
1032 /// ```
1033 #[inline]
1034 #[rustc_allow_incoherent_impl]
1035 #[unstable(feature = "f128", issue = "116909")]
1036 #[must_use = "method returns a new number and does not mutate the original value"]
1037 pub fn exp_m1(self) -> f128 {
1038 unsafe { cmath::expm1f128(self) }
1039 }
1040
1041 /// Returns `ln(1+n)` (natural logarithm) more accurately than if
1042 /// the operations were performed separately.
1043 ///
1044 /// # Unspecified precision
1045 ///
1046 /// The precision of this function is non-deterministic. This means it varies by platform,
1047 /// Rust version, and can even differ within the same execution from one invocation to the next.
1048 ///
1049 /// This function currently corresponds to the `log1pf128` from libc on Unix
1050 /// and Windows. Note that this might change in the future.
1051 ///
1052 /// # Examples
1053 ///
1054 /// ```
1055 /// #![feature(f128)]
1056 /// # #[cfg(reliable_f128_math)] {
1057 ///
1058 /// let x = 1e-8_f128;
1059 ///
1060 /// // for very small x, ln(1 + x) is approximately x - x^2 / 2
1061 /// let approx = x - x * x / 2.0;
1062 /// let abs_difference = (x.ln_1p() - approx).abs();
1063 ///
1064 /// assert!(abs_difference < 1e-10);
1065 /// # }
1066 /// ```
1067 #[inline]
1068 #[doc(alias = "log1p")]
1069 #[must_use = "method returns a new number and does not mutate the original value"]
1070 #[rustc_allow_incoherent_impl]
1071 #[unstable(feature = "f128", issue = "116909")]
1072 pub fn ln_1p(self) -> f128 {
1073 unsafe { cmath::log1pf128(self) }
1074 }
1075
1076 /// Hyperbolic sine function.
1077 ///
1078 /// # Unspecified precision
1079 ///
1080 /// The precision of this function is non-deterministic. This means it varies by platform,
1081 /// Rust version, and can even differ within the same execution from one invocation to the next.
1082 ///
1083 /// This function currently corresponds to the `sinhf128` from libc on Unix
1084 /// and Windows. Note that this might change in the future.
1085 ///
1086 /// # Examples
1087 ///
1088 /// ```
1089 /// #![feature(f128)]
1090 /// # #[cfg(reliable_f128_math)] {
1091 ///
1092 /// let e = std::f128::consts::E;
1093 /// let x = 1.0f128;
1094 ///
1095 /// let f = x.sinh();
1096 /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
1097 /// let g = ((e * e) - 1.0) / (2.0 * e);
1098 /// let abs_difference = (f - g).abs();
1099 ///
1100 /// assert!(abs_difference <= f128::EPSILON);
1101 /// # }
1102 /// ```
1103 #[inline]
1104 #[rustc_allow_incoherent_impl]
1105 #[unstable(feature = "f128", issue = "116909")]
1106 #[must_use = "method returns a new number and does not mutate the original value"]
1107 pub fn sinh(self) -> f128 {
1108 unsafe { cmath::sinhf128(self) }
1109 }
1110
1111 /// Hyperbolic cosine function.
1112 ///
1113 /// # Unspecified precision
1114 ///
1115 /// The precision of this function is non-deterministic. This means it varies by platform,
1116 /// Rust version, and can even differ within the same execution from one invocation to the next.
1117 ///
1118 /// This function currently corresponds to the `coshf128` from libc on Unix
1119 /// and Windows. Note that this might change in the future.
1120 ///
1121 /// # Examples
1122 ///
1123 /// ```
1124 /// #![feature(f128)]
1125 /// # #[cfg(reliable_f128_math)] {
1126 ///
1127 /// let e = std::f128::consts::E;
1128 /// let x = 1.0f128;
1129 /// let f = x.cosh();
1130 /// // Solving cosh() at 1 gives this result
1131 /// let g = ((e * e) + 1.0) / (2.0 * e);
1132 /// let abs_difference = (f - g).abs();
1133 ///
1134 /// // Same result
1135 /// assert!(abs_difference <= f128::EPSILON);
1136 /// # }
1137 /// ```
1138 #[inline]
1139 #[rustc_allow_incoherent_impl]
1140 #[unstable(feature = "f128", issue = "116909")]
1141 #[must_use = "method returns a new number and does not mutate the original value"]
1142 pub fn cosh(self) -> f128 {
1143 unsafe { cmath::coshf128(self) }
1144 }
1145
1146 /// Hyperbolic tangent function.
1147 ///
1148 /// # Unspecified precision
1149 ///
1150 /// The precision of this function is non-deterministic. This means it varies by platform,
1151 /// Rust version, and can even differ within the same execution from one invocation to the next.
1152 ///
1153 /// This function currently corresponds to the `tanhf128` from libc on Unix
1154 /// and Windows. Note that this might change in the future.
1155 ///
1156 /// # Examples
1157 ///
1158 /// ```
1159 /// #![feature(f128)]
1160 /// # #[cfg(reliable_f128_math)] {
1161 ///
1162 /// let e = std::f128::consts::E;
1163 /// let x = 1.0f128;
1164 ///
1165 /// let f = x.tanh();
1166 /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
1167 /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
1168 /// let abs_difference = (f - g).abs();
1169 ///
1170 /// assert!(abs_difference <= f128::EPSILON);
1171 /// # }
1172 /// ```
1173 #[inline]
1174 #[rustc_allow_incoherent_impl]
1175 #[unstable(feature = "f128", issue = "116909")]
1176 #[must_use = "method returns a new number and does not mutate the original value"]
1177 pub fn tanh(self) -> f128 {
1178 unsafe { cmath::tanhf128(self) }
1179 }
1180
1181 /// Inverse hyperbolic sine function.
1182 ///
1183 /// # Unspecified precision
1184 ///
1185 /// The precision of this function is non-deterministic. This means it varies by platform,
1186 /// Rust version, and can even differ within the same execution from one invocation to the next.
1187 ///
1188 /// # Examples
1189 ///
1190 /// ```
1191 /// #![feature(f128)]
1192 /// # #[cfg(reliable_f128_math)] {
1193 ///
1194 /// let x = 1.0f128;
1195 /// let f = x.sinh().asinh();
1196 ///
1197 /// let abs_difference = (f - x).abs();
1198 ///
1199 /// assert!(abs_difference <= f128::EPSILON);
1200 /// # }
1201 /// ```
1202 #[inline]
1203 #[doc(alias = "arcsinh")]
1204 #[rustc_allow_incoherent_impl]
1205 #[unstable(feature = "f128", issue = "116909")]
1206 #[must_use = "method returns a new number and does not mutate the original value"]
1207 pub fn asinh(self) -> f128 {
1208 let ax = self.abs();
1209 let ix = 1.0 / ax;
1210 (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
1211 }
1212
1213 /// Inverse hyperbolic cosine function.
1214 ///
1215 /// # Unspecified precision
1216 ///
1217 /// The precision of this function is non-deterministic. This means it varies by platform,
1218 /// Rust version, and can even differ within the same execution from one invocation to the next.
1219 ///
1220 /// # Examples
1221 ///
1222 /// ```
1223 /// #![feature(f128)]
1224 /// # #[cfg(reliable_f128_math)] {
1225 ///
1226 /// let x = 1.0f128;
1227 /// let f = x.cosh().acosh();
1228 ///
1229 /// let abs_difference = (f - x).abs();
1230 ///
1231 /// assert!(abs_difference <= f128::EPSILON);
1232 /// # }
1233 /// ```
1234 #[inline]
1235 #[doc(alias = "arccosh")]
1236 #[rustc_allow_incoherent_impl]
1237 #[unstable(feature = "f128", issue = "116909")]
1238 #[must_use = "method returns a new number and does not mutate the original value"]
1239 pub fn acosh(self) -> f128 {
1240 if self < 1.0 {
1241 Self::NAN
1242 } else {
1243 (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
1244 }
1245 }
1246
1247 /// Inverse hyperbolic tangent function.
1248 ///
1249 /// # Unspecified precision
1250 ///
1251 /// The precision of this function is non-deterministic. This means it varies by platform,
1252 /// Rust version, and can even differ within the same execution from one invocation to the next.
1253 ///
1254 /// # Examples
1255 ///
1256 /// ```
1257 /// #![feature(f128)]
1258 /// # #[cfg(reliable_f128_math)] {
1259 ///
1260 /// let e = std::f128::consts::E;
1261 /// let f = e.tanh().atanh();
1262 ///
1263 /// let abs_difference = (f - e).abs();
1264 ///
1265 /// assert!(abs_difference <= 1e-5);
1266 /// # }
1267 /// ```
1268 #[inline]
1269 #[doc(alias = "arctanh")]
1270 #[rustc_allow_incoherent_impl]
1271 #[unstable(feature = "f128", issue = "116909")]
1272 #[must_use = "method returns a new number and does not mutate the original value"]
1273 pub fn atanh(self) -> f128 {
1274 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
1275 }
1276
1277 /// Gamma function.
1278 ///
1279 /// # Unspecified precision
1280 ///
1281 /// The precision of this function is non-deterministic. This means it varies by platform,
1282 /// Rust version, and can even differ within the same execution from one invocation to the next.
1283 ///
1284 /// This function currently corresponds to the `tgammaf128` from libc on Unix
1285 /// and Windows. Note that this might change in the future.
1286 ///
1287 /// # Examples
1288 ///
1289 /// ```
1290 /// #![feature(f128)]
1291 /// #![feature(float_gamma)]
1292 /// # #[cfg(reliable_f128_math)] {
1293 ///
1294 /// let x = 5.0f128;
1295 ///
1296 /// let abs_difference = (x.gamma() - 24.0).abs();
1297 ///
1298 /// assert!(abs_difference <= f128::EPSILON);
1299 /// # }
1300 /// ```
1301 #[inline]
1302 #[rustc_allow_incoherent_impl]
1303 #[unstable(feature = "f128", issue = "116909")]
1304 #[must_use = "method returns a new number and does not mutate the original value"]
1305 pub fn gamma(self) -> f128 {
1306 unsafe { cmath::tgammaf128(self) }
1307 }
1308
1309 /// Natural logarithm of the absolute value of the gamma function
1310 ///
1311 /// The integer part of the tuple indicates the sign of the gamma function.
1312 ///
1313 /// # Unspecified precision
1314 ///
1315 /// The precision of this function is non-deterministic. This means it varies by platform,
1316 /// Rust version, and can even differ within the same execution from one invocation to the next.
1317 ///
1318 /// This function currently corresponds to the `lgammaf128_r` from libc on Unix
1319 /// and Windows. Note that this might change in the future.
1320 ///
1321 /// # Examples
1322 ///
1323 /// ```
1324 /// #![feature(f128)]
1325 /// #![feature(float_gamma)]
1326 /// # #[cfg(reliable_f128_math)] {
1327 ///
1328 /// let x = 2.0f128;
1329 ///
1330 /// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
1331 ///
1332 /// assert!(abs_difference <= f128::EPSILON);
1333 /// # }
1334 /// ```
1335 #[inline]
1336 #[rustc_allow_incoherent_impl]
1337 #[unstable(feature = "f128", issue = "116909")]
1338 #[must_use = "method returns a new number and does not mutate the original value"]
1339 pub fn ln_gamma(self) -> (f128, i32) {
1340 let mut signgamp: i32 = 0;
1341 let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) };
1342 (x, signgamp)
1343 }
641344}
library/std/src/f128/tests.rs+443-35
......@@ -4,6 +4,21 @@
44use crate::f128::consts;
55use crate::num::{FpCategory as Fp, *};
66
7// Note these tolerances make sense around zero, but not for more extreme exponents.
8
9/// For operations that are near exact, usually not involving math of different
10/// signs.
11const TOL_PRECISE: f128 = 1e-28;
12
13/// Default tolerances. Works for values that should be near precise but not exact. Roughly
14/// the precision carried by `100 * 100`.
15const TOL: f128 = 1e-12;
16
17/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained
18/// operations.
19#[cfg(reliable_f128_math)]
20const TOL_IMPR: f128 = 1e-10;
21
722/// Smallest number
823const TINY_BITS: u128 = 0x1;
924
......@@ -41,7 +56,33 @@ fn test_num_f128() {
4156 test_num(10f128, 2f128);
4257}
4358
44// FIXME(f16_f128): add min and max tests when available
59#[test]
60#[cfg(reliable_f128_math)]
61fn test_min_nan() {
62 assert_eq!(f128::NAN.min(2.0), 2.0);
63 assert_eq!(2.0f128.min(f128::NAN), 2.0);
64}
65
66#[test]
67#[cfg(reliable_f128_math)]
68fn test_max_nan() {
69 assert_eq!(f128::NAN.max(2.0), 2.0);
70 assert_eq!(2.0f128.max(f128::NAN), 2.0);
71}
72
73#[test]
74#[cfg(reliable_f128_math)]
75fn test_minimum() {
76 assert!(f128::NAN.minimum(2.0).is_nan());
77 assert!(2.0f128.minimum(f128::NAN).is_nan());
78}
79
80#[test]
81#[cfg(reliable_f128_math)]
82fn test_maximum() {
83 assert!(f128::NAN.maximum(2.0).is_nan());
84 assert!(2.0f128.maximum(f128::NAN).is_nan());
85}
4586
4687#[test]
4788fn test_nan() {
......@@ -191,9 +232,100 @@ fn test_classify() {
191232 assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
192233}
193234
194// FIXME(f16_f128): add missing math functions when available
235#[test]
236#[cfg(reliable_f128_math)]
237fn test_floor() {
238 assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE);
239 assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE);
240 assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE);
241 assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE);
242 assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE);
243 assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE);
244 assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE);
245 assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE);
246 assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE);
247 assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE);
248}
249
250#[test]
251#[cfg(reliable_f128_math)]
252fn test_ceil() {
253 assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE);
254 assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE);
255 assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE);
256 assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE);
257 assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE);
258 assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE);
259 assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE);
260 assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE);
261 assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE);
262 assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE);
263}
195264
196265#[test]
266#[cfg(reliable_f128_math)]
267fn test_round() {
268 assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE);
269 assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE);
270 assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE);
271 assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE);
272 assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE);
273 assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE);
274 assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE);
275 assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE);
276 assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE);
277 assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE);
278 assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE);
279}
280
281#[test]
282#[cfg(reliable_f128_math)]
283fn test_round_ties_even() {
284 assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE);
285 assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE);
286 assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE);
287 assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE);
288 assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE);
289 assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE);
290 assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE);
291 assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE);
292 assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE);
293 assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE);
294 assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE);
295}
296
297#[test]
298#[cfg(reliable_f128_math)]
299fn test_trunc() {
300 assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE);
301 assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE);
302 assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE);
303 assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE);
304 assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE);
305 assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE);
306 assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE);
307 assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE);
308 assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE);
309 assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE);
310}
311
312#[test]
313#[cfg(reliable_f128_math)]
314fn test_fract() {
315 assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE);
316 assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE);
317 assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE);
318 assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE);
319 assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE);
320 assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE);
321 assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE);
322 assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE);
323 assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE);
324 assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE);
325}
326
327#[test]
328#[cfg(reliable_f128_math)]
197329fn test_abs() {
198330 assert_eq!(f128::INFINITY.abs(), f128::INFINITY);
199331 assert_eq!(1f128.abs(), 1f128);
......@@ -293,6 +425,24 @@ fn test_next_down() {
293425}
294426
295427#[test]
428#[cfg(reliable_f128_math)]
429fn test_mul_add() {
430 let nan: f128 = f128::NAN;
431 let inf: f128 = f128::INFINITY;
432 let neg_inf: f128 = f128::NEG_INFINITY;
433 assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE);
434 assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE);
435 assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE);
436 assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE);
437 assert!(nan.mul_add(7.8, 9.0).is_nan());
438 assert_eq!(inf.mul_add(7.8, 9.0), inf);
439 assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
440 assert_eq!(8.9f128.mul_add(inf, 3.2), inf);
441 assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf);
442}
443
444#[test]
445#[cfg(reliable_f16_math)]
296446fn test_recip() {
297447 let nan: f128 = f128::NAN;
298448 let inf: f128 = f128::INFINITY;
......@@ -301,11 +451,161 @@ fn test_recip() {
301451 assert_eq!(2.0f128.recip(), 0.5);
302452 assert_eq!((-0.4f128).recip(), -2.5);
303453 assert_eq!(0.0f128.recip(), inf);
454 assert_approx_eq!(
455 f128::MAX.recip(),
456 8.40525785778023376565669454330438228902076605e-4933,
457 1e-4900
458 );
304459 assert!(nan.recip().is_nan());
305460 assert_eq!(inf.recip(), 0.0);
306461 assert_eq!(neg_inf.recip(), 0.0);
307462}
308463
464// Many math functions allow for less accurate results, so the next tolerance up is used
465
466#[test]
467#[cfg(reliable_f128_math)]
468fn test_powi() {
469 let nan: f128 = f128::NAN;
470 let inf: f128 = f128::INFINITY;
471 let neg_inf: f128 = f128::NEG_INFINITY;
472 assert_eq!(1.0f128.powi(1), 1.0);
473 assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL);
474 assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL);
475 assert_eq!(8.3f128.powi(0), 1.0);
476 assert!(nan.powi(2).is_nan());
477 assert_eq!(inf.powi(3), inf);
478 assert_eq!(neg_inf.powi(2), inf);
479}
480
481#[test]
482#[cfg(reliable_f128_math)]
483fn test_powf() {
484 let nan: f128 = f128::NAN;
485 let inf: f128 = f128::INFINITY;
486 let neg_inf: f128 = f128::NEG_INFINITY;
487 assert_eq!(1.0f128.powf(1.0), 1.0);
488 assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR);
489 assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR);
490 assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR);
491 assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR);
492 assert_eq!(8.3f128.powf(0.0), 1.0);
493 assert!(nan.powf(2.0).is_nan());
494 assert_eq!(inf.powf(2.0), inf);
495 assert_eq!(neg_inf.powf(3.0), neg_inf);
496}
497
498#[test]
499#[cfg(reliable_f128_math)]
500fn test_sqrt_domain() {
501 assert!(f128::NAN.sqrt().is_nan());
502 assert!(f128::NEG_INFINITY.sqrt().is_nan());
503 assert!((-1.0f128).sqrt().is_nan());
504 assert_eq!((-0.0f128).sqrt(), -0.0);
505 assert_eq!(0.0f128.sqrt(), 0.0);
506 assert_eq!(1.0f128.sqrt(), 1.0);
507 assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY);
508}
509
510#[test]
511#[cfg(reliable_f128_math)]
512fn test_exp() {
513 assert_eq!(1.0, 0.0f128.exp());
514 assert_approx_eq!(consts::E, 1.0f128.exp(), TOL);
515 assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL);
516
517 let inf: f128 = f128::INFINITY;
518 let neg_inf: f128 = f128::NEG_INFINITY;
519 let nan: f128 = f128::NAN;
520 assert_eq!(inf, inf.exp());
521 assert_eq!(0.0, neg_inf.exp());
522 assert!(nan.exp().is_nan());
523}
524
525#[test]
526#[cfg(reliable_f128_math)]
527fn test_exp2() {
528 assert_eq!(32.0, 5.0f128.exp2());
529 assert_eq!(1.0, 0.0f128.exp2());
530
531 let inf: f128 = f128::INFINITY;
532 let neg_inf: f128 = f128::NEG_INFINITY;
533 let nan: f128 = f128::NAN;
534 assert_eq!(inf, inf.exp2());
535 assert_eq!(0.0, neg_inf.exp2());
536 assert!(nan.exp2().is_nan());
537}
538
539#[test]
540#[cfg(reliable_f128_math)]
541fn test_ln() {
542 let nan: f128 = f128::NAN;
543 let inf: f128 = f128::INFINITY;
544 let neg_inf: f128 = f128::NEG_INFINITY;
545 assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL);
546 assert!(nan.ln().is_nan());
547 assert_eq!(inf.ln(), inf);
548 assert!(neg_inf.ln().is_nan());
549 assert!((-2.3f128).ln().is_nan());
550 assert_eq!((-0.0f128).ln(), neg_inf);
551 assert_eq!(0.0f128.ln(), neg_inf);
552 assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL);
553}
554
555#[test]
556#[cfg(reliable_f128_math)]
557fn test_log() {
558 let nan: f128 = f128::NAN;
559 let inf: f128 = f128::INFINITY;
560 let neg_inf: f128 = f128::NEG_INFINITY;
561 assert_eq!(10.0f128.log(10.0), 1.0);
562 assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL);
563 assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0);
564 assert!(1.0f128.log(1.0).is_nan());
565 assert!(1.0f128.log(-13.9).is_nan());
566 assert!(nan.log(2.3).is_nan());
567 assert_eq!(inf.log(10.0), inf);
568 assert!(neg_inf.log(8.8).is_nan());
569 assert!((-2.3f128).log(0.1).is_nan());
570 assert_eq!((-0.0f128).log(2.0), neg_inf);
571 assert_eq!(0.0f128.log(7.0), neg_inf);
572}
573
574#[test]
575#[cfg(reliable_f128_math)]
576fn test_log2() {
577 let nan: f128 = f128::NAN;
578 let inf: f128 = f128::INFINITY;
579 let neg_inf: f128 = f128::NEG_INFINITY;
580 assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL);
581 assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL);
582 assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL);
583 assert!(nan.log2().is_nan());
584 assert_eq!(inf.log2(), inf);
585 assert!(neg_inf.log2().is_nan());
586 assert!((-2.3f128).log2().is_nan());
587 assert_eq!((-0.0f128).log2(), neg_inf);
588 assert_eq!(0.0f128.log2(), neg_inf);
589}
590
591#[test]
592#[cfg(reliable_f128_math)]
593fn test_log10() {
594 let nan: f128 = f128::NAN;
595 let inf: f128 = f128::INFINITY;
596 let neg_inf: f128 = f128::NEG_INFINITY;
597 assert_eq!(10.0f128.log10(), 1.0);
598 assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL);
599 assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL);
600 assert_eq!(1.0f128.log10(), 0.0);
601 assert!(nan.log10().is_nan());
602 assert_eq!(inf.log10(), inf);
603 assert!(neg_inf.log10().is_nan());
604 assert!((-2.3f128).log10().is_nan());
605 assert_eq!((-0.0f128).log10(), neg_inf);
606 assert_eq!(0.0f128.log10(), neg_inf);
607}
608
309609#[test]
310610fn test_to_degrees() {
311611 let pi: f128 = consts::PI;
......@@ -313,8 +613,8 @@ fn test_to_degrees() {
313613 let inf: f128 = f128::INFINITY;
314614 let neg_inf: f128 = f128::NEG_INFINITY;
315615 assert_eq!(0.0f128.to_degrees(), 0.0);
316 assert_approx_eq!((-5.8f128).to_degrees(), -332.315521);
317 assert_eq!(pi.to_degrees(), 180.0);
616 assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL);
617 assert_approx_eq!(pi.to_degrees(), 180.0, TOL);
318618 assert!(nan.to_degrees().is_nan());
319619 assert_eq!(inf.to_degrees(), inf);
320620 assert_eq!(neg_inf.to_degrees(), neg_inf);
......@@ -328,19 +628,122 @@ fn test_to_radians() {
328628 let inf: f128 = f128::INFINITY;
329629 let neg_inf: f128 = f128::NEG_INFINITY;
330630 assert_eq!(0.0f128.to_radians(), 0.0);
331 assert_approx_eq!(154.6f128.to_radians(), 2.698279);
332 assert_approx_eq!((-332.31f128).to_radians(), -5.799903);
631 assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL);
632 assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL);
333633 // check approx rather than exact because round trip for pi doesn't fall on an exactly
334634 // representable value (unlike `f32` and `f64`).
335 assert_approx_eq!(180.0f128.to_radians(), pi);
635 assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE);
336636 assert!(nan.to_radians().is_nan());
337637 assert_eq!(inf.to_radians(), inf);
338638 assert_eq!(neg_inf.to_radians(), neg_inf);
339639}
340640
641#[test]
642#[cfg(reliable_f128_math)]
643fn test_asinh() {
644 // Lower accuracy results are allowed, use increased tolerances
645 assert_eq!(0.0f128.asinh(), 0.0f128);
646 assert_eq!((-0.0f128).asinh(), -0.0f128);
647
648 let inf: f128 = f128::INFINITY;
649 let neg_inf: f128 = f128::NEG_INFINITY;
650 let nan: f128 = f128::NAN;
651 assert_eq!(inf.asinh(), inf);
652 assert_eq!(neg_inf.asinh(), neg_inf);
653 assert!(nan.asinh().is_nan());
654 assert!((-0.0f128).asinh().is_sign_negative());
655
656 // issue 63271
657 assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR);
658 assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR);
659 // regression test for the catastrophic cancellation fixed in 72486
660 assert_approx_eq!(
661 (-67452098.07139316f128).asinh(),
662 -18.720075426274544393985484294000831757220,
663 TOL_IMPR
664 );
665
666 // test for low accuracy from issue 104548
667 assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR);
668 // mul needed for approximate comparison to be meaningful
669 assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR);
670}
671
672#[test]
673#[cfg(reliable_f128_math)]
674fn test_acosh() {
675 assert_eq!(1.0f128.acosh(), 0.0f128);
676 assert!(0.999f128.acosh().is_nan());
677
678 let inf: f128 = f128::INFINITY;
679 let neg_inf: f128 = f128::NEG_INFINITY;
680 let nan: f128 = f128::NAN;
681 assert_eq!(inf.acosh(), inf);
682 assert!(neg_inf.acosh().is_nan());
683 assert!(nan.acosh().is_nan());
684 assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR);
685 assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR);
686
687 // test for low accuracy from issue 104548
688 assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR);
689}
690
691#[test]
692#[cfg(reliable_f128_math)]
693fn test_atanh() {
694 assert_eq!(0.0f128.atanh(), 0.0f128);
695 assert_eq!((-0.0f128).atanh(), -0.0f128);
696
697 let inf: f128 = f128::INFINITY;
698 let neg_inf: f128 = f128::NEG_INFINITY;
699 let nan: f128 = f128::NAN;
700 assert_eq!(1.0f128.atanh(), inf);
701 assert_eq!((-1.0f128).atanh(), neg_inf);
702 assert!(2f128.atanh().atanh().is_nan());
703 assert!((-2f128).atanh().atanh().is_nan());
704 assert!(inf.atanh().is_nan());
705 assert!(neg_inf.atanh().is_nan());
706 assert!(nan.atanh().is_nan());
707 assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR);
708 assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR);
709}
710
711#[test]
712#[cfg(reliable_f128_math)]
713fn test_gamma() {
714 // precision can differ among platforms
715 assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR);
716 assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR);
717 assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR);
718 assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR);
719 assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR);
720 assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR);
721 assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR);
722 assert_eq!(0.0f128.gamma(), f128::INFINITY);
723 assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY);
724 assert!((-1.0f128).gamma().is_nan());
725 assert!((-2.0f128).gamma().is_nan());
726 assert!(f128::NAN.gamma().is_nan());
727 assert!(f128::NEG_INFINITY.gamma().is_nan());
728 assert_eq!(f128::INFINITY.gamma(), f128::INFINITY);
729 assert_eq!(1760.9f128.gamma(), f128::INFINITY);
730}
731
732#[test]
733#[cfg(reliable_f128_math)]
734fn test_ln_gamma() {
735 assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR);
736 assert_eq!(1.0f128.ln_gamma().1, 1);
737 assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR);
738 assert_eq!(2.0f128.ln_gamma().1, 1);
739 assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR);
740 assert_eq!(3.0f128.ln_gamma().1, 1);
741 assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR);
742 assert_eq!((-0.5f128).ln_gamma().1, -1);
743}
744
341745#[test]
342746fn test_real_consts() {
343 // FIXME(f16_f128): add math tests when available
344747 use super::consts;
345748
346749 let pi: f128 = consts::PI;
......@@ -351,29 +754,34 @@ fn test_real_consts() {
351754 let frac_pi_8: f128 = consts::FRAC_PI_8;
352755 let frac_1_pi: f128 = consts::FRAC_1_PI;
353756 let frac_2_pi: f128 = consts::FRAC_2_PI;
354 // let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI;
355 // let sqrt2: f128 = consts::SQRT_2;
356 // let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2;
357 // let e: f128 = consts::E;
358 // let log2_e: f128 = consts::LOG2_E;
359 // let log10_e: f128 = consts::LOG10_E;
360 // let ln_2: f128 = consts::LN_2;
361 // let ln_10: f128 = consts::LN_10;
362
363 assert_approx_eq!(frac_pi_2, pi / 2f128);
364 assert_approx_eq!(frac_pi_3, pi / 3f128);
365 assert_approx_eq!(frac_pi_4, pi / 4f128);
366 assert_approx_eq!(frac_pi_6, pi / 6f128);
367 assert_approx_eq!(frac_pi_8, pi / 8f128);
368 assert_approx_eq!(frac_1_pi, 1f128 / pi);
369 assert_approx_eq!(frac_2_pi, 2f128 / pi);
370 // assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt());
371 // assert_approx_eq!(sqrt2, 2f128.sqrt());
372 // assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt());
373 // assert_approx_eq!(log2_e, e.log2());
374 // assert_approx_eq!(log10_e, e.log10());
375 // assert_approx_eq!(ln_2, 2f128.ln());
376 // assert_approx_eq!(ln_10, 10f128.ln());
757
758 assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE);
759 assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE);
760 assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE);
761 assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE);
762 assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE);
763 assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE);
764 assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE);
765
766 #[cfg(reliable_f128_math)]
767 {
768 let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI;
769 let sqrt2: f128 = consts::SQRT_2;
770 let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2;
771 let e: f128 = consts::E;
772 let log2_e: f128 = consts::LOG2_E;
773 let log10_e: f128 = consts::LOG10_E;
774 let ln_2: f128 = consts::LN_2;
775 let ln_10: f128 = consts::LN_10;
776
777 assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE);
778 assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE);
779 assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE);
780 assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE);
781 assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE);
782 assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE);
783 assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE);
784 }
377785}
378786
379787#[test]
......@@ -382,10 +790,10 @@ fn test_float_bits_conv() {
382790 assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000);
383791 assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000);
384792 assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000);
385 assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0);
386 assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5);
387 assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0);
388 assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25);
793 assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE);
794 assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE);
795 assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE);
796 assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE);
389797
390798 // Check that NaNs roundtrip their bits regardless of signaling-ness
391799 // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
library/std/src/f16.rs+1287-9
......@@ -12,25 +12,180 @@ pub use core::f16::consts;
1212
1313#[cfg(not(test))]
1414use crate::intrinsics;
15#[cfg(not(test))]
16use crate::sys::cmath;
1517
1618#[cfg(not(test))]
1719impl f16 {
18 /// Raises a number to an integer power.
20 /// Returns the largest integer less than or equal to `self`.
1921 ///
20 /// Using this function is generally faster than using `powf`.
21 /// It might have a different sequence of rounding operations than `powf`,
22 /// so the results are not guaranteed to agree.
22 /// This function always returns the precise result.
2323 ///
24 /// # Unspecified precision
24 /// # Examples
2525 ///
26 /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
27 /// can even differ within the same execution from one invocation to the next.
26 /// ```
27 /// #![feature(f16)]
28 /// # #[cfg(reliable_f16_math)] {
29 ///
30 /// let f = 3.7_f16;
31 /// let g = 3.0_f16;
32 /// let h = -3.7_f16;
33 ///
34 /// assert_eq!(f.floor(), 3.0);
35 /// assert_eq!(g.floor(), 3.0);
36 /// assert_eq!(h.floor(), -4.0);
37 /// # }
38 /// ```
2839 #[inline]
2940 #[rustc_allow_incoherent_impl]
3041 #[unstable(feature = "f16", issue = "116909")]
3142 #[must_use = "method returns a new number and does not mutate the original value"]
32 pub fn powi(self, n: i32) -> f16 {
33 unsafe { intrinsics::powif16(self, n) }
43 pub fn floor(self) -> f16 {
44 unsafe { intrinsics::floorf16(self) }
45 }
46
47 /// Returns the smallest integer greater than or equal to `self`.
48 ///
49 /// This function always returns the precise result.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// #![feature(f16)]
55 /// # #[cfg(reliable_f16_math)] {
56 ///
57 /// let f = 3.01_f16;
58 /// let g = 4.0_f16;
59 ///
60 /// assert_eq!(f.ceil(), 4.0);
61 /// assert_eq!(g.ceil(), 4.0);
62 /// # }
63 /// ```
64 #[inline]
65 #[doc(alias = "ceiling")]
66 #[rustc_allow_incoherent_impl]
67 #[unstable(feature = "f16", issue = "116909")]
68 #[must_use = "method returns a new number and does not mutate the original value"]
69 pub fn ceil(self) -> f16 {
70 unsafe { intrinsics::ceilf16(self) }
71 }
72
73 /// Returns the nearest integer to `self`. If a value is half-way between two
74 /// integers, round away from `0.0`.
75 ///
76 /// This function always returns the precise result.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// #![feature(f16)]
82 /// # #[cfg(reliable_f16_math)] {
83 ///
84 /// let f = 3.3_f16;
85 /// let g = -3.3_f16;
86 /// let h = -3.7_f16;
87 /// let i = 3.5_f16;
88 /// let j = 4.5_f16;
89 ///
90 /// assert_eq!(f.round(), 3.0);
91 /// assert_eq!(g.round(), -3.0);
92 /// assert_eq!(h.round(), -4.0);
93 /// assert_eq!(i.round(), 4.0);
94 /// assert_eq!(j.round(), 5.0);
95 /// # }
96 /// ```
97 #[inline]
98 #[rustc_allow_incoherent_impl]
99 #[unstable(feature = "f16", issue = "116909")]
100 #[must_use = "method returns a new number and does not mutate the original value"]
101 pub fn round(self) -> f16 {
102 unsafe { intrinsics::roundf16(self) }
103 }
104
105 /// Returns the nearest integer to a number. Rounds half-way cases to the number
106 /// with an even least significant digit.
107 ///
108 /// This function always returns the precise result.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// #![feature(f16)]
114 /// # #[cfg(reliable_f16_math)] {
115 ///
116 /// let f = 3.3_f16;
117 /// let g = -3.3_f16;
118 /// let h = 3.5_f16;
119 /// let i = 4.5_f16;
120 ///
121 /// assert_eq!(f.round_ties_even(), 3.0);
122 /// assert_eq!(g.round_ties_even(), -3.0);
123 /// assert_eq!(h.round_ties_even(), 4.0);
124 /// assert_eq!(i.round_ties_even(), 4.0);
125 /// # }
126 /// ```
127 #[inline]
128 #[rustc_allow_incoherent_impl]
129 #[unstable(feature = "f16", issue = "116909")]
130 #[must_use = "method returns a new number and does not mutate the original value"]
131 pub fn round_ties_even(self) -> f16 {
132 unsafe { intrinsics::rintf16(self) }
133 }
134
135 /// Returns the integer part of `self`.
136 /// This means that non-integer numbers are always truncated towards zero.
137 ///
138 /// This function always returns the precise result.
139 ///
140 /// # Examples
141 ///
142 /// ```
143 /// #![feature(f16)]
144 /// # #[cfg(reliable_f16_math)] {
145 ///
146 /// let f = 3.7_f16;
147 /// let g = 3.0_f16;
148 /// let h = -3.7_f16;
149 ///
150 /// assert_eq!(f.trunc(), 3.0);
151 /// assert_eq!(g.trunc(), 3.0);
152 /// assert_eq!(h.trunc(), -3.0);
153 /// # }
154 /// ```
155 #[inline]
156 #[doc(alias = "truncate")]
157 #[rustc_allow_incoherent_impl]
158 #[unstable(feature = "f16", issue = "116909")]
159 #[must_use = "method returns a new number and does not mutate the original value"]
160 pub fn trunc(self) -> f16 {
161 unsafe { intrinsics::truncf16(self) }
162 }
163
164 /// Returns the fractional part of `self`.
165 ///
166 /// This function always returns the precise result.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// #![feature(f16)]
172 /// # #[cfg(reliable_f16_math)] {
173 ///
174 /// let x = 3.6_f16;
175 /// let y = -3.6_f16;
176 /// let abs_difference_x = (x.fract() - 0.6).abs();
177 /// let abs_difference_y = (y.fract() - (-0.6)).abs();
178 ///
179 /// assert!(abs_difference_x <= f16::EPSILON);
180 /// assert!(abs_difference_y <= f16::EPSILON);
181 /// # }
182 /// ```
183 #[inline]
184 #[rustc_allow_incoherent_impl]
185 #[unstable(feature = "f16", issue = "116909")]
186 #[must_use = "method returns a new number and does not mutate the original value"]
187 pub fn fract(self) -> f16 {
188 self - self.trunc()
34189 }
35190
36191 /// Computes the absolute value of `self`.
......@@ -60,4 +215,1127 @@ impl f16 {
60215 // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
61216 Self::from_bits(self.to_bits() & !(1 << 15))
62217 }
218
219 /// Returns a number that represents the sign of `self`.
220 ///
221 /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
222 /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
223 /// - NaN if the number is NaN
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// #![feature(f16)]
229 /// # #[cfg(reliable_f16_math)] {
230 ///
231 /// let f = 3.5_f16;
232 ///
233 /// assert_eq!(f.signum(), 1.0);
234 /// assert_eq!(f16::NEG_INFINITY.signum(), -1.0);
235 ///
236 /// assert!(f16::NAN.signum().is_nan());
237 /// # }
238 /// ```
239 #[inline]
240 #[rustc_allow_incoherent_impl]
241 #[unstable(feature = "f16", issue = "116909")]
242 #[must_use = "method returns a new number and does not mutate the original value"]
243 pub fn signum(self) -> f16 {
244 if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) }
245 }
246
247 /// Returns a number composed of the magnitude of `self` and the sign of
248 /// `sign`.
249 ///
250 /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
251 /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
252 /// `sign` is returned. Note, however, that conserving the sign bit on NaN
253 /// across arithmetical operations is not generally guaranteed.
254 /// See [explanation of NaN as a special value](primitive@f16) for more info.
255 ///
256 /// # Examples
257 ///
258 /// ```
259 /// #![feature(f16)]
260 /// # #[cfg(reliable_f16_math)] {
261 ///
262 /// let f = 3.5_f16;
263 ///
264 /// assert_eq!(f.copysign(0.42), 3.5_f16);
265 /// assert_eq!(f.copysign(-0.42), -3.5_f16);
266 /// assert_eq!((-f).copysign(0.42), 3.5_f16);
267 /// assert_eq!((-f).copysign(-0.42), -3.5_f16);
268 ///
269 /// assert!(f16::NAN.copysign(1.0).is_nan());
270 /// # }
271 /// ```
272 #[inline]
273 #[rustc_allow_incoherent_impl]
274 #[unstable(feature = "f16", issue = "116909")]
275 #[must_use = "method returns a new number and does not mutate the original value"]
276 pub fn copysign(self, sign: f16) -> f16 {
277 unsafe { intrinsics::copysignf16(self, sign) }
278 }
279
280 /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
281 /// error, yielding a more accurate result than an unfused multiply-add.
282 ///
283 /// Using `mul_add` *may* be more performant than an unfused multiply-add if
284 /// the target architecture has a dedicated `fma` CPU instruction. However,
285 /// this is not always true, and will be heavily dependant on designing
286 /// algorithms with specific target hardware in mind.
287 ///
288 /// # Precision
289 ///
290 /// The result of this operation is guaranteed to be the rounded
291 /// infinite-precision result. It is specified by IEEE 754 as
292 /// `fusedMultiplyAdd` and guaranteed not to change.
293 ///
294 /// # Examples
295 ///
296 /// ```
297 /// #![feature(f16)]
298 /// # #[cfg(reliable_f16_math)] {
299 ///
300 /// let m = 10.0_f16;
301 /// let x = 4.0_f16;
302 /// let b = 60.0_f16;
303 ///
304 /// assert_eq!(m.mul_add(x, b), 100.0);
305 /// assert_eq!(m * x + b, 100.0);
306 ///
307 /// let one_plus_eps = 1.0_f16 + f16::EPSILON;
308 /// let one_minus_eps = 1.0_f16 - f16::EPSILON;
309 /// let minus_one = -1.0_f16;
310 ///
311 /// // The exact result (1 + eps) * (1 - eps) = 1 - eps * eps.
312 /// assert_eq!(one_plus_eps.mul_add(one_minus_eps, minus_one), -f16::EPSILON * f16::EPSILON);
313 /// // Different rounding with the non-fused multiply and add.
314 /// assert_eq!(one_plus_eps * one_minus_eps + minus_one, 0.0);
315 /// # }
316 /// ```
317 #[inline]
318 #[rustc_allow_incoherent_impl]
319 #[unstable(feature = "f16", issue = "116909")]
320 #[must_use = "method returns a new number and does not mutate the original value"]
321 pub fn mul_add(self, a: f16, b: f16) -> f16 {
322 unsafe { intrinsics::fmaf16(self, a, b) }
323 }
324
325 /// Calculates Euclidean division, the matching method for `rem_euclid`.
326 ///
327 /// This computes the integer `n` such that
328 /// `self = n * rhs + self.rem_euclid(rhs)`.
329 /// In other words, the result is `self / rhs` rounded to the integer `n`
330 /// such that `self >= n * rhs`.
331 ///
332 /// # Precision
333 ///
334 /// The result of this operation is guaranteed to be the rounded
335 /// infinite-precision result.
336 ///
337 /// # Examples
338 ///
339 /// ```
340 /// #![feature(f16)]
341 /// # #[cfg(reliable_f16_math)] {
342 ///
343 /// let a: f16 = 7.0;
344 /// let b = 4.0;
345 /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0
346 /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0
347 /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
348 /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
349 /// # }
350 /// ```
351 #[inline]
352 #[rustc_allow_incoherent_impl]
353 #[unstable(feature = "f16", issue = "116909")]
354 #[must_use = "method returns a new number and does not mutate the original value"]
355 pub fn div_euclid(self, rhs: f16) -> f16 {
356 let q = (self / rhs).trunc();
357 if self % rhs < 0.0 {
358 return if rhs > 0.0 { q - 1.0 } else { q + 1.0 };
359 }
360 q
361 }
362
363 /// Calculates the least nonnegative remainder of `self (mod rhs)`.
364 ///
365 /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
366 /// most cases. However, due to a floating point round-off error it can
367 /// result in `r == rhs.abs()`, violating the mathematical definition, if
368 /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
369 /// This result is not an element of the function's codomain, but it is the
370 /// closest floating point number in the real numbers and thus fulfills the
371 /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
372 /// approximately.
373 ///
374 /// # Precision
375 ///
376 /// The result of this operation is guaranteed to be the rounded
377 /// infinite-precision result.
378 ///
379 /// # Examples
380 ///
381 /// ```
382 /// #![feature(f16)]
383 /// # #[cfg(reliable_f16_math)] {
384 ///
385 /// let a: f16 = 7.0;
386 /// let b = 4.0;
387 /// assert_eq!(a.rem_euclid(b), 3.0);
388 /// assert_eq!((-a).rem_euclid(b), 1.0);
389 /// assert_eq!(a.rem_euclid(-b), 3.0);
390 /// assert_eq!((-a).rem_euclid(-b), 1.0);
391 /// // limitation due to round-off error
392 /// assert!((-f16::EPSILON).rem_euclid(3.0) != 0.0);
393 /// # }
394 /// ```
395 #[inline]
396 #[rustc_allow_incoherent_impl]
397 #[doc(alias = "modulo", alias = "mod")]
398 #[unstable(feature = "f16", issue = "116909")]
399 #[must_use = "method returns a new number and does not mutate the original value"]
400 pub fn rem_euclid(self, rhs: f16) -> f16 {
401 let r = self % rhs;
402 if r < 0.0 { r + rhs.abs() } else { r }
403 }
404
405 /// Raises a number to an integer power.
406 ///
407 /// Using this function is generally faster than using `powf`.
408 /// It might have a different sequence of rounding operations than `powf`,
409 /// so the results are not guaranteed to agree.
410 ///
411 /// # Unspecified precision
412 ///
413 /// The precision of this function is non-deterministic. This means it varies by platform,
414 /// Rust version, and can even differ within the same execution from one invocation to the next.
415 #[inline]
416 #[rustc_allow_incoherent_impl]
417 #[unstable(feature = "f16", issue = "116909")]
418 #[must_use = "method returns a new number and does not mutate the original value"]
419 pub fn powi(self, n: i32) -> f16 {
420 unsafe { intrinsics::powif16(self, n) }
421 }
422
423 /// Raises a number to a floating point power.
424 ///
425 /// # Unspecified precision
426 ///
427 /// The precision of this function is non-deterministic. This means it varies by platform,
428 /// Rust version, and can even differ within the same execution from one invocation to the next.
429 ///
430 /// # Examples
431 ///
432 /// ```
433 /// #![feature(f16)]
434 /// # #[cfg(reliable_f16_math)] {
435 ///
436 /// let x = 2.0_f16;
437 /// let abs_difference = (x.powf(2.0) - (x * x)).abs();
438 ///
439 /// assert!(abs_difference <= f16::EPSILON);
440 /// # }
441 /// ```
442 #[inline]
443 #[rustc_allow_incoherent_impl]
444 #[unstable(feature = "f16", issue = "116909")]
445 #[must_use = "method returns a new number and does not mutate the original value"]
446 pub fn powf(self, n: f16) -> f16 {
447 unsafe { intrinsics::powf16(self, n) }
448 }
449
450 /// Returns the square root of a number.
451 ///
452 /// Returns NaN if `self` is a negative number other than `-0.0`.
453 ///
454 /// # Precision
455 ///
456 /// The result of this operation is guaranteed to be the rounded
457 /// infinite-precision result. It is specified by IEEE 754 as `squareRoot`
458 /// and guaranteed not to change.
459 ///
460 /// # Examples
461 ///
462 /// ```
463 /// #![feature(f16)]
464 /// # #[cfg(reliable_f16_math)] {
465 ///
466 /// let positive = 4.0_f16;
467 /// let negative = -4.0_f16;
468 /// let negative_zero = -0.0_f16;
469 ///
470 /// assert_eq!(positive.sqrt(), 2.0);
471 /// assert!(negative.sqrt().is_nan());
472 /// assert!(negative_zero.sqrt() == negative_zero);
473 /// # }
474 /// ```
475 #[inline]
476 #[rustc_allow_incoherent_impl]
477 #[unstable(feature = "f16", issue = "116909")]
478 #[must_use = "method returns a new number and does not mutate the original value"]
479 pub fn sqrt(self) -> f16 {
480 unsafe { intrinsics::sqrtf16(self) }
481 }
482
483 /// Returns `e^(self)`, (the exponential function).
484 ///
485 /// # Unspecified precision
486 ///
487 /// The precision of this function is non-deterministic. This means it varies by platform,
488 /// Rust version, and can even differ within the same execution from one invocation to the next.
489 ///
490 /// # Examples
491 ///
492 /// ```
493 /// #![feature(f16)]
494 /// # #[cfg(reliable_f16_math)] {
495 ///
496 /// let one = 1.0f16;
497 /// // e^1
498 /// let e = one.exp();
499 ///
500 /// // ln(e) - 1 == 0
501 /// let abs_difference = (e.ln() - 1.0).abs();
502 ///
503 /// assert!(abs_difference <= f16::EPSILON);
504 /// # }
505 /// ```
506 #[inline]
507 #[rustc_allow_incoherent_impl]
508 #[unstable(feature = "f16", issue = "116909")]
509 #[must_use = "method returns a new number and does not mutate the original value"]
510 pub fn exp(self) -> f16 {
511 unsafe { intrinsics::expf16(self) }
512 }
513
514 /// Returns `2^(self)`.
515 ///
516 /// # Unspecified precision
517 ///
518 /// The precision of this function is non-deterministic. This means it varies by platform,
519 /// Rust version, and can even differ within the same execution from one invocation to the next.
520 ///
521 /// # Examples
522 ///
523 /// ```
524 /// #![feature(f16)]
525 /// # #[cfg(reliable_f16_math)] {
526 ///
527 /// let f = 2.0f16;
528 ///
529 /// // 2^2 - 4 == 0
530 /// let abs_difference = (f.exp2() - 4.0).abs();
531 ///
532 /// assert!(abs_difference <= f16::EPSILON);
533 /// # }
534 /// ```
535 #[inline]
536 #[rustc_allow_incoherent_impl]
537 #[unstable(feature = "f16", issue = "116909")]
538 #[must_use = "method returns a new number and does not mutate the original value"]
539 pub fn exp2(self) -> f16 {
540 unsafe { intrinsics::exp2f16(self) }
541 }
542
543 /// Returns the natural logarithm of the number.
544 ///
545 /// # Unspecified precision
546 ///
547 /// The precision of this function is non-deterministic. This means it varies by platform,
548 /// Rust version, and can even differ within the same execution from one invocation to the next.
549 ///
550 /// # Examples
551 ///
552 /// ```
553 /// #![feature(f16)]
554 /// # #[cfg(reliable_f16_math)] {
555 ///
556 /// let one = 1.0f16;
557 /// // e^1
558 /// let e = one.exp();
559 ///
560 /// // ln(e) - 1 == 0
561 /// let abs_difference = (e.ln() - 1.0).abs();
562 ///
563 /// assert!(abs_difference <= f16::EPSILON);
564 /// # }
565 /// ```
566 #[inline]
567 #[rustc_allow_incoherent_impl]
568 #[unstable(feature = "f16", issue = "116909")]
569 #[must_use = "method returns a new number and does not mutate the original value"]
570 pub fn ln(self) -> f16 {
571 unsafe { intrinsics::logf16(self) }
572 }
573
574 /// Returns the logarithm of the number with respect to an arbitrary base.
575 ///
576 /// The result might not be correctly rounded owing to implementation details;
577 /// `self.log2()` can produce more accurate results for base 2, and
578 /// `self.log10()` can produce more accurate results for base 10.
579 ///
580 /// # Unspecified precision
581 ///
582 /// The precision of this function is non-deterministic. This means it varies by platform,
583 /// Rust version, and can even differ within the same execution from one invocation to the next.
584 ///
585 /// # Examples
586 ///
587 /// ```
588 /// #![feature(f16)]
589 /// # #[cfg(reliable_f16_math)] {
590 ///
591 /// let five = 5.0f16;
592 ///
593 /// // log5(5) - 1 == 0
594 /// let abs_difference = (five.log(5.0) - 1.0).abs();
595 ///
596 /// assert!(abs_difference <= f16::EPSILON);
597 /// # }
598 /// ```
599 #[inline]
600 #[rustc_allow_incoherent_impl]
601 #[unstable(feature = "f16", issue = "116909")]
602 #[must_use = "method returns a new number and does not mutate the original value"]
603 pub fn log(self, base: f16) -> f16 {
604 self.ln() / base.ln()
605 }
606
607 /// Returns the base 2 logarithm of the number.
608 ///
609 /// # Unspecified precision
610 ///
611 /// The precision of this function is non-deterministic. This means it varies by platform,
612 /// Rust version, and can even differ within the same execution from one invocation to the next.
613 ///
614 /// # Examples
615 ///
616 /// ```
617 /// #![feature(f16)]
618 /// # #[cfg(reliable_f16_math)] {
619 ///
620 /// let two = 2.0f16;
621 ///
622 /// // log2(2) - 1 == 0
623 /// let abs_difference = (two.log2() - 1.0).abs();
624 ///
625 /// assert!(abs_difference <= f16::EPSILON);
626 /// # }
627 /// ```
628 #[inline]
629 #[rustc_allow_incoherent_impl]
630 #[unstable(feature = "f16", issue = "116909")]
631 #[must_use = "method returns a new number and does not mutate the original value"]
632 pub fn log2(self) -> f16 {
633 unsafe { intrinsics::log2f16(self) }
634 }
635
636 /// Returns the base 10 logarithm of the number.
637 ///
638 /// # Unspecified precision
639 ///
640 /// The precision of this function is non-deterministic. This means it varies by platform,
641 /// Rust version, and can even differ within the same execution from one invocation to the next.
642 ///
643 /// # Examples
644 ///
645 /// ```
646 /// #![feature(f16)]
647 /// # #[cfg(reliable_f16_math)] {
648 ///
649 /// let ten = 10.0f16;
650 ///
651 /// // log10(10) - 1 == 0
652 /// let abs_difference = (ten.log10() - 1.0).abs();
653 ///
654 /// assert!(abs_difference <= f16::EPSILON);
655 /// # }
656 /// ```
657 #[inline]
658 #[rustc_allow_incoherent_impl]
659 #[unstable(feature = "f16", issue = "116909")]
660 #[must_use = "method returns a new number and does not mutate the original value"]
661 pub fn log10(self) -> f16 {
662 unsafe { intrinsics::log10f16(self) }
663 }
664
665 /// Returns the cube root of a number.
666 ///
667 /// # Unspecified precision
668 ///
669 /// The precision of this function is non-deterministic. This means it varies by platform,
670 /// Rust version, and can even differ within the same execution from one invocation to the next.
671 ///
672 /// This function currently corresponds to the `cbrtf` from libc on Unix
673 /// and Windows. Note that this might change in the future.
674 ///
675 /// # Examples
676 ///
677 /// ```
678 /// #![feature(f16)]
679 /// # #[cfg(reliable_f16_math)] {
680 ///
681 /// let x = 8.0f16;
682 ///
683 /// // x^(1/3) - 2 == 0
684 /// let abs_difference = (x.cbrt() - 2.0).abs();
685 ///
686 /// assert!(abs_difference <= f16::EPSILON);
687 /// # }
688 /// ```
689 #[inline]
690 #[rustc_allow_incoherent_impl]
691 #[unstable(feature = "f16", issue = "116909")]
692 #[must_use = "method returns a new number and does not mutate the original value"]
693 pub fn cbrt(self) -> f16 {
694 (unsafe { cmath::cbrtf(self as f32) }) as f16
695 }
696
697 /// Compute the distance between the origin and a point (`x`, `y`) on the
698 /// Euclidean plane. Equivalently, compute the length of the hypotenuse of a
699 /// right-angle triangle with other sides having length `x.abs()` and
700 /// `y.abs()`.
701 ///
702 /// # Unspecified precision
703 ///
704 /// The precision of this function is non-deterministic. This means it varies by platform,
705 /// Rust version, and can even differ within the same execution from one invocation to the next.
706 ///
707 /// This function currently corresponds to the `hypotf` from libc on Unix
708 /// and Windows. Note that this might change in the future.
709 ///
710 /// # Examples
711 ///
712 /// ```
713 /// #![feature(f16)]
714 /// # #[cfg(reliable_f16_math)] {
715 ///
716 /// let x = 2.0f16;
717 /// let y = 3.0f16;
718 ///
719 /// // sqrt(x^2 + y^2)
720 /// let abs_difference = (x.hypot(y) - (x.powi(2) + y.powi(2)).sqrt()).abs();
721 ///
722 /// assert!(abs_difference <= f16::EPSILON);
723 /// # }
724 /// ```
725 #[inline]
726 #[rustc_allow_incoherent_impl]
727 #[unstable(feature = "f16", issue = "116909")]
728 #[must_use = "method returns a new number and does not mutate the original value"]
729 pub fn hypot(self, other: f16) -> f16 {
730 (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16
731 }
732
733 /// Computes the sine of a number (in radians).
734 ///
735 /// # Unspecified precision
736 ///
737 /// The precision of this function is non-deterministic. This means it varies by platform,
738 /// Rust version, and can even differ within the same execution from one invocation to the next.
739 ///
740 /// # Examples
741 ///
742 /// ```
743 /// #![feature(f16)]
744 /// # #[cfg(reliable_f16_math)] {
745 ///
746 /// let x = std::f16::consts::FRAC_PI_2;
747 ///
748 /// let abs_difference = (x.sin() - 1.0).abs();
749 ///
750 /// assert!(abs_difference <= f16::EPSILON);
751 /// # }
752 /// ```
753 #[inline]
754 #[rustc_allow_incoherent_impl]
755 #[unstable(feature = "f16", issue = "116909")]
756 #[must_use = "method returns a new number and does not mutate the original value"]
757 pub fn sin(self) -> f16 {
758 unsafe { intrinsics::sinf16(self) }
759 }
760
761 /// Computes the cosine of a number (in radians).
762 ///
763 /// # Unspecified precision
764 ///
765 /// The precision of this function is non-deterministic. This means it varies by platform,
766 /// Rust version, and can even differ within the same execution from one invocation to the next.
767 ///
768 /// # Examples
769 ///
770 /// ```
771 /// #![feature(f16)]
772 /// # #[cfg(reliable_f16_math)] {
773 ///
774 /// let x = 2.0 * std::f16::consts::PI;
775 ///
776 /// let abs_difference = (x.cos() - 1.0).abs();
777 ///
778 /// assert!(abs_difference <= f16::EPSILON);
779 /// # }
780 /// ```
781 #[inline]
782 #[rustc_allow_incoherent_impl]
783 #[unstable(feature = "f16", issue = "116909")]
784 #[must_use = "method returns a new number and does not mutate the original value"]
785 pub fn cos(self) -> f16 {
786 unsafe { intrinsics::cosf16(self) }
787 }
788
789 /// Computes the tangent of a number (in radians).
790 ///
791 /// # Unspecified precision
792 ///
793 /// The precision of this function is non-deterministic. This means it varies by platform,
794 /// Rust version, and can even differ within the same execution from one invocation to the next.
795 ///
796 /// This function currently corresponds to the `tanf` from libc on Unix and
797 /// Windows. Note that this might change in the future.
798 ///
799 /// # Examples
800 ///
801 /// ```
802 /// #![feature(f16)]
803 /// # #[cfg(reliable_f16_math)] {
804 ///
805 /// let x = std::f16::consts::FRAC_PI_4;
806 /// let abs_difference = (x.tan() - 1.0).abs();
807 ///
808 /// assert!(abs_difference <= f16::EPSILON);
809 /// # }
810 /// ```
811 #[inline]
812 #[rustc_allow_incoherent_impl]
813 #[unstable(feature = "f16", issue = "116909")]
814 #[must_use = "method returns a new number and does not mutate the original value"]
815 pub fn tan(self) -> f16 {
816 (unsafe { cmath::tanf(self as f32) }) as f16
817 }
818
819 /// Computes the arcsine of a number. Return value is in radians in
820 /// the range [-pi/2, pi/2] or NaN if the number is outside the range
821 /// [-1, 1].
822 ///
823 /// # Unspecified precision
824 ///
825 /// The precision of this function is non-deterministic. This means it varies by platform,
826 /// Rust version, and can even differ within the same execution from one invocation to the next.
827 ///
828 /// This function currently corresponds to the `asinf` from libc on Unix
829 /// and Windows. Note that this might change in the future.
830 ///
831 /// # Examples
832 ///
833 /// ```
834 /// #![feature(f16)]
835 /// # #[cfg(reliable_f16_math)] {
836 ///
837 /// let f = std::f16::consts::FRAC_PI_2;
838 ///
839 /// // asin(sin(pi/2))
840 /// let abs_difference = (f.sin().asin() - std::f16::consts::FRAC_PI_2).abs();
841 ///
842 /// assert!(abs_difference <= f16::EPSILON);
843 /// # }
844 /// ```
845 #[inline]
846 #[doc(alias = "arcsin")]
847 #[rustc_allow_incoherent_impl]
848 #[unstable(feature = "f16", issue = "116909")]
849 #[must_use = "method returns a new number and does not mutate the original value"]
850 pub fn asin(self) -> f16 {
851 (unsafe { cmath::asinf(self as f32) }) as f16
852 }
853
854 /// Computes the arccosine of a number. Return value is in radians in
855 /// the range [0, pi] or NaN if the number is outside the range
856 /// [-1, 1].
857 ///
858 /// # Unspecified precision
859 ///
860 /// The precision of this function is non-deterministic. This means it varies by platform,
861 /// Rust version, and can even differ within the same execution from one invocation to the next.
862 ///
863 /// This function currently corresponds to the `acosf` from libc on Unix
864 /// and Windows. Note that this might change in the future.
865 ///
866 /// # Examples
867 ///
868 /// ```
869 /// #![feature(f16)]
870 /// # #[cfg(reliable_f16_math)] {
871 ///
872 /// let f = std::f16::consts::FRAC_PI_4;
873 ///
874 /// // acos(cos(pi/4))
875 /// let abs_difference = (f.cos().acos() - std::f16::consts::FRAC_PI_4).abs();
876 ///
877 /// assert!(abs_difference <= f16::EPSILON);
878 /// # }
879 /// ```
880 #[inline]
881 #[doc(alias = "arccos")]
882 #[rustc_allow_incoherent_impl]
883 #[unstable(feature = "f16", issue = "116909")]
884 #[must_use = "method returns a new number and does not mutate the original value"]
885 pub fn acos(self) -> f16 {
886 (unsafe { cmath::acosf(self as f32) }) as f16
887 }
888
889 /// Computes the arctangent of a number. Return value is in radians in the
890 /// range [-pi/2, pi/2];
891 ///
892 /// # Unspecified precision
893 ///
894 /// The precision of this function is non-deterministic. This means it varies by platform,
895 /// Rust version, and can even differ within the same execution from one invocation to the next.
896 ///
897 /// This function currently corresponds to the `atanf` from libc on Unix
898 /// and Windows. Note that this might change in the future.
899 ///
900 /// # Examples
901 ///
902 /// ```
903 /// #![feature(f16)]
904 /// # #[cfg(reliable_f16_math)] {
905 ///
906 /// let f = 1.0f16;
907 ///
908 /// // atan(tan(1))
909 /// let abs_difference = (f.tan().atan() - 1.0).abs();
910 ///
911 /// assert!(abs_difference <= f16::EPSILON);
912 /// # }
913 /// ```
914 #[inline]
915 #[doc(alias = "arctan")]
916 #[rustc_allow_incoherent_impl]
917 #[unstable(feature = "f16", issue = "116909")]
918 #[must_use = "method returns a new number and does not mutate the original value"]
919 pub fn atan(self) -> f16 {
920 (unsafe { cmath::atanf(self as f32) }) as f16
921 }
922
923 /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
924 ///
925 /// * `x = 0`, `y = 0`: `0`
926 /// * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]`
927 /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
928 /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
929 ///
930 /// # Unspecified precision
931 ///
932 /// The precision of this function is non-deterministic. This means it varies by platform,
933 /// Rust version, and can even differ within the same execution from one invocation to the next.
934 ///
935 /// This function currently corresponds to the `atan2f` from libc on Unix
936 /// and Windows. Note that this might change in the future.
937 ///
938 /// # Examples
939 ///
940 /// ```
941 /// #![feature(f16)]
942 /// # #[cfg(reliable_f16_math)] {
943 ///
944 /// // Positive angles measured counter-clockwise
945 /// // from positive x axis
946 /// // -pi/4 radians (45 deg clockwise)
947 /// let x1 = 3.0f16;
948 /// let y1 = -3.0f16;
949 ///
950 /// // 3pi/4 radians (135 deg counter-clockwise)
951 /// let x2 = -3.0f16;
952 /// let y2 = 3.0f16;
953 ///
954 /// let abs_difference_1 = (y1.atan2(x1) - (-std::f16::consts::FRAC_PI_4)).abs();
955 /// let abs_difference_2 = (y2.atan2(x2) - (3.0 * std::f16::consts::FRAC_PI_4)).abs();
956 ///
957 /// assert!(abs_difference_1 <= f16::EPSILON);
958 /// assert!(abs_difference_2 <= f16::EPSILON);
959 /// # }
960 /// ```
961 #[inline]
962 #[rustc_allow_incoherent_impl]
963 #[unstable(feature = "f16", issue = "116909")]
964 #[must_use = "method returns a new number and does not mutate the original value"]
965 pub fn atan2(self, other: f16) -> f16 {
966 (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16
967 }
968
969 /// Simultaneously computes the sine and cosine of the number, `x`. Returns
970 /// `(sin(x), cos(x))`.
971 ///
972 /// # Unspecified precision
973 ///
974 /// The precision of this function is non-deterministic. This means it varies by platform,
975 /// Rust version, and can even differ within the same execution from one invocation to the next.
976 ///
977 /// This function currently corresponds to the `(f16::sin(x),
978 /// f16::cos(x))`. Note that this might change in the future.
979 ///
980 /// # Examples
981 ///
982 /// ```
983 /// #![feature(f16)]
984 /// # #[cfg(reliable_f16_math)] {
985 ///
986 /// let x = std::f16::consts::FRAC_PI_4;
987 /// let f = x.sin_cos();
988 ///
989 /// let abs_difference_0 = (f.0 - x.sin()).abs();
990 /// let abs_difference_1 = (f.1 - x.cos()).abs();
991 ///
992 /// assert!(abs_difference_0 <= f16::EPSILON);
993 /// assert!(abs_difference_1 <= f16::EPSILON);
994 /// # }
995 /// ```
996 #[inline]
997 #[doc(alias = "sincos")]
998 #[rustc_allow_incoherent_impl]
999 #[unstable(feature = "f16", issue = "116909")]
1000 pub fn sin_cos(self) -> (f16, f16) {
1001 (self.sin(), self.cos())
1002 }
1003
1004 /// Returns `e^(self) - 1` in a way that is accurate even if the
1005 /// number is close to zero.
1006 ///
1007 /// # Unspecified precision
1008 ///
1009 /// The precision of this function is non-deterministic. This means it varies by platform,
1010 /// Rust version, and can even differ within the same execution from one invocation to the next.
1011 ///
1012 /// This function currently corresponds to the `expm1f` from libc on Unix
1013 /// and Windows. Note that this might change in the future.
1014 ///
1015 /// # Examples
1016 ///
1017 /// ```
1018 /// #![feature(f16)]
1019 /// # #[cfg(reliable_f16_math)] {
1020 ///
1021 /// let x = 1e-4_f16;
1022 ///
1023 /// // for very small x, e^x is approximately 1 + x + x^2 / 2
1024 /// let approx = x + x * x / 2.0;
1025 /// let abs_difference = (x.exp_m1() - approx).abs();
1026 ///
1027 /// assert!(abs_difference < 1e-4);
1028 /// # }
1029 /// ```
1030 #[inline]
1031 #[rustc_allow_incoherent_impl]
1032 #[unstable(feature = "f16", issue = "116909")]
1033 #[must_use = "method returns a new number and does not mutate the original value"]
1034 pub fn exp_m1(self) -> f16 {
1035 (unsafe { cmath::expm1f(self as f32) }) as f16
1036 }
1037
1038 /// Returns `ln(1+n)` (natural logarithm) more accurately than if
1039 /// the operations were performed separately.
1040 ///
1041 /// # Unspecified precision
1042 ///
1043 /// The precision of this function is non-deterministic. This means it varies by platform,
1044 /// Rust version, and can even differ within the same execution from one invocation to the next.
1045 ///
1046 /// This function currently corresponds to the `log1pf` from libc on Unix
1047 /// and Windows. Note that this might change in the future.
1048 ///
1049 /// # Examples
1050 ///
1051 /// ```
1052 /// #![feature(f16)]
1053 /// # #[cfg(reliable_f16_math)] {
1054 ///
1055 /// let x = 1e-4_f16;
1056 ///
1057 /// // for very small x, ln(1 + x) is approximately x - x^2 / 2
1058 /// let approx = x - x * x / 2.0;
1059 /// let abs_difference = (x.ln_1p() - approx).abs();
1060 ///
1061 /// assert!(abs_difference < 1e-4);
1062 /// # }
1063 /// ```
1064 #[inline]
1065 #[doc(alias = "log1p")]
1066 #[rustc_allow_incoherent_impl]
1067 #[unstable(feature = "f16", issue = "116909")]
1068 #[must_use = "method returns a new number and does not mutate the original value"]
1069 pub fn ln_1p(self) -> f16 {
1070 (unsafe { cmath::log1pf(self as f32) }) as f16
1071 }
1072
1073 /// Hyperbolic sine function.
1074 ///
1075 /// # Unspecified precision
1076 ///
1077 /// The precision of this function is non-deterministic. This means it varies by platform,
1078 /// Rust version, and can even differ within the same execution from one invocation to the next.
1079 ///
1080 /// This function currently corresponds to the `sinhf` from libc on Unix
1081 /// and Windows. Note that this might change in the future.
1082 ///
1083 /// # Examples
1084 ///
1085 /// ```
1086 /// #![feature(f16)]
1087 /// # #[cfg(reliable_f16_math)] {
1088 ///
1089 /// let e = std::f16::consts::E;
1090 /// let x = 1.0f16;
1091 ///
1092 /// let f = x.sinh();
1093 /// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
1094 /// let g = ((e * e) - 1.0) / (2.0 * e);
1095 /// let abs_difference = (f - g).abs();
1096 ///
1097 /// assert!(abs_difference <= f16::EPSILON);
1098 /// # }
1099 /// ```
1100 #[inline]
1101 #[rustc_allow_incoherent_impl]
1102 #[unstable(feature = "f16", issue = "116909")]
1103 #[must_use = "method returns a new number and does not mutate the original value"]
1104 pub fn sinh(self) -> f16 {
1105 (unsafe { cmath::sinhf(self as f32) }) as f16
1106 }
1107
1108 /// Hyperbolic cosine function.
1109 ///
1110 /// # Unspecified precision
1111 ///
1112 /// The precision of this function is non-deterministic. This means it varies by platform,
1113 /// Rust version, and can even differ within the same execution from one invocation to the next.
1114 ///
1115 /// This function currently corresponds to the `coshf` from libc on Unix
1116 /// and Windows. Note that this might change in the future.
1117 ///
1118 /// # Examples
1119 ///
1120 /// ```
1121 /// #![feature(f16)]
1122 /// # #[cfg(reliable_f16_math)] {
1123 ///
1124 /// let e = std::f16::consts::E;
1125 /// let x = 1.0f16;
1126 /// let f = x.cosh();
1127 /// // Solving cosh() at 1 gives this result
1128 /// let g = ((e * e) + 1.0) / (2.0 * e);
1129 /// let abs_difference = (f - g).abs();
1130 ///
1131 /// // Same result
1132 /// assert!(abs_difference <= f16::EPSILON);
1133 /// # }
1134 /// ```
1135 #[inline]
1136 #[rustc_allow_incoherent_impl]
1137 #[unstable(feature = "f16", issue = "116909")]
1138 #[must_use = "method returns a new number and does not mutate the original value"]
1139 pub fn cosh(self) -> f16 {
1140 (unsafe { cmath::coshf(self as f32) }) as f16
1141 }
1142
1143 /// Hyperbolic tangent function.
1144 ///
1145 /// # Unspecified precision
1146 ///
1147 /// The precision of this function is non-deterministic. This means it varies by platform,
1148 /// Rust version, and can even differ within the same execution from one invocation to the next.
1149 ///
1150 /// This function currently corresponds to the `tanhf` from libc on Unix
1151 /// and Windows. Note that this might change in the future.
1152 ///
1153 /// # Examples
1154 ///
1155 /// ```
1156 /// #![feature(f16)]
1157 /// # #[cfg(reliable_f16_math)] {
1158 ///
1159 /// let e = std::f16::consts::E;
1160 /// let x = 1.0f16;
1161 ///
1162 /// let f = x.tanh();
1163 /// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
1164 /// let g = (1.0 - e.powi(-2)) / (1.0 + e.powi(-2));
1165 /// let abs_difference = (f - g).abs();
1166 ///
1167 /// assert!(abs_difference <= f16::EPSILON);
1168 /// # }
1169 /// ```
1170 #[inline]
1171 #[rustc_allow_incoherent_impl]
1172 #[unstable(feature = "f16", issue = "116909")]
1173 #[must_use = "method returns a new number and does not mutate the original value"]
1174 pub fn tanh(self) -> f16 {
1175 (unsafe { cmath::tanhf(self as f32) }) as f16
1176 }
1177
1178 /// Inverse hyperbolic sine function.
1179 ///
1180 /// # Unspecified precision
1181 ///
1182 /// The precision of this function is non-deterministic. This means it varies by platform,
1183 /// Rust version, and can even differ within the same execution from one invocation to the next.
1184 ///
1185 /// # Examples
1186 ///
1187 /// ```
1188 /// #![feature(f16)]
1189 /// # #[cfg(reliable_f16_math)] {
1190 ///
1191 /// let x = 1.0f16;
1192 /// let f = x.sinh().asinh();
1193 ///
1194 /// let abs_difference = (f - x).abs();
1195 ///
1196 /// assert!(abs_difference <= f16::EPSILON);
1197 /// # }
1198 /// ```
1199 #[inline]
1200 #[doc(alias = "arcsinh")]
1201 #[rustc_allow_incoherent_impl]
1202 #[unstable(feature = "f16", issue = "116909")]
1203 #[must_use = "method returns a new number and does not mutate the original value"]
1204 pub fn asinh(self) -> f16 {
1205 let ax = self.abs();
1206 let ix = 1.0 / ax;
1207 (ax + (ax / (Self::hypot(1.0, ix) + ix))).ln_1p().copysign(self)
1208 }
1209
1210 /// Inverse hyperbolic cosine function.
1211 ///
1212 /// # Unspecified precision
1213 ///
1214 /// The precision of this function is non-deterministic. This means it varies by platform,
1215 /// Rust version, and can even differ within the same execution from one invocation to the next.
1216 ///
1217 /// # Examples
1218 ///
1219 /// ```
1220 /// #![feature(f16)]
1221 /// # #[cfg(reliable_f16_math)] {
1222 ///
1223 /// let x = 1.0f16;
1224 /// let f = x.cosh().acosh();
1225 ///
1226 /// let abs_difference = (f - x).abs();
1227 ///
1228 /// assert!(abs_difference <= f16::EPSILON);
1229 /// # }
1230 /// ```
1231 #[inline]
1232 #[doc(alias = "arccosh")]
1233 #[rustc_allow_incoherent_impl]
1234 #[unstable(feature = "f16", issue = "116909")]
1235 #[must_use = "method returns a new number and does not mutate the original value"]
1236 pub fn acosh(self) -> f16 {
1237 if self < 1.0 {
1238 Self::NAN
1239 } else {
1240 (self + ((self - 1.0).sqrt() * (self + 1.0).sqrt())).ln()
1241 }
1242 }
1243
1244 /// Inverse hyperbolic tangent function.
1245 ///
1246 /// # Unspecified precision
1247 ///
1248 /// The precision of this function is non-deterministic. This means it varies by platform,
1249 /// Rust version, and can even differ within the same execution from one invocation to the next.
1250 ///
1251 /// # Examples
1252 ///
1253 /// ```
1254 /// #![feature(f16)]
1255 /// # #[cfg(reliable_f16_math)] {
1256 ///
1257 /// let e = std::f16::consts::E;
1258 /// let f = e.tanh().atanh();
1259 ///
1260 /// let abs_difference = (f - e).abs();
1261 ///
1262 /// assert!(abs_difference <= 0.01);
1263 /// # }
1264 /// ```
1265 #[inline]
1266 #[doc(alias = "arctanh")]
1267 #[rustc_allow_incoherent_impl]
1268 #[unstable(feature = "f16", issue = "116909")]
1269 #[must_use = "method returns a new number and does not mutate the original value"]
1270 pub fn atanh(self) -> f16 {
1271 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
1272 }
1273
1274 /// Gamma function.
1275 ///
1276 /// # Unspecified precision
1277 ///
1278 /// The precision of this function is non-deterministic. This means it varies by platform,
1279 /// Rust version, and can even differ within the same execution from one invocation to the next.
1280 ///
1281 /// This function currently corresponds to the `tgammaf` from libc on Unix
1282 /// and Windows. Note that this might change in the future.
1283 ///
1284 /// # Examples
1285 ///
1286 /// ```
1287 /// #![feature(f16)]
1288 /// #![feature(float_gamma)]
1289 /// # #[cfg(reliable_f16_math)] {
1290 ///
1291 /// let x = 5.0f16;
1292 ///
1293 /// let abs_difference = (x.gamma() - 24.0).abs();
1294 ///
1295 /// assert!(abs_difference <= f16::EPSILON);
1296 /// # }
1297 /// ```
1298 #[inline]
1299 #[rustc_allow_incoherent_impl]
1300 #[unstable(feature = "f16", issue = "116909")]
1301 #[must_use = "method returns a new number and does not mutate the original value"]
1302 pub fn gamma(self) -> f16 {
1303 (unsafe { cmath::tgammaf(self as f32) }) as f16
1304 }
1305
1306 /// Natural logarithm of the absolute value of the gamma function
1307 ///
1308 /// The integer part of the tuple indicates the sign of the gamma function.
1309 ///
1310 /// # Unspecified precision
1311 ///
1312 /// The precision of this function is non-deterministic. This means it varies by platform,
1313 /// Rust version, and can even differ within the same execution from one invocation to the next.
1314 ///
1315 /// This function currently corresponds to the `lgamma_r` from libc on Unix
1316 /// and Windows. Note that this might change in the future.
1317 ///
1318 /// # Examples
1319 ///
1320 /// ```
1321 /// #![feature(f16)]
1322 /// #![feature(float_gamma)]
1323 /// # #[cfg(reliable_f16_math)] {
1324 ///
1325 /// let x = 2.0f16;
1326 ///
1327 /// let abs_difference = (x.ln_gamma().0 - 0.0).abs();
1328 ///
1329 /// assert!(abs_difference <= f16::EPSILON);
1330 /// # }
1331 /// ```
1332 #[inline]
1333 #[rustc_allow_incoherent_impl]
1334 #[unstable(feature = "f16", issue = "116909")]
1335 #[must_use = "method returns a new number and does not mutate the original value"]
1336 pub fn ln_gamma(self) -> (f16, i32) {
1337 let mut signgamp: i32 = 0;
1338 let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16;
1339 (x, signgamp)
1340 }
631341}
library/std/src/f16/tests.rs+433-39
......@@ -4,11 +4,21 @@
44use crate::f16::consts;
55use crate::num::{FpCategory as Fp, *};
66
7// We run out of precision pretty quickly with f16
8// const F16_APPROX_L1: f16 = 0.001;
9const F16_APPROX_L2: f16 = 0.01;
10// const F16_APPROX_L3: f16 = 0.1;
11const F16_APPROX_L4: f16 = 0.5;
7/// Tolerance for results on the order of 10.0e-2;
8#[cfg(reliable_f16_math)]
9const TOL_N2: f16 = 0.0001;
10
11/// Tolerance for results on the order of 10.0e+0
12#[cfg(reliable_f16_math)]
13const TOL_0: f16 = 0.01;
14
15/// Tolerance for results on the order of 10.0e+2
16#[cfg(reliable_f16_math)]
17const TOL_P2: f16 = 0.5;
18
19/// Tolerance for results on the order of 10.0e+4
20#[cfg(reliable_f16_math)]
21const TOL_P4: f16 = 10.0;
1222
1323/// Smallest number
1424const TINY_BITS: u16 = 0x1;
......@@ -47,7 +57,33 @@ fn test_num_f16() {
4757 test_num(10f16, 2f16);
4858}
4959
50// FIXME(f16_f128): add min and max tests when available
60#[test]
61#[cfg(reliable_f16_math)]
62fn test_min_nan() {
63 assert_eq!(f16::NAN.min(2.0), 2.0);
64 assert_eq!(2.0f16.min(f16::NAN), 2.0);
65}
66
67#[test]
68#[cfg(reliable_f16_math)]
69fn test_max_nan() {
70 assert_eq!(f16::NAN.max(2.0), 2.0);
71 assert_eq!(2.0f16.max(f16::NAN), 2.0);
72}
73
74#[test]
75#[cfg(reliable_f16_math)]
76fn test_minimum() {
77 assert!(f16::NAN.minimum(2.0).is_nan());
78 assert!(2.0f16.minimum(f16::NAN).is_nan());
79}
80
81#[test]
82#[cfg(reliable_f16_math)]
83fn test_maximum() {
84 assert!(f16::NAN.maximum(2.0).is_nan());
85 assert!(2.0f16.maximum(f16::NAN).is_nan());
86}
5187
5288#[test]
5389fn test_nan() {
......@@ -197,9 +233,100 @@ fn test_classify() {
197233 assert_eq!(1e-5f16.classify(), Fp::Subnormal);
198234}
199235
200// FIXME(f16_f128): add missing math functions when available
236#[test]
237#[cfg(reliable_f16_math)]
238fn test_floor() {
239 assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0);
240 assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0);
241 assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0);
242 assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0);
243 assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0);
244 assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0);
245 assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0);
246 assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0);
247 assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0);
248 assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0);
249}
250
251#[test]
252#[cfg(reliable_f16_math)]
253fn test_ceil() {
254 assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0);
255 assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0);
256 assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0);
257 assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0);
258 assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0);
259 assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0);
260 assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0);
261 assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0);
262 assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0);
263 assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0);
264}
265
266#[test]
267#[cfg(reliable_f16_math)]
268fn test_round() {
269 assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0);
270 assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0);
271 assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0);
272 assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0);
273 assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0);
274 assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0);
275 assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0);
276 assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0);
277 assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0);
278 assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0);
279 assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0);
280}
281
282#[test]
283#[cfg(reliable_f16_math)]
284fn test_round_ties_even() {
285 assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0);
286 assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0);
287 assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0);
288 assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0);
289 assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0);
290 assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0);
291 assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0);
292 assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0);
293 assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0);
294 assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0);
295 assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0);
296}
297
298#[test]
299#[cfg(reliable_f16_math)]
300fn test_trunc() {
301 assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0);
302 assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0);
303 assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0);
304 assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0);
305 assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0);
306 assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0);
307 assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0);
308 assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0);
309 assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0);
310 assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0);
311}
312
313#[test]
314#[cfg(reliable_f16_math)]
315fn test_fract() {
316 assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0);
317 assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0);
318 assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0);
319 assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0);
320 assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0);
321 assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0);
322 assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0);
323 assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0);
324 assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0);
325 assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0);
326}
201327
202328#[test]
329#[cfg(reliable_f16_math)]
203330fn test_abs() {
204331 assert_eq!(f16::INFINITY.abs(), f16::INFINITY);
205332 assert_eq!(1f16.abs(), 1f16);
......@@ -299,6 +426,24 @@ fn test_next_down() {
299426}
300427
301428#[test]
429#[cfg(reliable_f16_math)]
430fn test_mul_add() {
431 let nan: f16 = f16::NAN;
432 let inf: f16 = f16::INFINITY;
433 let neg_inf: f16 = f16::NEG_INFINITY;
434 assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2);
435 assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2);
436 assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0);
437 assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0);
438 assert!(nan.mul_add(7.8, 9.0).is_nan());
439 assert_eq!(inf.mul_add(7.8, 9.0), inf);
440 assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
441 assert_eq!(8.9f16.mul_add(inf, 3.2), inf);
442 assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf);
443}
444
445#[test]
446#[cfg(reliable_f16_math)]
302447fn test_recip() {
303448 let nan: f16 = f16::NAN;
304449 let inf: f16 = f16::INFINITY;
......@@ -307,11 +452,157 @@ fn test_recip() {
307452 assert_eq!(2.0f16.recip(), 0.5);
308453 assert_eq!((-0.4f16).recip(), -2.5);
309454 assert_eq!(0.0f16.recip(), inf);
455 assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4);
310456 assert!(nan.recip().is_nan());
311457 assert_eq!(inf.recip(), 0.0);
312458 assert_eq!(neg_inf.recip(), 0.0);
313459}
314460
461#[test]
462#[cfg(reliable_f16_math)]
463fn test_powi() {
464 // FIXME(llvm19): LLVM misoptimizes `powi.f16`
465 // <https://github.com/llvm/llvm-project/issues/98665>
466 // let nan: f16 = f16::NAN;
467 // let inf: f16 = f16::INFINITY;
468 // let neg_inf: f16 = f16::NEG_INFINITY;
469 // assert_eq!(1.0f16.powi(1), 1.0);
470 // assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0);
471 // assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2);
472 // assert_eq!(8.3f16.powi(0), 1.0);
473 // assert!(nan.powi(2).is_nan());
474 // assert_eq!(inf.powi(3), inf);
475 // assert_eq!(neg_inf.powi(2), inf);
476}
477
478#[test]
479#[cfg(reliable_f16_math)]
480fn test_powf() {
481 let nan: f16 = f16::NAN;
482 let inf: f16 = f16::INFINITY;
483 let neg_inf: f16 = f16::NEG_INFINITY;
484 assert_eq!(1.0f16.powf(1.0), 1.0);
485 assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2);
486 assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2);
487 assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2);
488 assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2);
489 assert_eq!(8.3f16.powf(0.0), 1.0);
490 assert!(nan.powf(2.0).is_nan());
491 assert_eq!(inf.powf(2.0), inf);
492 assert_eq!(neg_inf.powf(3.0), neg_inf);
493}
494
495#[test]
496#[cfg(reliable_f16_math)]
497fn test_sqrt_domain() {
498 assert!(f16::NAN.sqrt().is_nan());
499 assert!(f16::NEG_INFINITY.sqrt().is_nan());
500 assert!((-1.0f16).sqrt().is_nan());
501 assert_eq!((-0.0f16).sqrt(), -0.0);
502 assert_eq!(0.0f16.sqrt(), 0.0);
503 assert_eq!(1.0f16.sqrt(), 1.0);
504 assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY);
505}
506
507#[test]
508#[cfg(reliable_f16_math)]
509fn test_exp() {
510 assert_eq!(1.0, 0.0f16.exp());
511 assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0);
512 assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0);
513
514 let inf: f16 = f16::INFINITY;
515 let neg_inf: f16 = f16::NEG_INFINITY;
516 let nan: f16 = f16::NAN;
517 assert_eq!(inf, inf.exp());
518 assert_eq!(0.0, neg_inf.exp());
519 assert!(nan.exp().is_nan());
520}
521
522#[test]
523#[cfg(reliable_f16_math)]
524fn test_exp2() {
525 assert_eq!(32.0, 5.0f16.exp2());
526 assert_eq!(1.0, 0.0f16.exp2());
527
528 let inf: f16 = f16::INFINITY;
529 let neg_inf: f16 = f16::NEG_INFINITY;
530 let nan: f16 = f16::NAN;
531 assert_eq!(inf, inf.exp2());
532 assert_eq!(0.0, neg_inf.exp2());
533 assert!(nan.exp2().is_nan());
534}
535
536#[test]
537#[cfg(reliable_f16_math)]
538fn test_ln() {
539 let nan: f16 = f16::NAN;
540 let inf: f16 = f16::INFINITY;
541 let neg_inf: f16 = f16::NEG_INFINITY;
542 assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0);
543 assert!(nan.ln().is_nan());
544 assert_eq!(inf.ln(), inf);
545 assert!(neg_inf.ln().is_nan());
546 assert!((-2.3f16).ln().is_nan());
547 assert_eq!((-0.0f16).ln(), neg_inf);
548 assert_eq!(0.0f16.ln(), neg_inf);
549 assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0);
550}
551
552#[test]
553#[cfg(reliable_f16_math)]
554fn test_log() {
555 let nan: f16 = f16::NAN;
556 let inf: f16 = f16::INFINITY;
557 let neg_inf: f16 = f16::NEG_INFINITY;
558 assert_eq!(10.0f16.log(10.0), 1.0);
559 assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0);
560 assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0);
561 assert!(1.0f16.log(1.0).is_nan());
562 assert!(1.0f16.log(-13.9).is_nan());
563 assert!(nan.log(2.3).is_nan());
564 assert_eq!(inf.log(10.0), inf);
565 assert!(neg_inf.log(8.8).is_nan());
566 assert!((-2.3f16).log(0.1).is_nan());
567 assert_eq!((-0.0f16).log(2.0), neg_inf);
568 assert_eq!(0.0f16.log(7.0), neg_inf);
569}
570
571#[test]
572#[cfg(reliable_f16_math)]
573fn test_log2() {
574 let nan: f16 = f16::NAN;
575 let inf: f16 = f16::INFINITY;
576 let neg_inf: f16 = f16::NEG_INFINITY;
577 assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0);
578 assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0);
579 assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0);
580 assert!(nan.log2().is_nan());
581 assert_eq!(inf.log2(), inf);
582 assert!(neg_inf.log2().is_nan());
583 assert!((-2.3f16).log2().is_nan());
584 assert_eq!((-0.0f16).log2(), neg_inf);
585 assert_eq!(0.0f16.log2(), neg_inf);
586}
587
588#[test]
589#[cfg(reliable_f16_math)]
590fn test_log10() {
591 let nan: f16 = f16::NAN;
592 let inf: f16 = f16::INFINITY;
593 let neg_inf: f16 = f16::NEG_INFINITY;
594 assert_eq!(10.0f16.log10(), 1.0);
595 assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0);
596 assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0);
597 assert_eq!(1.0f16.log10(), 0.0);
598 assert!(nan.log10().is_nan());
599 assert_eq!(inf.log10(), inf);
600 assert!(neg_inf.log10().is_nan());
601 assert!((-2.3f16).log10().is_nan());
602 assert_eq!((-0.0f16).log10(), neg_inf);
603 assert_eq!(0.0f16.log10(), neg_inf);
604}
605
315606#[test]
316607fn test_to_degrees() {
317608 let pi: f16 = consts::PI;
......@@ -319,8 +610,8 @@ fn test_to_degrees() {
319610 let inf: f16 = f16::INFINITY;
320611 let neg_inf: f16 = f16::NEG_INFINITY;
321612 assert_eq!(0.0f16.to_degrees(), 0.0);
322 assert_approx_eq!((-5.8f16).to_degrees(), -332.315521);
323 assert_approx_eq!(pi.to_degrees(), 180.0, F16_APPROX_L4);
613 assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2);
614 assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2);
324615 assert!(nan.to_degrees().is_nan());
325616 assert_eq!(inf.to_degrees(), inf);
326617 assert_eq!(neg_inf.to_degrees(), neg_inf);
......@@ -334,14 +625,112 @@ fn test_to_radians() {
334625 let inf: f16 = f16::INFINITY;
335626 let neg_inf: f16 = f16::NEG_INFINITY;
336627 assert_eq!(0.0f16.to_radians(), 0.0);
337 assert_approx_eq!(154.6f16.to_radians(), 2.698279);
338 assert_approx_eq!((-332.31f16).to_radians(), -5.799903);
339 assert_approx_eq!(180.0f16.to_radians(), pi, F16_APPROX_L2);
628 assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0);
629 assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0);
630 assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0);
340631 assert!(nan.to_radians().is_nan());
341632 assert_eq!(inf.to_radians(), inf);
342633 assert_eq!(neg_inf.to_radians(), neg_inf);
343634}
344635
636#[test]
637#[cfg(reliable_f16_math)]
638fn test_asinh() {
639 assert_eq!(0.0f16.asinh(), 0.0f16);
640 assert_eq!((-0.0f16).asinh(), -0.0f16);
641
642 let inf: f16 = f16::INFINITY;
643 let neg_inf: f16 = f16::NEG_INFINITY;
644 let nan: f16 = f16::NAN;
645 assert_eq!(inf.asinh(), inf);
646 assert_eq!(neg_inf.asinh(), neg_inf);
647 assert!(nan.asinh().is_nan());
648 assert!((-0.0f16).asinh().is_sign_negative());
649 // issue 63271
650 assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0);
651 assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0);
652 // regression test for the catastrophic cancellation fixed in 72486
653 assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0);
654
655 // test for low accuracy from issue 104548
656 assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0);
657 // mul needed for approximate comparison to be meaningful
658 assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0);
659}
660
661#[test]
662#[cfg(reliable_f16_math)]
663fn test_acosh() {
664 assert_eq!(1.0f16.acosh(), 0.0f16);
665 assert!(0.999f16.acosh().is_nan());
666
667 let inf: f16 = f16::INFINITY;
668 let neg_inf: f16 = f16::NEG_INFINITY;
669 let nan: f16 = f16::NAN;
670 assert_eq!(inf.acosh(), inf);
671 assert!(neg_inf.acosh().is_nan());
672 assert!(nan.acosh().is_nan());
673 assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0);
674 assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0);
675
676 // test for low accuracy from issue 104548
677 assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2);
678}
679
680#[test]
681#[cfg(reliable_f16_math)]
682fn test_atanh() {
683 assert_eq!(0.0f16.atanh(), 0.0f16);
684 assert_eq!((-0.0f16).atanh(), -0.0f16);
685
686 let inf: f16 = f16::INFINITY;
687 let neg_inf: f16 = f16::NEG_INFINITY;
688 let nan: f16 = f16::NAN;
689 assert_eq!(1.0f16.atanh(), inf);
690 assert_eq!((-1.0f16).atanh(), neg_inf);
691 assert!(2f16.atanh().atanh().is_nan());
692 assert!((-2f16).atanh().atanh().is_nan());
693 assert!(inf.atanh().is_nan());
694 assert!(neg_inf.atanh().is_nan());
695 assert!(nan.atanh().is_nan());
696 assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0);
697 assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0);
698}
699
700#[test]
701#[cfg(reliable_f16_math)]
702fn test_gamma() {
703 // precision can differ among platforms
704 assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0);
705 assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0);
706 assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0);
707 assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0);
708 assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0);
709 assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0);
710 assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0);
711 assert_eq!(0.0f16.gamma(), f16::INFINITY);
712 assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY);
713 assert!((-1.0f16).gamma().is_nan());
714 assert!((-2.0f16).gamma().is_nan());
715 assert!(f16::NAN.gamma().is_nan());
716 assert!(f16::NEG_INFINITY.gamma().is_nan());
717 assert_eq!(f16::INFINITY.gamma(), f16::INFINITY);
718 assert_eq!(171.71f16.gamma(), f16::INFINITY);
719}
720
721#[test]
722#[cfg(reliable_f16_math)]
723fn test_ln_gamma() {
724 assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0);
725 assert_eq!(1.0f16.ln_gamma().1, 1);
726 assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0);
727 assert_eq!(2.0f16.ln_gamma().1, 1);
728 assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0);
729 assert_eq!(3.0f16.ln_gamma().1, 1);
730 assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0);
731 assert_eq!((-0.5f16).ln_gamma().1, -1);
732}
733
345734#[test]
346735fn test_real_consts() {
347736 // FIXME(f16_f128): add math tests when available
......@@ -355,29 +744,34 @@ fn test_real_consts() {
355744 let frac_pi_8: f16 = consts::FRAC_PI_8;
356745 let frac_1_pi: f16 = consts::FRAC_1_PI;
357746 let frac_2_pi: f16 = consts::FRAC_2_PI;
358 // let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI;
359 // let sqrt2: f16 = consts::SQRT_2;
360 // let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2;
361 // let e: f16 = consts::E;
362 // let log2_e: f16 = consts::LOG2_E;
363 // let log10_e: f16 = consts::LOG10_E;
364 // let ln_2: f16 = consts::LN_2;
365 // let ln_10: f16 = consts::LN_10;
366
367 assert_approx_eq!(frac_pi_2, pi / 2f16);
368 assert_approx_eq!(frac_pi_3, pi / 3f16);
369 assert_approx_eq!(frac_pi_4, pi / 4f16);
370 assert_approx_eq!(frac_pi_6, pi / 6f16);
371 assert_approx_eq!(frac_pi_8, pi / 8f16);
372 assert_approx_eq!(frac_1_pi, 1f16 / pi);
373 assert_approx_eq!(frac_2_pi, 2f16 / pi);
374 // assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt());
375 // assert_approx_eq!(sqrt2, 2f16.sqrt());
376 // assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt());
377 // assert_approx_eq!(log2_e, e.log2());
378 // assert_approx_eq!(log10_e, e.log10());
379 // assert_approx_eq!(ln_2, 2f16.ln());
380 // assert_approx_eq!(ln_10, 10f16.ln());
747
748 assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0);
749 assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0);
750 assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0);
751 assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0);
752 assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0);
753 assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0);
754 assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0);
755
756 #[cfg(reliable_f16_math)]
757 {
758 let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI;
759 let sqrt2: f16 = consts::SQRT_2;
760 let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2;
761 let e: f16 = consts::E;
762 let log2_e: f16 = consts::LOG2_E;
763 let log10_e: f16 = consts::LOG10_E;
764 let ln_2: f16 = consts::LN_2;
765 let ln_10: f16 = consts::LN_10;
766
767 assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0);
768 assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0);
769 assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0);
770 assert_approx_eq!(log2_e, e.log2(), TOL_0);
771 assert_approx_eq!(log10_e, e.log10(), TOL_0);
772 assert_approx_eq!(ln_2, 2f16.ln(), TOL_0);
773 assert_approx_eq!(ln_10, 10f16.ln(), TOL_0);
774 }
381775}
382776
383777#[test]
......@@ -386,10 +780,10 @@ fn test_float_bits_conv() {
386780 assert_eq!((12.5f16).to_bits(), 0x4a40);
387781 assert_eq!((1337f16).to_bits(), 0x6539);
388782 assert_eq!((-14.25f16).to_bits(), 0xcb20);
389 assert_approx_eq!(f16::from_bits(0x3c00), 1.0);
390 assert_approx_eq!(f16::from_bits(0x4a40), 12.5);
391 assert_approx_eq!(f16::from_bits(0x6539), 1337.0);
392 assert_approx_eq!(f16::from_bits(0xcb20), -14.25);
783 assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0);
784 assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0);
785 assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4);
786 assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0);
393787
394788 // Check that NaNs roundtrip their bits regardless of signaling-ness
395789 let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1;
library/std/src/keyword_docs.rs+1-1
......@@ -155,7 +155,7 @@ mod break_keyword {}
155155/// const WORDS: &str = "hello convenience!";
156156/// ```
157157///
158/// `const` items looks remarkably similar to `static` items, which introduces some confusion as
158/// `const` items look remarkably similar to `static` items, which introduces some confusion as
159159/// to which one should be used at which times. To put it simply, constants are inlined wherever
160160/// they're used, making using them identical to simply replacing the name of the `const` with its
161161/// value. Static variables, on the other hand, point to a single location in memory, which all
library/std/src/macros.rs+1-1
......@@ -382,7 +382,7 @@ macro_rules! assert_approx_eq {
382382 let diff = (*a - *b).abs();
383383 assert!(
384384 diff < $lim,
385 "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, actual {diff:?})",
385 "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})",
386386 lim = $lim
387387 );
388388 }};
library/std/src/sys/cmath.rs+15
......@@ -28,6 +28,21 @@ extern "C" {
2828 pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
2929 pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
3030
31 pub fn acosf128(n: f128) -> f128;
32 pub fn asinf128(n: f128) -> f128;
33 pub fn atanf128(n: f128) -> f128;
34 pub fn atan2f128(a: f128, b: f128) -> f128;
35 pub fn cbrtf128(n: f128) -> f128;
36 pub fn coshf128(n: f128) -> f128;
37 pub fn expm1f128(n: f128) -> f128;
38 pub fn hypotf128(x: f128, y: f128) -> f128;
39 pub fn log1pf128(n: f128) -> f128;
40 pub fn sinhf128(n: f128) -> f128;
41 pub fn tanf128(n: f128) -> f128;
42 pub fn tanhf128(n: f128) -> f128;
43 pub fn tgammaf128(n: f128) -> f128;
44 pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
45
3146 cfg_if::cfg_if! {
3247 if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
3348 pub fn acosf(n: f32) -> f32;
src/tools/run-make-support/src/external_deps/c_build.rs+22-5
......@@ -12,14 +12,31 @@ use crate::targets::{is_darwin, is_msvc, is_windows};
1212/// Built from a C file.
1313#[track_caller]
1414pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
15 build_native_static_lib_internal(lib_name, false)
16}
17
18/// Builds an optimized static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
19/// Built from a C file.
20#[track_caller]
21pub fn build_native_static_lib_optimized(lib_name: &str) -> PathBuf {
22 build_native_static_lib_internal(lib_name, true)
23}
24
25#[track_caller]
26fn build_native_static_lib_internal(lib_name: &str, optimzed: bool) -> PathBuf {
1527 let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
1628 let src = format!("{lib_name}.c");
1729 let lib_path = static_lib_name(lib_name);
18 if is_msvc() {
19 cc().arg("-c").out_exe(&obj_file).input(src).run();
20 } else {
21 cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run();
22 };
30
31 let mut cc = cc();
32 if !is_msvc() {
33 cc.arg("-v");
34 }
35 if optimzed {
36 cc.optimize();
37 }
38 cc.arg("-c").out_exe(&obj_file).input(src).optimize().run();
39
2340 let obj_file = if is_msvc() {
2441 PathBuf::from(format!("{lib_name}.obj"))
2542 } else {
src/tools/run-make-support/src/external_deps/cc.rs+11
......@@ -115,6 +115,17 @@ impl Cc {
115115 self.cmd.arg(path.as_ref());
116116 self
117117 }
118
119 /// Optimize the output.
120 /// Equivalent to `-O3` for GNU-compatible linkers or `-O2` for MSVC linkers.
121 pub fn optimize(&mut self) -> &mut Self {
122 if is_msvc() {
123 self.cmd.arg("-O2");
124 } else {
125 self.cmd.arg("-O3");
126 }
127 self
128 }
118129}
119130
120131/// `EXTRACFLAGS`
src/tools/run-make-support/src/lib.rs+1-1
......@@ -45,7 +45,7 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust
4545
4646// These rely on external dependencies.
4747pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
48pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx};
48pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
4949pub use clang::{clang, Clang};
5050pub use htmldocck::htmldocck;
5151pub use llvm::{
src/tools/tidy/src/allowed_run_make_makefiles.txt-3
......@@ -22,9 +22,6 @@ run-make/no-alloc-shim/Makefile
2222run-make/pdb-buildinfo-cl-cmd/Makefile
2323run-make/pgo-gen-lto/Makefile
2424run-make/pgo-indirect-call-promotion/Makefile
25run-make/raw-dylib-alt-calling-convention/Makefile
26run-make/raw-dylib-c/Makefile
27run-make/redundant-libs/Makefile
2825run-make/remap-path-prefix-dwarf/Makefile
2926run-make/reproducible-build/Makefile
3027run-make/rlib-format-packed-bundled-libs/Makefile
tests/run-make/link-args-order/rmake.rs+5-6
......@@ -3,15 +3,14 @@
33// checks that linker arguments remain intact and in the order they were originally passed in.
44// See https://github.com/rust-lang/rust/pull/70665
55
6//@ ignore-msvc
7// Reason: the ld linker does not exist on Windows.
8
9use run_make_support::rustc;
6use run_make_support::{is_msvc, rustc};
107
118fn main() {
9 let linker = if is_msvc() { "msvc" } else { "ld" };
10
1211 rustc()
1312 .input("empty.rs")
14 .linker_flavor("ld")
13 .linker_flavor(linker)
1514 .link_arg("a")
1615 .link_args("b c")
1716 .link_args("d e")
......@@ -20,7 +19,7 @@ fn main() {
2019 .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
2120 rustc()
2221 .input("empty.rs")
23 .linker_flavor("ld")
22 .linker_flavor(linker)
2423 .arg("-Zpre-link-arg=a")
2524 .arg("-Zpre-link-args=b c")
2625 .arg("-Zpre-link-args=d e")
tests/run-make/link-dedup/rmake.rs+25-8
......@@ -5,20 +5,37 @@
55// Without the --cfg flag, there should be a single -ltesta, no more, no less.
66// See https://github.com/rust-lang/rust/pull/84794
77
8//@ ignore-msvc
8use std::fmt::Write;
99
10use run_make_support::rustc;
10use run_make_support::{is_msvc, rustc};
1111
1212fn main() {
1313 rustc().input("depa.rs").run();
1414 rustc().input("depb.rs").run();
1515 rustc().input("depc.rs").run();
16
1617 let output = rustc().input("empty.rs").cfg("bar").run_fail();
17 output.assert_stderr_contains(r#""-ltesta" "-ltestb" "-ltesta""#);
18 let output = rustc().input("empty.rs").run_fail();
19 output.assert_stderr_contains(r#""-ltesta""#);
20 let output = rustc().input("empty.rs").run_fail();
21 output.assert_stderr_not_contains(r#""-ltestb""#);
18 output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
19
2220 let output = rustc().input("empty.rs").run_fail();
23 output.assert_stderr_not_contains(r#""-ltesta" "-ltesta" "-ltesta""#);
21 output.assert_stderr_contains(needle_from_libs(&["testa"]));
22 output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
23 output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
24 // Adjacent identical native libraries are no longer deduplicated if
25 // they come from different crates (https://github.com/rust-lang/rust/pull/103311)
26 // so the following will fail:
27 //output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa"]));
28}
29
30fn needle_from_libs(libs: &[&str]) -> String {
31 let mut needle = String::new();
32 for lib in libs {
33 if is_msvc() {
34 let _ = needle.write_fmt(format_args!(r#""{lib}.lib" "#));
35 } else {
36 let _ = needle.write_fmt(format_args!(r#""-l{lib}" "#));
37 }
38 }
39 needle.pop(); // remove trailing space
40 needle
2441}
tests/run-make/naked-symbol-visibility/a_rust_dylib.rs created+89
......@@ -0,0 +1,89 @@
1#![feature(naked_functions, asm_const, linkage)]
2#![crate_type = "dylib"]
3
4use std::arch::asm;
5
6pub trait TraitWithConst {
7 const COUNT: u32;
8}
9
10struct Test;
11
12impl TraitWithConst for Test {
13 const COUNT: u32 = 1;
14}
15
16#[no_mangle]
17fn entry() {
18 private_vanilla();
19 private_naked();
20
21 public_vanilla_generic::<Test>();
22 public_naked_generic::<Test>();
23}
24
25extern "C" fn private_vanilla() -> u32 {
26 42
27}
28
29#[naked]
30extern "C" fn private_naked() -> u32 {
31 unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
32}
33
34#[no_mangle]
35pub extern "C" fn public_vanilla() -> u32 {
36 42
37}
38
39#[naked]
40#[no_mangle]
41pub extern "C" fn public_naked() -> u32 {
42 unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
43}
44
45pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
46 T::COUNT
47}
48
49#[naked]
50pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 {
51 unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) }
52}
53
54#[linkage = "external"]
55extern "C" fn vanilla_external_linkage() -> u32 {
56 42
57}
58
59#[naked]
60#[linkage = "external"]
61extern "C" fn naked_external_linkage() -> u32 {
62 unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
63}
64
65#[cfg(not(windows))]
66#[linkage = "weak"]
67extern "C" fn vanilla_weak_linkage() -> u32 {
68 42
69}
70
71#[naked]
72#[cfg(not(windows))]
73#[linkage = "weak"]
74extern "C" fn naked_weak_linkage() -> u32 {
75 unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
76}
77
78// functions that are declared in an `extern "C"` block are currently not exported
79// this maybe should change in the future, this is just tracking the current behavior
80// reported in https://github.com/rust-lang/rust/issues/128071
81std::arch::global_asm! {
82 ".globl function_defined_in_global_asm",
83 "function_defined_in_global_asm:",
84 "ret",
85}
86
87extern "C" {
88 pub fn function_defined_in_global_asm();
89}
tests/run-make/naked-symbol-visibility/rmake.rs created+98
......@@ -0,0 +1,98 @@
1//@ ignore-windows
2//@ only-x86_64
3use run_make_support::object::read::{File, Object, Symbol};
4use run_make_support::object::ObjectSymbol;
5use run_make_support::targets::is_windows;
6use run_make_support::{dynamic_lib_name, env_var, rfs, rustc};
7
8fn main() {
9 let rdylib_name = dynamic_lib_name("a_rust_dylib");
10 rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();
11
12 let binary_data = rfs::read(&rdylib_name);
13 let rdylib = File::parse(&*binary_data).unwrap();
14
15 // naked should mirror vanilla
16 not_exported(&rdylib, "private_vanilla");
17 not_exported(&rdylib, "private_naked");
18
19 global_function(&rdylib, "public_vanilla");
20 global_function(&rdylib, "public_naked");
21
22 not_exported(&rdylib, "public_vanilla_generic");
23 not_exported(&rdylib, "public_naked_generic");
24
25 global_function(&rdylib, "vanilla_external_linkage");
26 global_function(&rdylib, "naked_external_linkage");
27
28 // FIXME: make this work on windows (gnu and msvc). See the PR
29 // https://github.com/rust-lang/rust/pull/128362 for some approaches
30 // that don't work
31 //
32 // #[linkage = "weak"] does not work well on windows, we get
33 //
34 // lib.def : error LNK2001: unresolved external symbol naked_weak_linkageā
35 // lib.def : error LNK2001: unresolved external symbol vanilla_weak_linkage
36 //
37 // so just skip weak symbols on windows (for now)
38 if !is_windows() {
39 weak_function(&rdylib, "vanilla_weak_linkage");
40 weak_function(&rdylib, "naked_weak_linkage");
41 }
42
43 // functions that are declared in an `extern "C"` block are currently not exported
44 // this maybe should change in the future, this is just tracking the current behavior
45 // reported in https://github.com/rust-lang/rust/issues/128071
46 not_exported(&rdylib, "function_defined_in_global_asm");
47
48 // share generics should expose the generic functions
49 rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
50 let binary_data = rfs::read(&rdylib_name);
51 let rdylib = File::parse(&*binary_data).unwrap();
52
53 global_function(&rdylib, "public_vanilla_generic");
54 global_function(&rdylib, "public_naked_generic");
55}
56
57#[track_caller]
58fn global_function(file: &File, symbol_name: &str) {
59 let symbols = find_dynamic_symbol(file, symbol_name);
60 let [symbol] = symbols.as_slice() else {
61 panic!("symbol {symbol_name} occurs {} times", symbols.len())
62 };
63
64 assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
65 assert!(symbol.is_global(), "`{symbol_name}` is not marked as global");
66}
67
68#[track_caller]
69fn weak_function(file: &File, symbol_name: &str) {
70 let symbols = find_dynamic_symbol(file, symbol_name);
71 let [symbol] = symbols.as_slice() else {
72 panic!("symbol {symbol_name} occurs {} times", symbols.len())
73 };
74
75 assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
76 assert!(symbol.is_weak(), "`{symbol_name}` is not marked as weak");
77}
78
79#[track_caller]
80fn not_exported(file: &File, symbol_name: &str) {
81 assert_eq!(find_dynamic_symbol(file, symbol_name).len(), 0)
82}
83
84fn find_subsequence(haystack: &[u8], needle: &[u8]) -> bool {
85 haystack.windows(needle.len()).any(|window| window == needle)
86}
87
88fn find_dynamic_symbol<'file, 'data>(
89 file: &'file File<'data>,
90 expected: &str,
91) -> Vec<Symbol<'data, 'file>> {
92 file.exports()
93 .unwrap()
94 .into_iter()
95 .filter(|e| find_subsequence(e.name(), expected.as_bytes()))
96 .filter_map(|e| file.symbol_by_name_bytes(e.name()))
97 .collect()
98}
tests/run-make/no-duplicate-libs/main.rs+3-3
......@@ -1,6 +1,6 @@
1#[link(name = "foo")] // linker should drop this library, no symbols used
2#[link(name = "bar")] // symbol comes from this library
3#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it
1#[link(name = "foo", kind = "static")] // linker should drop this library, no symbols used
2#[link(name = "bar", kind = "static")] // symbol comes from this library
3#[link(name = "foo", kind = "static")] // now linker picks up `foo` b/c `bar` library needs it
44extern "C" {
55 fn bar();
66}
tests/run-make/no-duplicate-libs/rmake.rs-3
......@@ -9,9 +9,6 @@
99//@ ignore-cross-compile
1010// Reason: the compiled binary is executed
1111
12//@ ignore-msvc
13// Reason: native compilation results in an unresolved external symbol
14
1512use run_make_support::{build_native_static_lib, run, rustc};
1613
1714fn main() {
tests/run-make/raw-dylib-alt-calling-convention/Makefile deleted-24
......@@ -1,24 +0,0 @@
1# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
2
3# only-x86
4# only-windows
5
6include ../tools.mk
7
8all:
9 $(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
10 $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
11 $(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
12ifdef IS_MSVC
13 $(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
14else
15 $(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
16endif
17
18 "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
19 $(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
20
21ifdef IS_MSVC
22 "$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
23 $(RUSTC_TEST_OP) "$(TMPDIR)"/output.msvc.txt output.msvc.txt
24endif
tests/run-make/raw-dylib-alt-calling-convention/rmake.rs created+32
......@@ -0,0 +1,32 @@
1// `raw-dylib` is a Windows-specific attribute which emits idata sections for the items in the
2// attached extern block,
3// so they may be linked against without linking against an import library.
4// To learn more, read https://github.com/rust-lang/rfcs/blob/master/text/2627-raw-dylib-kind.md
5// This test uses this feature alongside alternative calling conventions, checking that both
6// features are compatible and result in the expected output upon execution of the binary.
7// See https://github.com/rust-lang/rust/pull/84171
8
9//@ only-x86
10//@ only-windows
11
12use run_make_support::{build_native_dynamic_lib, diff, is_msvc, run, run_with_args, rustc};
13
14fn main() {
15 rustc()
16 .crate_type("lib")
17 .crate_name("raw_dylib_alt_calling_convention_test")
18 .input("lib.rs")
19 .run();
20 rustc().crate_type("bin").input("driver.rs").run();
21 build_native_dynamic_lib("extern");
22 let out = run("driver").stdout_utf8();
23 diff().expected_file("output.txt").actual_text("actual", out).normalize(r#"\r"#, "").run();
24 if is_msvc() {
25 let out_msvc = run_with_args("driver", &["true"]).stdout_utf8();
26 diff()
27 .expected_file("output.msvc.txt")
28 .actual_text("actual", out_msvc)
29 .normalize(r#"\r"#, "")
30 .run();
31 }
32}
tests/run-make/raw-dylib-c/Makefile deleted-28
......@@ -1,28 +0,0 @@
1# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
2
3# only-windows
4
5include ../tools.mk
6
7all:
8 $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
9 $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
10 $(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
11 $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
12 $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
13ifdef IS_MSVC
14 $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
15 $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
16else
17 $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
18 $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
19endif
20 "$(TMPDIR)"/driver | tr -d '\r' > "$(TMPDIR)"/output.txt
21 "$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
22
23ifdef RUSTC_BLESS_TEST
24 cp "$(TMPDIR)"/output.txt output.txt
25else
26 $(DIFF) output.txt "$(TMPDIR)"/output.txt
27 $(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
28endif
tests/run-make/raw-dylib-c/rmake.rs created+29
......@@ -0,0 +1,29 @@
1// `raw-dylib` is a Windows-specific attribute which emits idata sections for the items in the
2// attached extern block,
3// so they may be linked against without linking against an import library.
4// To learn more, read https://github.com/rust-lang/rfcs/blob/master/text/2627-raw-dylib-kind.md
5// This test is the simplest of the raw-dylib tests, simply smoke-testing that the feature
6// can be used to build an executable binary with an expected output with native C files
7// compiling into dynamic libraries.
8// See https://github.com/rust-lang/rust/pull/86419
9
10//@ only-windows
11
12use run_make_support::{build_native_dynamic_lib, diff, run, rustc};
13
14fn main() {
15 rustc().crate_type("lib").crate_name("raw_dylib_test").input("lib.rs").run();
16 rustc().crate_type("bin").input("driver.rs").run();
17 rustc().crate_type("bin").crate_name("raw_dylib_test_bin").input("lib.rs").run();
18 build_native_dynamic_lib("extern_1");
19 build_native_dynamic_lib("extern_2");
20 let out_driver = run("driver").stdout_utf8();
21 let out_raw = run("raw_dylib_test_bin").stdout_utf8();
22
23 diff()
24 .expected_file("output.txt")
25 .actual_text("actual", out_driver)
26 .normalize(r#"\r"#, "")
27 .run();
28 diff().expected_file("output.txt").actual_text("actual", out_raw).normalize(r#"\r"#, "").run();
29}
tests/run-make/redundant-libs/Makefile deleted-24
......@@ -1,24 +0,0 @@
1# ignore-cross-compile
2include ../tools.mk
3
4# ignore-windows-msvc
5
6# rustc will remove one of the two redundant references to foo below. Depending
7# on which one gets removed, we'll get a linker error on SOME platforms (like
8# Linux). On these platforms, when a library is referenced, the linker will
9# only pull in the symbols needed _at that point in time_. If a later library
10# depends on additional symbols from the library, they will not have been pulled
11# in, and you'll get undefined symbols errors.
12#
13# So in this example, we need to ensure that rustc keeps the _later_ reference
14# to foo, and not the former one.
15RUSTC_FLAGS = \
16 -l static=bar \
17 -l foo \
18 -l static=baz \
19 -l foo \
20 --print link-args
21
22all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz)
23 $(RUSTC) $(RUSTC_FLAGS) main.rs
24 $(call RUN,main)
tests/run-make/redundant-libs/rmake.rs created+34
......@@ -0,0 +1,34 @@
1// rustc will remove one of the two redundant references to foo below. Depending
2// on which one gets removed, we'll get a linker error on SOME platforms (like
3// Linux). On these platforms, when a library is referenced, the linker will
4// only pull in the symbols needed _at that point in time_. If a later library
5// depends on additional symbols from the library, they will not have been pulled
6// in, and you'll get undefined symbols errors.
7//
8// So in this example, we need to ensure that rustc keeps the _later_ reference
9// to foo, and not the former one.
10
11//@ ignore-cross-compile
12// Reason: the compiled binary is executed
13//@ ignore-windows-msvc
14// Reason: this test links libraries via link.exe, which only accepts the import library
15// for the dynamic library, i.e. `foo.dll.lib`. However, build_native_dynamic_lib only
16// produces `foo.dll` - the dynamic library itself. To make this test work on MSVC, one
17// would need to derive the import library from the dynamic library.
18// See https://stackoverflow.com/questions/9360280/
19
20use run_make_support::{
21 build_native_dynamic_lib, build_native_static_lib, cwd, is_msvc, rfs, run, rustc,
22};
23
24fn main() {
25 build_native_dynamic_lib("foo");
26 build_native_static_lib("bar");
27 build_native_static_lib("baz");
28 rustc()
29 .args(&["-lstatic=bar", "-lfoo", "-lstatic=baz", "-lfoo"])
30 .input("main.rs")
31 .print("link-args")
32 .run();
33 run("main");
34}
tests/run-make/zero-extend-abi-param-passing/param_passing.rs+1-1
......@@ -2,7 +2,7 @@
22// LLVM optimization choices. See additional note below for an
33// example.
44
5#[link(name = "bad")]
5#[link(name = "bad", kind = "static")]
66extern "C" {
77 pub fn c_read_value(a: u32, b: u32, c: u32) -> u16;
88}
tests/run-make/zero-extend-abi-param-passing/rmake.rs+4-11
......@@ -6,20 +6,13 @@
66// while simultaneously interfacing with a C library and using the -O3 flag.
77// See https://github.com/rust-lang/rust/issues/97463
88
9//@ ignore-msvc
10// Reason: the rustc compilation fails due to an unresolved external symbol
11
129//@ ignore-cross-compile
1310// Reason: The compiled binary is executed.
14
15use run_make_support::{cc, is_msvc, llvm_ar, run, rustc, static_lib_name};
11use run_make_support::{build_native_static_lib_optimized, run, rustc};
1612
1713fn main() {
18 // The issue exercised by this test specifically needs needs `-O`
19 // flags (like `-O3`) to reproduce. Thus, we call `cc()` instead of
20 // the nicer `build_native_static_lib`.
21 cc().arg("-c").arg("-O3").out_exe("bad.o").input("bad.c").run();
22 llvm_ar().obj_to_ar().output_input(static_lib_name("bad"), "bad.o").run();
23 rustc().input("param_passing.rs").arg("-lbad").opt_level("3").run();
14 // The issue exercised by this test specifically needs an optimized native static lib.
15 build_native_static_lib_optimized("bad");
16 rustc().input("param_passing.rs").opt_level("3").run();
2417 run("param_passing");
2518}