| author | bors <bors@rust-lang.org> 2024-08-07 06:01:57 UTC |
| committer | bors <bors@rust-lang.org> 2024-08-07 06:01:57 UTC |
| log | 6a2cd0d50c9b7e1243d948641758c76d1f22e25e |
| tree | 923d47c919f664b72637c9aabf2ece3c97ac6895 |
| parent | 2f3dc46465c04d10cb74d34b1bd80c3ebfdc05bf |
| parent | 701bc03c52fd411f1b7f86072903602ad92a45e7 |
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: rollup34 files changed, 4514 insertions(+), 226 deletions(-)
compiler/rustc_codegen_llvm/src/context.rs+4-4| ... | ... | @@ -775,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> { |
| 775 | 775 | ifn!("llvm.debugtrap", fn() -> void); |
| 776 | 776 | ifn!("llvm.frameaddress", fn(t_i32) -> ptr); |
| 777 | 777 | |
| 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); | |
| 782 | 782 | |
| 783 | 783 | ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16); |
| 784 | 784 | 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>( |
| 35 | 35 | sym::sqrtf64 => "llvm.sqrt.f64", |
| 36 | 36 | sym::sqrtf128 => "llvm.sqrt.f128", |
| 37 | 37 | |
| 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", | |
| 42 | 42 | |
| 43 | 43 | sym::sinf16 => "llvm.sin.f16", |
| 44 | 44 | sym::sinf32 => "llvm.sin.f32", |
library/core/src/intrinsics.rs+289| ... | ... | @@ -1528,6 +1528,12 @@ extern "rust-intrinsic" { |
| 1528 | 1528 | #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] |
| 1529 | 1529 | pub fn unaligned_volatile_store<T>(dst: *mut T, val: T); |
| 1530 | 1530 | |
| 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; | |
| 1531 | 1537 | /// Returns the square root of an `f32` |
| 1532 | 1538 | /// |
| 1533 | 1539 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1540,6 +1546,12 @@ extern "rust-intrinsic" { |
| 1540 | 1546 | /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) |
| 1541 | 1547 | #[rustc_nounwind] |
| 1542 | 1548 | 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; | |
| 1543 | 1555 | |
| 1544 | 1556 | /// Raises an `f16` to an integer power. |
| 1545 | 1557 | /// |
| ... | ... | @@ -1566,6 +1578,12 @@ extern "rust-intrinsic" { |
| 1566 | 1578 | #[rustc_nounwind] |
| 1567 | 1579 | pub fn powif128(a: f128, x: i32) -> f128; |
| 1568 | 1580 | |
| 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; | |
| 1569 | 1587 | /// Returns the sine of an `f32`. |
| 1570 | 1588 | /// |
| 1571 | 1589 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1578,7 +1596,19 @@ extern "rust-intrinsic" { |
| 1578 | 1596 | /// [`f64::sin`](../../std/primitive.f64.html#method.sin) |
| 1579 | 1597 | #[rustc_nounwind] |
| 1580 | 1598 | 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; | |
| 1581 | 1605 | |
| 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; | |
| 1582 | 1612 | /// Returns the cosine of an `f32`. |
| 1583 | 1613 | /// |
| 1584 | 1614 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1591,7 +1621,19 @@ extern "rust-intrinsic" { |
| 1591 | 1621 | /// [`f64::cos`](../../std/primitive.f64.html#method.cos) |
| 1592 | 1622 | #[rustc_nounwind] |
| 1593 | 1623 | 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; | |
| 1594 | 1630 | |
| 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; | |
| 1595 | 1637 | /// Raises an `f32` to an `f32` power. |
| 1596 | 1638 | /// |
| 1597 | 1639 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1604,7 +1646,19 @@ extern "rust-intrinsic" { |
| 1604 | 1646 | /// [`f64::powf`](../../std/primitive.f64.html#method.powf) |
| 1605 | 1647 | #[rustc_nounwind] |
| 1606 | 1648 | 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; | |
| 1607 | 1655 | |
| 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; | |
| 1608 | 1662 | /// Returns the exponential of an `f32`. |
| 1609 | 1663 | /// |
| 1610 | 1664 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1617,7 +1671,19 @@ extern "rust-intrinsic" { |
| 1617 | 1671 | /// [`f64::exp`](../../std/primitive.f64.html#method.exp) |
| 1618 | 1672 | #[rustc_nounwind] |
| 1619 | 1673 | 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; | |
| 1620 | 1680 | |
| 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; | |
| 1621 | 1687 | /// Returns 2 raised to the power of an `f32`. |
| 1622 | 1688 | /// |
| 1623 | 1689 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1630,7 +1696,19 @@ extern "rust-intrinsic" { |
| 1630 | 1696 | /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) |
| 1631 | 1697 | #[rustc_nounwind] |
| 1632 | 1698 | 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; | |
| 1633 | 1705 | |
| 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; | |
| 1634 | 1712 | /// Returns the natural logarithm of an `f32`. |
| 1635 | 1713 | /// |
| 1636 | 1714 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1643,7 +1721,19 @@ extern "rust-intrinsic" { |
| 1643 | 1721 | /// [`f64::ln`](../../std/primitive.f64.html#method.ln) |
| 1644 | 1722 | #[rustc_nounwind] |
| 1645 | 1723 | 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; | |
| 1646 | 1730 | |
| 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; | |
| 1647 | 1737 | /// Returns the base 10 logarithm of an `f32`. |
| 1648 | 1738 | /// |
| 1649 | 1739 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1656,7 +1746,19 @@ extern "rust-intrinsic" { |
| 1656 | 1746 | /// [`f64::log10`](../../std/primitive.f64.html#method.log10) |
| 1657 | 1747 | #[rustc_nounwind] |
| 1658 | 1748 | 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; | |
| 1659 | 1755 | |
| 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; | |
| 1660 | 1762 | /// Returns the base 2 logarithm of an `f32`. |
| 1661 | 1763 | /// |
| 1662 | 1764 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1669,7 +1771,19 @@ extern "rust-intrinsic" { |
| 1669 | 1771 | /// [`f64::log2`](../../std/primitive.f64.html#method.log2) |
| 1670 | 1772 | #[rustc_nounwind] |
| 1671 | 1773 | 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; | |
| 1672 | 1780 | |
| 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; | |
| 1673 | 1787 | /// Returns `a * b + c` for `f32` values. |
| 1674 | 1788 | /// |
| 1675 | 1789 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1682,7 +1796,19 @@ extern "rust-intrinsic" { |
| 1682 | 1796 | /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) |
| 1683 | 1797 | #[rustc_nounwind] |
| 1684 | 1798 | 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; | |
| 1685 | 1805 | |
| 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; | |
| 1686 | 1812 | /// Returns the absolute value of an `f32`. |
| 1687 | 1813 | /// |
| 1688 | 1814 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1695,7 +1821,25 @@ extern "rust-intrinsic" { |
| 1695 | 1821 | /// [`f64::abs`](../../std/primitive.f64.html#method.abs) |
| 1696 | 1822 | #[rustc_nounwind] |
| 1697 | 1823 | 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; | |
| 1698 | 1830 | |
| 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; | |
| 1699 | 1843 | /// Returns the minimum of two `f32` values. |
| 1700 | 1844 | /// |
| 1701 | 1845 | /// Note that, unlike most intrinsics, this is safe to call; |
| ... | ... | @@ -1720,6 +1864,31 @@ extern "rust-intrinsic" { |
| 1720 | 1864 | #[rustc_safe_intrinsic] |
| 1721 | 1865 | #[rustc_nounwind] |
| 1722 | 1866 | 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; | |
| 1723 | 1892 | /// Returns the maximum of two `f32` values. |
| 1724 | 1893 | /// |
| 1725 | 1894 | /// Note that, unlike most intrinsics, this is safe to call; |
| ... | ... | @@ -1744,7 +1913,25 @@ extern "rust-intrinsic" { |
| 1744 | 1913 | #[rustc_safe_intrinsic] |
| 1745 | 1914 | #[rustc_nounwind] |
| 1746 | 1915 | 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; | |
| 1747 | 1928 | |
| 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; | |
| 1748 | 1935 | /// Copies the sign from `y` to `x` for `f32` values. |
| 1749 | 1936 | /// |
| 1750 | 1937 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1757,7 +1944,19 @@ extern "rust-intrinsic" { |
| 1757 | 1944 | /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) |
| 1758 | 1945 | #[rustc_nounwind] |
| 1759 | 1946 | 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; | |
| 1760 | 1953 | |
| 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; | |
| 1761 | 1960 | /// Returns the largest integer less than or equal to an `f32`. |
| 1762 | 1961 | /// |
| 1763 | 1962 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1770,7 +1969,19 @@ extern "rust-intrinsic" { |
| 1770 | 1969 | /// [`f64::floor`](../../std/primitive.f64.html#method.floor) |
| 1771 | 1970 | #[rustc_nounwind] |
| 1772 | 1971 | 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; | |
| 1773 | 1978 | |
| 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; | |
| 1774 | 1985 | /// Returns the smallest integer greater than or equal to an `f32`. |
| 1775 | 1986 | /// |
| 1776 | 1987 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1783,7 +1994,19 @@ extern "rust-intrinsic" { |
| 1783 | 1994 | /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) |
| 1784 | 1995 | #[rustc_nounwind] |
| 1785 | 1996 | 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; | |
| 1786 | 2003 | |
| 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; | |
| 1787 | 2010 | /// Returns the integer part of an `f32`. |
| 1788 | 2011 | /// |
| 1789 | 2012 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1796,7 +2019,25 @@ extern "rust-intrinsic" { |
| 1796 | 2019 | /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) |
| 1797 | 2020 | #[rustc_nounwind] |
| 1798 | 2021 | 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; | |
| 1799 | 2028 | |
| 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; | |
| 1800 | 2041 | /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, |
| 1801 | 2042 | /// so this rounds half-way cases to the number with an even least significant digit. |
| 1802 | 2043 | /// |
| ... | ... | @@ -1821,7 +2062,25 @@ extern "rust-intrinsic" { |
| 1821 | 2062 | /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) |
| 1822 | 2063 | #[rustc_nounwind] |
| 1823 | 2064 | 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; | |
| 1824 | 2077 | |
| 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; | |
| 1825 | 2084 | /// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, |
| 1826 | 2085 | /// so this rounds half-way cases to the number with an even least significant digit. |
| 1827 | 2086 | /// |
| ... | ... | @@ -1834,7 +2093,19 @@ extern "rust-intrinsic" { |
| 1834 | 2093 | /// This intrinsic does not have a stable counterpart. |
| 1835 | 2094 | #[rustc_nounwind] |
| 1836 | 2095 | 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; | |
| 1837 | 2102 | |
| 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; | |
| 1838 | 2109 | /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. |
| 1839 | 2110 | /// |
| 1840 | 2111 | /// The stabilized version of this intrinsic is |
| ... | ... | @@ -1847,7 +2118,19 @@ extern "rust-intrinsic" { |
| 1847 | 2118 | /// [`f64::round`](../../std/primitive.f64.html#method.round) |
| 1848 | 2119 | #[rustc_nounwind] |
| 1849 | 2120 | 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; | |
| 1850 | 2127 | |
| 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; | |
| 1851 | 2134 | /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number |
| 1852 | 2135 | /// with an even least significant digit. |
| 1853 | 2136 | /// |
| ... | ... | @@ -1860,6 +2143,12 @@ extern "rust-intrinsic" { |
| 1860 | 2143 | /// This intrinsic does not have a stable counterpart. |
| 1861 | 2144 | #[rustc_nounwind] |
| 1862 | 2145 | 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; | |
| 1863 | 2152 | |
| 1864 | 2153 | /// Float addition that allows optimizations based on algebraic rules. |
| 1865 | 2154 | /// May assume inputs are finite. |
library/core/src/num/f128.rs+176| ... | ... | @@ -686,6 +686,182 @@ impl f128 { |
| 686 | 686 | self * RADS_PER_DEG |
| 687 | 687 | } |
| 688 | 688 | |
| 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 | ||
| 689 | 865 | /// Rounds toward zero and converts to any primitive integer type, |
| 690 | 866 | /// assuming that the value is finite and fits in that type. |
| 691 | 867 | /// |
library/core/src/num/f16.rs+171| ... | ... | @@ -720,6 +720,177 @@ impl f16 { |
| 720 | 720 | self * RADS_PER_DEG |
| 721 | 721 | } |
| 722 | 722 | |
| 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 | ||
| 723 | 894 | /// Rounds toward zero and converts to any primitive integer type, |
| 724 | 895 | /// assuming that the value is finite and fits in that type. |
| 725 | 896 | /// |
library/core/src/num/f32.rs+3-3| ... | ... | @@ -1070,13 +1070,13 @@ impl f32 { |
| 1070 | 1070 | // Overflow is impossible |
| 1071 | 1071 | (a + b) / 2. |
| 1072 | 1072 | } else if abs_a < LO { |
| 1073 | // Not safe to halve a | |
| 1073 | // Not safe to halve `a` (would underflow) | |
| 1074 | 1074 | a + (b / 2.) |
| 1075 | 1075 | } else if abs_b < LO { |
| 1076 | // Not safe to halve b | |
| 1076 | // Not safe to halve `b` (would underflow) | |
| 1077 | 1077 | (a / 2.) + b |
| 1078 | 1078 | } else { |
| 1079 | // Not safe to halve a and b | |
| 1079 | // Safe to halve `a` and `b` | |
| 1080 | 1080 | (a / 2.) + (b / 2.) |
| 1081 | 1081 | } |
| 1082 | 1082 | } |
library/core/src/num/f64.rs+3-3| ... | ... | @@ -1064,13 +1064,13 @@ impl f64 { |
| 1064 | 1064 | // Overflow is impossible |
| 1065 | 1065 | (a + b) / 2. |
| 1066 | 1066 | } else if abs_a < LO { |
| 1067 | // Not safe to halve a | |
| 1067 | // Not safe to halve `a` (would underflow) | |
| 1068 | 1068 | a + (b / 2.) |
| 1069 | 1069 | } else if abs_b < LO { |
| 1070 | // Not safe to halve b | |
| 1070 | // Not safe to halve `b` (would underflow) | |
| 1071 | 1071 | (a / 2.) + b |
| 1072 | 1072 | } else { |
| 1073 | // Not safe to halve a and b | |
| 1073 | // Safe to halve `a` and `b` | |
| 1074 | 1074 | (a / 2.) + (b / 2.) |
| 1075 | 1075 | } |
| 1076 | 1076 | } |
library/core/src/primitive_docs.rs+3| ... | ... | @@ -1244,6 +1244,9 @@ mod prim_f64 {} |
| 1244 | 1244 | /// actually implement it. For x86-64 and AArch64, ISA support is not even specified, |
| 1245 | 1245 | /// so it will always be a software implementation significantly slower than `f64`. |
| 1246 | 1246 | /// |
| 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 | /// | |
| 1247 | 1250 | /// *[See also the `std::f128::consts` module](crate::f128::consts).* |
| 1248 | 1251 | /// |
| 1249 | 1252 | /// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format |
library/std/build.rs+37| ... | ... | @@ -85,6 +85,11 @@ fn main() { |
| 85 | 85 | println!("cargo:rustc-check-cfg=cfg(reliable_f16)"); |
| 86 | 86 | println!("cargo:rustc-check-cfg=cfg(reliable_f128)"); |
| 87 | 87 | |
| 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 | ||
| 88 | 93 | let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { |
| 89 | 94 | // Selection failure until recent LLVM <https://github.com/llvm/llvm-project/issues/93894> |
| 90 | 95 | // FIXME(llvm19): can probably be removed at the version bump |
| ... | ... | @@ -130,10 +135,42 @@ fn main() { |
| 130 | 135 | _ => false, |
| 131 | 136 | }; |
| 132 | 137 | |
| 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 | ||
| 133 | 164 | if has_reliable_f16 { |
| 134 | 165 | println!("cargo:rustc-cfg=reliable_f16"); |
| 135 | 166 | } |
| 136 | 167 | if has_reliable_f128 { |
| 137 | 168 | println!("cargo:rustc-cfg=reliable_f128"); |
| 138 | 169 | } |
| 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 | } | |
| 139 | 176 | } |
library/std/src/f128.rs+1290-10| ... | ... | @@ -12,25 +12,180 @@ pub use core::f128::consts; |
| 12 | 12 | |
| 13 | 13 | #[cfg(not(test))] |
| 14 | 14 | use crate::intrinsics; |
| 15 | #[cfg(not(test))] | |
| 16 | use crate::sys::cmath; | |
| 15 | 17 | |
| 16 | 18 | #[cfg(not(test))] |
| 17 | 19 | impl f128 { |
| 18 | /// Raises a number to an integer power. | |
| 20 | /// Returns the largest integer less than or equal to `self`. | |
| 19 | 21 | /// |
| 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. | |
| 23 | 23 | /// |
| 24 | /// # Unspecified precision | |
| 24 | /// # Examples | |
| 25 | 25 | /// |
| 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 | /// ``` | |
| 28 | 39 | #[inline] |
| 29 | 40 | #[rustc_allow_incoherent_impl] |
| 30 | 41 | #[unstable(feature = "f128", issue = "116909")] |
| 31 | 42 | #[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() | |
| 34 | 189 | } |
| 35 | 190 | |
| 36 | 191 | /// Computes the absolute value of `self`. |
| ... | ... | @@ -41,7 +196,7 @@ impl f128 { |
| 41 | 196 | /// |
| 42 | 197 | /// ``` |
| 43 | 198 | /// #![feature(f128)] |
| 44 | /// # #[cfg(reliable_f128)] { // FIXME(f16_f128): reliable_f128 | |
| 199 | /// # #[cfg(reliable_f128)] { | |
| 45 | 200 | /// |
| 46 | 201 | /// let x = 3.5_f128; |
| 47 | 202 | /// let y = -3.5_f128; |
| ... | ... | @@ -61,4 +216,1129 @@ impl f128 { |
| 61 | 216 | // We don't do this now because LLVM has lowering bugs for f128 math. |
| 62 | 217 | Self::from_bits(self.to_bits() & !(1 << 127)) |
| 63 | 218 | } |
| 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 | } | |
| 64 | 1344 | } |
library/std/src/f128/tests.rs+443-35| ... | ... | @@ -4,6 +4,21 @@ |
| 4 | 4 | use crate::f128::consts; |
| 5 | 5 | use crate::num::{FpCategory as Fp, *}; |
| 6 | 6 | |
| 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. | |
| 11 | const 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`. | |
| 15 | const 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)] | |
| 20 | const TOL_IMPR: f128 = 1e-10; | |
| 21 | ||
| 7 | 22 | /// Smallest number |
| 8 | 23 | const TINY_BITS: u128 = 0x1; |
| 9 | 24 | |
| ... | ... | @@ -41,7 +56,33 @@ fn test_num_f128() { |
| 41 | 56 | test_num(10f128, 2f128); |
| 42 | 57 | } |
| 43 | 58 | |
| 44 | // FIXME(f16_f128): add min and max tests when available | |
| 59 | #[test] | |
| 60 | #[cfg(reliable_f128_math)] | |
| 61 | fn 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)] | |
| 68 | fn 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)] | |
| 75 | fn 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)] | |
| 82 | fn test_maximum() { | |
| 83 | assert!(f128::NAN.maximum(2.0).is_nan()); | |
| 84 | assert!(2.0f128.maximum(f128::NAN).is_nan()); | |
| 85 | } | |
| 45 | 86 | |
| 46 | 87 | #[test] |
| 47 | 88 | fn test_nan() { |
| ... | ... | @@ -191,9 +232,100 @@ fn test_classify() { |
| 191 | 232 | assert_eq!(1e-4932f128.classify(), Fp::Subnormal); |
| 192 | 233 | } |
| 193 | 234 | |
| 194 | // FIXME(f16_f128): add missing math functions when available | |
| 235 | #[test] | |
| 236 | #[cfg(reliable_f128_math)] | |
| 237 | fn 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)] | |
| 252 | fn 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 | } | |
| 195 | 264 | |
| 196 | 265 | #[test] |
| 266 | #[cfg(reliable_f128_math)] | |
| 267 | fn 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)] | |
| 283 | fn 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)] | |
| 299 | fn 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)] | |
| 314 | fn 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)] | |
| 197 | 329 | fn test_abs() { |
| 198 | 330 | assert_eq!(f128::INFINITY.abs(), f128::INFINITY); |
| 199 | 331 | assert_eq!(1f128.abs(), 1f128); |
| ... | ... | @@ -293,6 +425,24 @@ fn test_next_down() { |
| 293 | 425 | } |
| 294 | 426 | |
| 295 | 427 | #[test] |
| 428 | #[cfg(reliable_f128_math)] | |
| 429 | fn 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)] | |
| 296 | 446 | fn test_recip() { |
| 297 | 447 | let nan: f128 = f128::NAN; |
| 298 | 448 | let inf: f128 = f128::INFINITY; |
| ... | ... | @@ -301,11 +451,161 @@ fn test_recip() { |
| 301 | 451 | assert_eq!(2.0f128.recip(), 0.5); |
| 302 | 452 | assert_eq!((-0.4f128).recip(), -2.5); |
| 303 | 453 | assert_eq!(0.0f128.recip(), inf); |
| 454 | assert_approx_eq!( | |
| 455 | f128::MAX.recip(), | |
| 456 | 8.40525785778023376565669454330438228902076605e-4933, | |
| 457 | 1e-4900 | |
| 458 | ); | |
| 304 | 459 | assert!(nan.recip().is_nan()); |
| 305 | 460 | assert_eq!(inf.recip(), 0.0); |
| 306 | 461 | assert_eq!(neg_inf.recip(), 0.0); |
| 307 | 462 | } |
| 308 | 463 | |
| 464 | // Many math functions allow for less accurate results, so the next tolerance up is used | |
| 465 | ||
| 466 | #[test] | |
| 467 | #[cfg(reliable_f128_math)] | |
| 468 | fn 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)] | |
| 483 | fn 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)] | |
| 500 | fn 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)] | |
| 512 | fn 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)] | |
| 527 | fn 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)] | |
| 541 | fn 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)] | |
| 557 | fn 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)] | |
| 576 | fn 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)] | |
| 593 | fn 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 | ||
| 309 | 609 | #[test] |
| 310 | 610 | fn test_to_degrees() { |
| 311 | 611 | let pi: f128 = consts::PI; |
| ... | ... | @@ -313,8 +613,8 @@ fn test_to_degrees() { |
| 313 | 613 | let inf: f128 = f128::INFINITY; |
| 314 | 614 | let neg_inf: f128 = f128::NEG_INFINITY; |
| 315 | 615 | 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); | |
| 318 | 618 | assert!(nan.to_degrees().is_nan()); |
| 319 | 619 | assert_eq!(inf.to_degrees(), inf); |
| 320 | 620 | assert_eq!(neg_inf.to_degrees(), neg_inf); |
| ... | ... | @@ -328,19 +628,122 @@ fn test_to_radians() { |
| 328 | 628 | let inf: f128 = f128::INFINITY; |
| 329 | 629 | let neg_inf: f128 = f128::NEG_INFINITY; |
| 330 | 630 | 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); | |
| 333 | 633 | // check approx rather than exact because round trip for pi doesn't fall on an exactly |
| 334 | 634 | // 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); | |
| 336 | 636 | assert!(nan.to_radians().is_nan()); |
| 337 | 637 | assert_eq!(inf.to_radians(), inf); |
| 338 | 638 | assert_eq!(neg_inf.to_radians(), neg_inf); |
| 339 | 639 | } |
| 340 | 640 | |
| 641 | #[test] | |
| 642 | #[cfg(reliable_f128_math)] | |
| 643 | fn 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)] | |
| 674 | fn 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)] | |
| 693 | fn 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)] | |
| 713 | fn 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)] | |
| 734 | fn 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 | ||
| 341 | 745 | #[test] |
| 342 | 746 | fn test_real_consts() { |
| 343 | // FIXME(f16_f128): add math tests when available | |
| 344 | 747 | use super::consts; |
| 345 | 748 | |
| 346 | 749 | let pi: f128 = consts::PI; |
| ... | ... | @@ -351,29 +754,34 @@ fn test_real_consts() { |
| 351 | 754 | let frac_pi_8: f128 = consts::FRAC_PI_8; |
| 352 | 755 | let frac_1_pi: f128 = consts::FRAC_1_PI; |
| 353 | 756 | 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 | } | |
| 377 | 785 | } |
| 378 | 786 | |
| 379 | 787 | #[test] |
| ... | ... | @@ -382,10 +790,10 @@ fn test_float_bits_conv() { |
| 382 | 790 | assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000); |
| 383 | 791 | assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000); |
| 384 | 792 | 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); | |
| 389 | 797 | |
| 390 | 798 | // Check that NaNs roundtrip their bits regardless of signaling-ness |
| 391 | 799 | // 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; |
| 12 | 12 | |
| 13 | 13 | #[cfg(not(test))] |
| 14 | 14 | use crate::intrinsics; |
| 15 | #[cfg(not(test))] | |
| 16 | use crate::sys::cmath; | |
| 15 | 17 | |
| 16 | 18 | #[cfg(not(test))] |
| 17 | 19 | impl f16 { |
| 18 | /// Raises a number to an integer power. | |
| 20 | /// Returns the largest integer less than or equal to `self`. | |
| 19 | 21 | /// |
| 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. | |
| 23 | 23 | /// |
| 24 | /// # Unspecified precision | |
| 24 | /// # Examples | |
| 25 | 25 | /// |
| 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 | /// ``` | |
| 28 | 39 | #[inline] |
| 29 | 40 | #[rustc_allow_incoherent_impl] |
| 30 | 41 | #[unstable(feature = "f16", issue = "116909")] |
| 31 | 42 | #[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() | |
| 34 | 189 | } |
| 35 | 190 | |
| 36 | 191 | /// Computes the absolute value of `self`. |
| ... | ... | @@ -60,4 +215,1127 @@ impl f16 { |
| 60 | 215 | // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available |
| 61 | 216 | Self::from_bits(self.to_bits() & !(1 << 15)) |
| 62 | 217 | } |
| 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 | } | |
| 63 | 1341 | } |
library/std/src/f16/tests.rs+433-39| ... | ... | @@ -4,11 +4,21 @@ |
| 4 | 4 | use crate::f16::consts; |
| 5 | 5 | use crate::num::{FpCategory as Fp, *}; |
| 6 | 6 | |
| 7 | // We run out of precision pretty quickly with f16 | |
| 8 | // const F16_APPROX_L1: f16 = 0.001; | |
| 9 | const F16_APPROX_L2: f16 = 0.01; | |
| 10 | // const F16_APPROX_L3: f16 = 0.1; | |
| 11 | const F16_APPROX_L4: f16 = 0.5; | |
| 7 | /// Tolerance for results on the order of 10.0e-2; | |
| 8 | #[cfg(reliable_f16_math)] | |
| 9 | const TOL_N2: f16 = 0.0001; | |
| 10 | ||
| 11 | /// Tolerance for results on the order of 10.0e+0 | |
| 12 | #[cfg(reliable_f16_math)] | |
| 13 | const TOL_0: f16 = 0.01; | |
| 14 | ||
| 15 | /// Tolerance for results on the order of 10.0e+2 | |
| 16 | #[cfg(reliable_f16_math)] | |
| 17 | const TOL_P2: f16 = 0.5; | |
| 18 | ||
| 19 | /// Tolerance for results on the order of 10.0e+4 | |
| 20 | #[cfg(reliable_f16_math)] | |
| 21 | const TOL_P4: f16 = 10.0; | |
| 12 | 22 | |
| 13 | 23 | /// Smallest number |
| 14 | 24 | const TINY_BITS: u16 = 0x1; |
| ... | ... | @@ -47,7 +57,33 @@ fn test_num_f16() { |
| 47 | 57 | test_num(10f16, 2f16); |
| 48 | 58 | } |
| 49 | 59 | |
| 50 | // FIXME(f16_f128): add min and max tests when available | |
| 60 | #[test] | |
| 61 | #[cfg(reliable_f16_math)] | |
| 62 | fn 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)] | |
| 69 | fn 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)] | |
| 76 | fn 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)] | |
| 83 | fn test_maximum() { | |
| 84 | assert!(f16::NAN.maximum(2.0).is_nan()); | |
| 85 | assert!(2.0f16.maximum(f16::NAN).is_nan()); | |
| 86 | } | |
| 51 | 87 | |
| 52 | 88 | #[test] |
| 53 | 89 | fn test_nan() { |
| ... | ... | @@ -197,9 +233,100 @@ fn test_classify() { |
| 197 | 233 | assert_eq!(1e-5f16.classify(), Fp::Subnormal); |
| 198 | 234 | } |
| 199 | 235 | |
| 200 | // FIXME(f16_f128): add missing math functions when available | |
| 236 | #[test] | |
| 237 | #[cfg(reliable_f16_math)] | |
| 238 | fn 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)] | |
| 253 | fn 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)] | |
| 268 | fn 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)] | |
| 284 | fn 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)] | |
| 300 | fn 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)] | |
| 315 | fn 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 | } | |
| 201 | 327 | |
| 202 | 328 | #[test] |
| 329 | #[cfg(reliable_f16_math)] | |
| 203 | 330 | fn test_abs() { |
| 204 | 331 | assert_eq!(f16::INFINITY.abs(), f16::INFINITY); |
| 205 | 332 | assert_eq!(1f16.abs(), 1f16); |
| ... | ... | @@ -299,6 +426,24 @@ fn test_next_down() { |
| 299 | 426 | } |
| 300 | 427 | |
| 301 | 428 | #[test] |
| 429 | #[cfg(reliable_f16_math)] | |
| 430 | fn 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)] | |
| 302 | 447 | fn test_recip() { |
| 303 | 448 | let nan: f16 = f16::NAN; |
| 304 | 449 | let inf: f16 = f16::INFINITY; |
| ... | ... | @@ -307,11 +452,157 @@ fn test_recip() { |
| 307 | 452 | assert_eq!(2.0f16.recip(), 0.5); |
| 308 | 453 | assert_eq!((-0.4f16).recip(), -2.5); |
| 309 | 454 | assert_eq!(0.0f16.recip(), inf); |
| 455 | assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); | |
| 310 | 456 | assert!(nan.recip().is_nan()); |
| 311 | 457 | assert_eq!(inf.recip(), 0.0); |
| 312 | 458 | assert_eq!(neg_inf.recip(), 0.0); |
| 313 | 459 | } |
| 314 | 460 | |
| 461 | #[test] | |
| 462 | #[cfg(reliable_f16_math)] | |
| 463 | fn 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)] | |
| 480 | fn 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)] | |
| 497 | fn 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)] | |
| 509 | fn 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)] | |
| 524 | fn 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)] | |
| 538 | fn 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)] | |
| 554 | fn 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)] | |
| 573 | fn 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)] | |
| 590 | fn 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 | ||
| 315 | 606 | #[test] |
| 316 | 607 | fn test_to_degrees() { |
| 317 | 608 | let pi: f16 = consts::PI; |
| ... | ... | @@ -319,8 +610,8 @@ fn test_to_degrees() { |
| 319 | 610 | let inf: f16 = f16::INFINITY; |
| 320 | 611 | let neg_inf: f16 = f16::NEG_INFINITY; |
| 321 | 612 | 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); | |
| 324 | 615 | assert!(nan.to_degrees().is_nan()); |
| 325 | 616 | assert_eq!(inf.to_degrees(), inf); |
| 326 | 617 | assert_eq!(neg_inf.to_degrees(), neg_inf); |
| ... | ... | @@ -334,14 +625,112 @@ fn test_to_radians() { |
| 334 | 625 | let inf: f16 = f16::INFINITY; |
| 335 | 626 | let neg_inf: f16 = f16::NEG_INFINITY; |
| 336 | 627 | 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); | |
| 340 | 631 | assert!(nan.to_radians().is_nan()); |
| 341 | 632 | assert_eq!(inf.to_radians(), inf); |
| 342 | 633 | assert_eq!(neg_inf.to_radians(), neg_inf); |
| 343 | 634 | } |
| 344 | 635 | |
| 636 | #[test] | |
| 637 | #[cfg(reliable_f16_math)] | |
| 638 | fn 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)] | |
| 663 | fn 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)] | |
| 682 | fn 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)] | |
| 702 | fn 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)] | |
| 723 | fn 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 | ||
| 345 | 734 | #[test] |
| 346 | 735 | fn test_real_consts() { |
| 347 | 736 | // FIXME(f16_f128): add math tests when available |
| ... | ... | @@ -355,29 +744,34 @@ fn test_real_consts() { |
| 355 | 744 | let frac_pi_8: f16 = consts::FRAC_PI_8; |
| 356 | 745 | let frac_1_pi: f16 = consts::FRAC_1_PI; |
| 357 | 746 | 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 | } | |
| 381 | 775 | } |
| 382 | 776 | |
| 383 | 777 | #[test] |
| ... | ... | @@ -386,10 +780,10 @@ fn test_float_bits_conv() { |
| 386 | 780 | assert_eq!((12.5f16).to_bits(), 0x4a40); |
| 387 | 781 | assert_eq!((1337f16).to_bits(), 0x6539); |
| 388 | 782 | 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); | |
| 393 | 787 | |
| 394 | 788 | // Check that NaNs roundtrip their bits regardless of signaling-ness |
| 395 | 789 | let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1; |
library/std/src/keyword_docs.rs+1-1| ... | ... | @@ -155,7 +155,7 @@ mod break_keyword {} |
| 155 | 155 | /// const WORDS: &str = "hello convenience!"; |
| 156 | 156 | /// ``` |
| 157 | 157 | /// |
| 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 | |
| 159 | 159 | /// to which one should be used at which times. To put it simply, constants are inlined wherever |
| 160 | 160 | /// they're used, making using them identical to simply replacing the name of the `const` with its |
| 161 | 161 | /// 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 { |
| 382 | 382 | let diff = (*a - *b).abs(); |
| 383 | 383 | assert!( |
| 384 | 384 | 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:?})", | |
| 386 | 386 | lim = $lim |
| 387 | 387 | ); |
| 388 | 388 | }}; |
library/std/src/sys/cmath.rs+15| ... | ... | @@ -28,6 +28,21 @@ extern "C" { |
| 28 | 28 | pub fn lgamma_r(n: f64, s: &mut i32) -> f64; |
| 29 | 29 | pub fn lgammaf_r(n: f32, s: &mut i32) -> f32; |
| 30 | 30 | |
| 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 | ||
| 31 | 46 | cfg_if::cfg_if! { |
| 32 | 47 | if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] { |
| 33 | 48 | 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}; |
| 12 | 12 | /// Built from a C file. |
| 13 | 13 | #[track_caller] |
| 14 | 14 | pub 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] | |
| 21 | pub fn build_native_static_lib_optimized(lib_name: &str) -> PathBuf { | |
| 22 | build_native_static_lib_internal(lib_name, true) | |
| 23 | } | |
| 24 | ||
| 25 | #[track_caller] | |
| 26 | fn build_native_static_lib_internal(lib_name: &str, optimzed: bool) -> PathBuf { | |
| 15 | 27 | let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") }; |
| 16 | 28 | let src = format!("{lib_name}.c"); |
| 17 | 29 | 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 | ||
| 23 | 40 | let obj_file = if is_msvc() { |
| 24 | 41 | PathBuf::from(format!("{lib_name}.obj")) |
| 25 | 42 | } else { |
src/tools/run-make-support/src/external_deps/cc.rs+11| ... | ... | @@ -115,6 +115,17 @@ impl Cc { |
| 115 | 115 | self.cmd.arg(path.as_ref()); |
| 116 | 116 | self |
| 117 | 117 | } |
| 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 | } | |
| 118 | 129 | } |
| 119 | 130 | |
| 120 | 131 | /// `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 |
| 45 | 45 | |
| 46 | 46 | // These rely on external dependencies. |
| 47 | 47 | pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc}; |
| 48 | pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx}; | |
| 48 | pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx}; | |
| 49 | 49 | pub use clang::{clang, Clang}; |
| 50 | 50 | pub use htmldocck::htmldocck; |
| 51 | 51 | pub use llvm::{ |
src/tools/tidy/src/allowed_run_make_makefiles.txt-3| ... | ... | @@ -22,9 +22,6 @@ run-make/no-alloc-shim/Makefile |
| 22 | 22 | run-make/pdb-buildinfo-cl-cmd/Makefile |
| 23 | 23 | run-make/pgo-gen-lto/Makefile |
| 24 | 24 | run-make/pgo-indirect-call-promotion/Makefile |
| 25 | run-make/raw-dylib-alt-calling-convention/Makefile | |
| 26 | run-make/raw-dylib-c/Makefile | |
| 27 | run-make/redundant-libs/Makefile | |
| 28 | 25 | run-make/remap-path-prefix-dwarf/Makefile |
| 29 | 26 | run-make/reproducible-build/Makefile |
| 30 | 27 | run-make/rlib-format-packed-bundled-libs/Makefile |
tests/run-make/link-args-order/rmake.rs+5-6| ... | ... | @@ -3,15 +3,14 @@ |
| 3 | 3 | // checks that linker arguments remain intact and in the order they were originally passed in. |
| 4 | 4 | // See https://github.com/rust-lang/rust/pull/70665 |
| 5 | 5 | |
| 6 | //@ ignore-msvc | |
| 7 | // Reason: the ld linker does not exist on Windows. | |
| 8 | ||
| 9 | use run_make_support::rustc; | |
| 6 | use run_make_support::{is_msvc, rustc}; | |
| 10 | 7 | |
| 11 | 8 | fn main() { |
| 9 | let linker = if is_msvc() { "msvc" } else { "ld" }; | |
| 10 | ||
| 12 | 11 | rustc() |
| 13 | 12 | .input("empty.rs") |
| 14 | .linker_flavor("ld") | |
| 13 | .linker_flavor(linker) | |
| 15 | 14 | .link_arg("a") |
| 16 | 15 | .link_args("b c") |
| 17 | 16 | .link_args("d e") |
| ... | ... | @@ -20,7 +19,7 @@ fn main() { |
| 20 | 19 | .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#); |
| 21 | 20 | rustc() |
| 22 | 21 | .input("empty.rs") |
| 23 | .linker_flavor("ld") | |
| 22 | .linker_flavor(linker) | |
| 24 | 23 | .arg("-Zpre-link-arg=a") |
| 25 | 24 | .arg("-Zpre-link-args=b c") |
| 26 | 25 | .arg("-Zpre-link-args=d e") |
tests/run-make/link-dedup/rmake.rs+25-8| ... | ... | @@ -5,20 +5,37 @@ |
| 5 | 5 | // Without the --cfg flag, there should be a single -ltesta, no more, no less. |
| 6 | 6 | // See https://github.com/rust-lang/rust/pull/84794 |
| 7 | 7 | |
| 8 | //@ ignore-msvc | |
| 8 | use std::fmt::Write; | |
| 9 | 9 | |
| 10 | use run_make_support::rustc; | |
| 10 | use run_make_support::{is_msvc, rustc}; | |
| 11 | 11 | |
| 12 | 12 | fn main() { |
| 13 | 13 | rustc().input("depa.rs").run(); |
| 14 | 14 | rustc().input("depb.rs").run(); |
| 15 | 15 | rustc().input("depc.rs").run(); |
| 16 | ||
| 16 | 17 | 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 | ||
| 22 | 20 | 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 | ||
| 30 | fn 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 | |
| 24 | 41 | } |
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 | ||
| 4 | use std::arch::asm; | |
| 5 | ||
| 6 | pub trait TraitWithConst { | |
| 7 | const COUNT: u32; | |
| 8 | } | |
| 9 | ||
| 10 | struct Test; | |
| 11 | ||
| 12 | impl TraitWithConst for Test { | |
| 13 | const COUNT: u32 = 1; | |
| 14 | } | |
| 15 | ||
| 16 | #[no_mangle] | |
| 17 | fn entry() { | |
| 18 | private_vanilla(); | |
| 19 | private_naked(); | |
| 20 | ||
| 21 | public_vanilla_generic::<Test>(); | |
| 22 | public_naked_generic::<Test>(); | |
| 23 | } | |
| 24 | ||
| 25 | extern "C" fn private_vanilla() -> u32 { | |
| 26 | 42 | |
| 27 | } | |
| 28 | ||
| 29 | #[naked] | |
| 30 | extern "C" fn private_naked() -> u32 { | |
| 31 | unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } | |
| 32 | } | |
| 33 | ||
| 34 | #[no_mangle] | |
| 35 | pub extern "C" fn public_vanilla() -> u32 { | |
| 36 | 42 | |
| 37 | } | |
| 38 | ||
| 39 | #[naked] | |
| 40 | #[no_mangle] | |
| 41 | pub extern "C" fn public_naked() -> u32 { | |
| 42 | unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } | |
| 43 | } | |
| 44 | ||
| 45 | pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 { | |
| 46 | T::COUNT | |
| 47 | } | |
| 48 | ||
| 49 | #[naked] | |
| 50 | pub 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"] | |
| 55 | extern "C" fn vanilla_external_linkage() -> u32 { | |
| 56 | 42 | |
| 57 | } | |
| 58 | ||
| 59 | #[naked] | |
| 60 | #[linkage = "external"] | |
| 61 | extern "C" fn naked_external_linkage() -> u32 { | |
| 62 | unsafe { asm!("mov rax, 42", "ret", options(noreturn)) } | |
| 63 | } | |
| 64 | ||
| 65 | #[cfg(not(windows))] | |
| 66 | #[linkage = "weak"] | |
| 67 | extern "C" fn vanilla_weak_linkage() -> u32 { | |
| 68 | 42 | |
| 69 | } | |
| 70 | ||
| 71 | #[naked] | |
| 72 | #[cfg(not(windows))] | |
| 73 | #[linkage = "weak"] | |
| 74 | extern "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 | |
| 81 | std::arch::global_asm! { | |
| 82 | ".globl function_defined_in_global_asm", | |
| 83 | "function_defined_in_global_asm:", | |
| 84 | "ret", | |
| 85 | } | |
| 86 | ||
| 87 | extern "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 | |
| 3 | use run_make_support::object::read::{File, Object, Symbol}; | |
| 4 | use run_make_support::object::ObjectSymbol; | |
| 5 | use run_make_support::targets::is_windows; | |
| 6 | use run_make_support::{dynamic_lib_name, env_var, rfs, rustc}; | |
| 7 | ||
| 8 | fn 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] | |
| 58 | fn 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] | |
| 69 | fn 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] | |
| 80 | fn not_exported(file: &File, symbol_name: &str) { | |
| 81 | assert_eq!(find_dynamic_symbol(file, symbol_name).len(), 0) | |
| 82 | } | |
| 83 | ||
| 84 | fn find_subsequence(haystack: &[u8], needle: &[u8]) -> bool { | |
| 85 | haystack.windows(needle.len()).any(|window| window == needle) | |
| 86 | } | |
| 87 | ||
| 88 | fn 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 | |
| 4 | 4 | extern "C" { |
| 5 | 5 | fn bar(); |
| 6 | 6 | } |
tests/run-make/no-duplicate-libs/rmake.rs-3| ... | ... | @@ -9,9 +9,6 @@ |
| 9 | 9 | //@ ignore-cross-compile |
| 10 | 10 | // Reason: the compiled binary is executed |
| 11 | 11 | |
| 12 | //@ ignore-msvc | |
| 13 | // Reason: native compilation results in an unresolved external symbol | |
| 14 | ||
| 15 | 12 | use run_make_support::{build_native_static_lib, run, rustc}; |
| 16 | 13 | |
| 17 | 14 | fn 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 | ||
| 6 | include ../tools.mk | |
| 7 | ||
| 8 | all: | |
| 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) | |
| 12 | ifdef IS_MSVC | |
| 13 | 	$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib | |
| 14 | else | |
| 15 | 	$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll | |
| 16 | endif | |
| 17 | ||
| 18 | 	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt | |
| 19 | 	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt | |
| 20 | ||
| 21 | ifdef IS_MSVC | |
| 22 | 	"$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt | |
| 23 | 	$(RUSTC_TEST_OP) "$(TMPDIR)"/output.msvc.txt output.msvc.txt | |
| 24 | endif |
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 | ||
| 12 | use run_make_support::{build_native_dynamic_lib, diff, is_msvc, run, run_with_args, rustc}; | |
| 13 | ||
| 14 | fn 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 | ||
| 5 | include ../tools.mk | |
| 6 | ||
| 7 | all: | |
| 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) | |
| 13 | ifdef 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 | |
| 16 | else | |
| 17 | 	$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll | |
| 18 | 	$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll | |
| 19 | endif | |
| 20 | 	"$(TMPDIR)"/driver | tr -d '\r' > "$(TMPDIR)"/output.txt | |
| 21 | 	"$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt | |
| 22 | ||
| 23 | ifdef RUSTC_BLESS_TEST | |
| 24 | 	cp "$(TMPDIR)"/output.txt output.txt | |
| 25 | else | |
| 26 | 	$(DIFF) output.txt "$(TMPDIR)"/output.txt | |
| 27 | 	$(DIFF) output.txt "$(TMPDIR)"/output_bin.txt | |
| 28 | endif |
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 | ||
| 12 | use run_make_support::{build_native_dynamic_lib, diff, run, rustc}; | |
| 13 | ||
| 14 | fn 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 | |
| 2 | include ../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. | |
| 15 | RUSTC_FLAGS = \ | |
| 16 | -l static=bar \ | |
| 17 | -l foo \ | |
| 18 | -l static=baz \ | |
| 19 | -l foo \ | |
| 20 | --print link-args | |
| 21 | ||
| 22 | all: $(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 | ||
| 20 | use run_make_support::{ | |
| 21 | build_native_dynamic_lib, build_native_static_lib, cwd, is_msvc, rfs, run, rustc, | |
| 22 | }; | |
| 23 | ||
| 24 | fn 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 @@ |
| 2 | 2 | // LLVM optimization choices. See additional note below for an |
| 3 | 3 | // example. |
| 4 | 4 | |
| 5 | #[link(name = "bad")] | |
| 5 | #[link(name = "bad", kind = "static")] | |
| 6 | 6 | extern "C" { |
| 7 | 7 | pub fn c_read_value(a: u32, b: u32, c: u32) -> u16; |
| 8 | 8 | } |
tests/run-make/zero-extend-abi-param-passing/rmake.rs+4-11| ... | ... | @@ -6,20 +6,13 @@ |
| 6 | 6 | // while simultaneously interfacing with a C library and using the -O3 flag. |
| 7 | 7 | // See https://github.com/rust-lang/rust/issues/97463 |
| 8 | 8 | |
| 9 | //@ ignore-msvc | |
| 10 | // Reason: the rustc compilation fails due to an unresolved external symbol | |
| 11 | ||
| 12 | 9 | //@ ignore-cross-compile |
| 13 | 10 | // Reason: The compiled binary is executed. |
| 14 | ||
| 15 | use run_make_support::{cc, is_msvc, llvm_ar, run, rustc, static_lib_name}; | |
| 11 | use run_make_support::{build_native_static_lib_optimized, run, rustc}; | |
| 16 | 12 | |
| 17 | 13 | fn 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(); | |
| 24 | 17 | run("param_passing"); |
| 25 | 18 | } |