You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

libm

Package Overview
Dependencies
Maintainers
0
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

libm - cargo Package Compare versions

Comparing version
0.2.15
to
0.2.16
+175
src/math/support/int_traits/narrowing_div.rs
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
use crate::support::{CastInto, DInt, HInt, Int, MinInt, u256};
/// Trait for unsigned division of a double-wide integer
/// when the quotient doesn't overflow.
///
/// This is the inverse of widening multiplication:
/// - for any `x` and nonzero `y`: `x.widen_mul(y).checked_narrowing_div_rem(y) == Some((x, 0))`,
/// - and for any `r in 0..y`: `x.carrying_mul(y, r).checked_narrowing_div_rem(y) == Some((x, r))`,
pub trait NarrowingDiv: DInt + MinInt<Unsigned = Self> {
/// Computes `(self / n, self % n))`
///
/// # Safety
/// The caller must ensure that `self.hi() < n`, or equivalently,
/// that the quotient does not overflow.
unsafe fn unchecked_narrowing_div_rem(self, n: Self::H) -> (Self::H, Self::H);
/// Returns `Some((self / n, self % n))` when `self.hi() < n`.
fn checked_narrowing_div_rem(self, n: Self::H) -> Option<(Self::H, Self::H)> {
if self.hi() < n {
Some(unsafe { self.unchecked_narrowing_div_rem(n) })
} else {
None
}
}
}
// For primitive types we can just use the standard
// division operators in the double-wide type.
macro_rules! impl_narrowing_div_primitive {
($D:ident) => {
impl NarrowingDiv for $D {
unsafe fn unchecked_narrowing_div_rem(self, n: Self::H) -> (Self::H, Self::H) {
if self.hi() >= n {
unsafe { core::hint::unreachable_unchecked() }
}
((self / n.widen()).cast(), (self % n.widen()).cast())
}
}
};
}
// Extend division from `u2N / uN` to `u4N / u2N`
// This is not the most efficient algorithm, but it is
// relatively simple.
macro_rules! impl_narrowing_div_recurse {
($D:ident) => {
impl NarrowingDiv for $D {
unsafe fn unchecked_narrowing_div_rem(self, n: Self::H) -> (Self::H, Self::H) {
if self.hi() >= n {
unsafe { core::hint::unreachable_unchecked() }
}
// Normalize the divisor by shifting the most significant one
// to the leading position. `n != 0` is implied by `self.hi() < n`
let lz = n.leading_zeros();
let a = self << lz;
let b = n << lz;
let ah = a.hi();
let (a0, a1) = a.lo().lo_hi();
// SAFETY: For both calls, `b.leading_zeros() == 0` by the above shift.
// SAFETY: `ah < b` follows from `self.hi() < n`
let (q1, r) = unsafe { div_three_digits_by_two(a1, ah, b) };
// SAFETY: `r < b` is given as the postcondition of the previous call
let (q0, r) = unsafe { div_three_digits_by_two(a0, r, b) };
// Undo the earlier normalization for the remainder
(Self::H::from_lo_hi(q0, q1), r >> lz)
}
}
};
}
impl_narrowing_div_primitive!(u16);
impl_narrowing_div_primitive!(u32);
impl_narrowing_div_primitive!(u64);
impl_narrowing_div_primitive!(u128);
impl_narrowing_div_recurse!(u256);
/// Implement `u3N / u2N`-division on top of `u2N / uN`-division.
///
/// Returns the quotient and remainder of `(a * R + a0) / n`,
/// where `R = (1 << U::BITS)` is the digit size.
///
/// # Safety
/// Requires that `n.leading_zeros() == 0` and `a < n`.
unsafe fn div_three_digits_by_two<U>(a0: U, a: U::D, n: U::D) -> (U, U::D)
where
U: HInt,
U::D: Int + NarrowingDiv,
{
if n.leading_zeros() > 0 || a >= n {
unsafe { core::hint::unreachable_unchecked() }
}
// n = n1R + n0
let (n0, n1) = n.lo_hi();
// a = a2R + a1
let (a1, a2) = a.lo_hi();
let mut q;
let mut r;
let mut wrap;
// `a < n` is guaranteed by the caller, but `a2 == n1 && a1 < n0` is possible
if let Some((q0, r1)) = a.checked_narrowing_div_rem(n1) {
q = q0;
// a = qn1 + r1, where 0 <= r1 < n1
// Include the remainder with the low bits:
// r = a0 + r1R
r = U::D::from_lo_hi(a0, r1);
// Subtract the contribution of the divisor low bits with the estimated quotient
let d = q.widen_mul(n0);
(r, wrap) = r.overflowing_sub(d);
// Since `q` is the quotient of dividing with a slightly smaller divisor,
// it may be an overapproximation, but is never too small, and similarly,
// `r` is now either the correct remainder ...
if !wrap {
return (q, r);
}
// ... or the remainder went "negative" (by as much as `d = qn0 < RR`)
// and we have to adjust.
q -= U::ONE;
} else {
debug_assert!(a2 == n1 && a1 < n0);
// Otherwise, `a2 == n1`, and the estimated quotient would be
// `R + (a1 % n1)`, but the correct quotient can't overflow.
// We'll start from `q = R = (1 << U::BITS)`,
// so `r = aR + a0 - qn = (a - n)R + a0`
r = U::D::from_lo_hi(a0, a1.wrapping_sub(n0));
// Since `a < n`, the first decrement is always needed:
q = U::MAX; /* R - 1 */
}
(r, wrap) = r.overflowing_add(n);
if wrap {
return (q, r);
}
// If the remainder still didn't wrap, we need another step.
q -= U::ONE;
(r, wrap) = r.overflowing_add(n);
// Since `n >= RR/2`, at least one of the two `r += n` must have wrapped.
debug_assert!(wrap, "estimated quotient should be off by at most two");
(q, r)
}
#[cfg(test)]
mod test {
use super::{HInt, NarrowingDiv};
#[test]
fn inverse_mul() {
for x in 0..=u8::MAX {
for y in 1..=u8::MAX {
let xy = x.widen_mul(y);
assert_eq!(xy.checked_narrowing_div_rem(y), Some((x, 0)));
assert_eq!(
(xy + (y - 1) as u16).checked_narrowing_div_rem(y),
Some((x, y - 1))
);
if y > 1 {
assert_eq!((xy + 1).checked_narrowing_div_rem(y), Some((x, 1)));
assert_eq!(
(xy + (y - 2) as u16).checked_narrowing_div_rem(y),
Some((x, y - 2))
);
}
}
}
}
}
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
//! This module provides accelerated modular multiplication by large powers
//! of two, which is needed for computing floating point remainders in `fmod`
//! and similar functions.
//!
//! To keep the equations somewhat concise, the following conventions are used:
//! - all integer operations are in the mathematical sense, without overflow
//! - concatenation means multiplication: `2xq = 2 * x * q`
//! - `R = (1 << U::BITS)` is the modulus of wrapping arithmetic in `U`
use crate::support::int_traits::NarrowingDiv;
use crate::support::{DInt, HInt, Int};
/// Compute the remainder `(x << e) % y` with unbounded integers.
/// Requires `x < 2y` and `y.leading_zeros() >= 2`
pub fn linear_mul_reduction<U>(x: U, mut e: u32, mut y: U) -> U
where
U: HInt + Int<Unsigned = U>,
U::D: NarrowingDiv,
{
assert!(y <= U::MAX >> 2);
assert!(x < (y << 1));
let _0 = U::ZERO;
let _1 = U::ONE;
// power of two divisors
if (y & (y - _1)).is_zero() {
if e < U::BITS {
// shift and only keep low bits
return (x << e) & (y - _1);
} else {
// would shift out all the bits
return _0;
}
}
// Use the identity `(x << e) % y == ((x << (e + s)) % (y << s)) >> s`
// to shift the divisor so it has exactly two leading zeros to satisfy
// the precondition of `Reducer::new`
let s = y.leading_zeros() - 2;
e += s;
y <<= s;
// `m: Reducer` keeps track of the remainder `x` in a form that makes it
// very efficient to do `x <<= k` modulo `y` for integers `k < U::BITS`
let mut m = Reducer::new(x, y);
// Use the faster special case with constant `k == U::BITS - 1` while we can
while e >= U::BITS - 1 {
m.word_reduce();
e -= U::BITS - 1;
}
// Finish with the variable shift operation
m.shift_reduce(e);
// The partial remainder is in `[0, 2y)` ...
let r = m.partial_remainder();
// ... so check and correct, and compensate for the earlier shift.
r.checked_sub(y).unwrap_or(r) >> s
}
/// Helper type for computing the reductions. The implementation has a number
/// of seemingly weird choices, but everything is aimed at streamlining
/// `Reducer::word_reduce` into its current form.
///
/// Implicitly contains:
/// n in (R/8, R/4)
/// x in [0, 2n)
/// The value of `n` is fixed for a given `Reducer`,
/// but the value of `x` is modified by the methods.
#[derive(Debug, Clone, PartialEq, Eq)]
struct Reducer<U: HInt> {
// m = 2n
m: U,
// q = (RR/2) / m
// r = (RR/2) % m
// Then RR/2 = qm + r, where `0 <= r < m`
// The value `q` is only needed during construction, so isn't saved.
r: U,
// The value `x` is implicitly stored as `2 * q * x`:
_2xq: U::D,
}
impl<U> Reducer<U>
where
U: HInt,
U: Int<Unsigned = U>,
{
/// Construct a reducer for `(x << _) mod n`.
///
/// Requires `R/8 < n < R/4` and `x < 2n`.
fn new(x: U, n: U) -> Self
where
U::D: NarrowingDiv,
{
let _1 = U::ONE;
assert!(n > (_1 << (U::BITS - 3)));
assert!(n < (_1 << (U::BITS - 2)));
let m = n << 1;
assert!(x < m);
// We need to compute the parameters
// `q = (RR/2) / m`
// `r = (RR/2) % m`
// Since `m` is in `(R/4, R/2)`, the quotient `q` is in `[R, 2R)`, and
// it would overflow in `U` if computed directly. Instead, we compute
// `f = q - R`, which is in `[0, R)`. To do so, we simply subtract `Rm`
// from the dividend, which doesn't change the remainder:
// `f = R(R/2 - m) / m`
// `r = R(R/2 - m) % m`
let dividend = ((_1 << (U::BITS - 1)) - m).widen_hi();
let (f, r) = dividend.checked_narrowing_div_rem(m).unwrap();
// As `x < m`, `xq < qm <= RR/2`
// Thus `2xq = 2xR + 2xf` does not overflow in `U::D`.
let _2x = x + x;
let _2xq = _2x.widen_hi() + _2x.widen_mul(f);
Self { m, r, _2xq }
}
/// Extract the current remainder `x` in the range `[0, 2n)`
fn partial_remainder(&self) -> U {
// `RR/2 = qm + r`, where `0 <= r < m`
// `2xq = uR + v`, where `0 <= v < R`
// The goal is to extract the current value of `x` from the value `2xq`
// that we actually have. A bit simplified, we could multiply it by `m`
// to obtain `2xqm == 2x(RR/2 - r) == xRR - 2xr`, where `2xr < RR`.
// We could just round that up to the next multiple of `RR` to get `x`,
// but we can avoid having to multiply the full double-wide `2xq` by
// making a couple of adjustments:
// First, let's only use the high half `u` for the product, and
// include an additional error term due to the truncation:
// `mu = xR - (2xr + mv)/R`
// Next, show bounds for the error term
// `0 <= mv < mR` follows from `0 <= v < R`
// `0 <= 2xr < mR` follows from `0 <= x < m < R/2` and `0 <= r < m`
// Adding those together, we have:
// `0 <= (mv + 2xr)/R < 2m`
// Which also implies:
// `0 < 2m - (mv + 2xr)/R <= 2m < R`
// For that reason, we can use `u + 2` as the factor to obtain
// `m(u + 2) = xR + (2m - (mv + 2xr)/R)`
// By the previous inequality, the second term fits neatly in the lower
// half, so we get exactly `x` as the high half.
let u = self._2xq.hi();
let _2 = U::ONE + U::ONE;
self.m.widen_mul(u + _2).hi()
// Additionally, we should ensure that `u + 2` cannot overflow:
// Since `x < m` and `2qm <= RR`,
// `2xq <= 2q(m-1) <= RR - 2q`
// As we also have `q > R`,
// `2xq < RR - 2R`
// which is sufficient.
}
/// Replace the remainder `x` with `(x << k) - un`,
/// for a suitable quotient `u`, which is returned.
///
/// Requires that `k < U::BITS`.
fn shift_reduce(&mut self, k: u32) -> U {
assert!(k < U::BITS);
// First, split the shifted value:
// `2xq << k = aRR/2 + b`, where `0 <= b < RR/2`
let a = self._2xq.hi() >> (U::BITS - 1 - k);
let (low, high) = (self._2xq << k).lo_hi();
let b = U::D::from_lo_hi(low, high & (U::MAX >> 1));
// Then, subtract `2anq = aqm`:
// ```
// (2xq << k) - aqm
// = aRR/2 + b - aqm
// = a(RR/2 - qm) + b
// = ar + b
// ```
self._2xq = a.widen_mul(self.r) + b;
a
// Since `a` is at most the high half of `2xq`, we have
// `a + 2 < R` (shown above, in `partial_remainder`)
// Using that together with `b < RR/2` and `r < m < R/2`,
// we get `(a + 2)r + b < RR`, so
// `ar + b < RR - 2r = 2mq`
// which shows that the new remainder still satisfies `x < m`.
}
// NB: `word_reduce()` is just the special case `shift_reduce(U::BITS - 1)`
// that optimizes especially well. The correspondence is that `a == u` and
// `b == (v >> 1).widen_hi()`
//
/// Replace the remainder `x` with `x(R/2) - un`,
/// for a suitable quotient `u`, which is returned.
fn word_reduce(&mut self) -> U {
// To do so, we replace `2xq = uR + v` with
// ```
// 2 * (x(R/2) - un) * q
// = xqR - 2unq
// = xqR - uqm
// = uRR/2 + vR/2 - uRR/2 + ur
// = ur + (v/2)R
// ```
let (v, u) = self._2xq.lo_hi();
self._2xq = u.widen_mul(self.r) + U::widen_hi(v >> 1);
u
// Additional notes:
// 1. As `v` is the low bits of `2xq`, it is even and can be halved.
// 2. The new remainder is `(xr + mv/2) / R` (see below)
// and since `v < R`, `r < m`, `x < m < R/2`,
// that is also strictly less than `m`.
// ```
// (x(R/2) - un)R
// = xRR/2 - (m/2)uR
// = x(qm + r) - (m/2)(2xq - v)
// = xqm + xr - xqm + mv/2
// = xr + mv/2
// ```
}
}
#[cfg(test)]
mod test {
use crate::support::linear_mul_reduction;
use crate::support::modular::Reducer;
#[test]
fn reducer_ops() {
for n in 33..=63_u8 {
for x in 0..2 * n {
let temp = Reducer::new(x, n);
let n = n as u32;
let x0 = temp.partial_remainder() as u32;
assert_eq!(x as u32, x0);
for k in 0..=7 {
let mut red = temp.clone();
let u = red.shift_reduce(k) as u32;
let x1 = red.partial_remainder() as u32;
assert_eq!(x1, (x0 << k) - u * n);
assert!(x1 < 2 * n);
assert!((red._2xq as u32).is_multiple_of(2 * x1));
// `word_reduce` is equivalent to
// `shift_reduce(U::BITS - 1)`
if k == 7 {
let mut alt = temp.clone();
let w = alt.word_reduce();
assert_eq!(u, w as u32);
assert_eq!(alt, red);
}
}
}
}
}
#[test]
fn reduction_u8() {
for y in 1..64u8 {
for x in 0..2 * y {
let mut r = x % y;
for e in 0..100 {
assert_eq!(r, linear_mul_reduction(x, e, y));
// maintain the correct expected remainder
r <<= 1;
if r >= y {
r -= y;
}
}
}
}
}
#[test]
fn reduction_u128() {
assert_eq!(
linear_mul_reduction::<u128>(17, 100, 123456789),
(17 << 100) % 123456789
);
// power-of-two divisor
assert_eq!(
linear_mul_reduction(0xdead_beef, 100, 1_u128 << 116),
0xbeef << 100
);
let x = 10_u128.pow(37);
let y = 11_u128.pow(36);
assert!(x < y);
let mut r = x;
for e in 0..1000 {
assert_eq!(r, linear_mul_reduction(x, e, y));
// maintain the correct expected remainder
r <<= 1;
if r >= y {
r -= y;
}
assert!(r != 0);
}
}
}
+1
-1
{
"git": {
"sha1": "a4c748f72a1dce652cc3e41c3a8425731bd1519a"
"sha1": "dfd2203a4d6110820ad7bb65cafe1bf331a03a3d"
},
"path_in_vcs": "libm"
}

@@ -7,3 +7,3 @@ # This file is automatically @generated by Cargo.

name = "libm"
version = "0.2.15"
version = "0.2.16"
dependencies = [

@@ -15,5 +15,5 @@ "no-panic",

name = "no-panic"
version = "0.1.35"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "113d1abd5bb3dc25a75d9b3a973f40e31eb03e0bae23c172b32cca4bcb9cfad2"
checksum = "f967505aabc8af5752d098c34146544a43684817cdba8f9725b292530cabbf53"
dependencies = [

@@ -27,5 +27,5 @@ "proc-macro2",

name = "proc-macro2"
version = "1.0.95"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [

@@ -37,5 +37,5 @@ "unicode-ident",

name = "quote"
version = "1.0.40"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [

@@ -47,5 +47,5 @@ "proc-macro2",

name = "syn"
version = "2.0.101"
version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [

@@ -59,4 +59,4 @@ "proc-macro2",

name = "unicode-ident"
version = "1.0.18"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"

@@ -16,4 +16,9 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO

name = "libm"
version = "0.2.15"
authors = ["Jorge Aparicio <jorge@japaric.io>"]
version = "0.2.16"
authors = [
"Alex Crichton <alex@alexcrichton.com>",
"Amanieu d'Antras <amanieu@gmail.com>",
"Jorge Aparicio <japaricious@gmail.com>",
"Trevor Gross <tg@trevorgross.com>",
]
build = "build.rs"

@@ -26,3 +31,2 @@ autolib = false

description = "libm in pure Rust"
documentation = "https://docs.rs/libm"
readme = "README.md"

@@ -29,0 +33,0 @@ keywords = [

@@ -11,2 +11,18 @@ # Changelog

## [0.2.16](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.15...libm-v0.2.16) - 2025-12-07
### Fixed
- Fix an incorrect result for `fminimum` and `fmaximum` with the input (-0, NaN)
- Fix a typo in `libm::Libm::roundeven`
- Fix the `expm1f` overflow threshold
- Change `CmpResult` to use a pointer-sized return type
- Compare against `CARGO_CFG_TARGET_FAMILY` in a multi-valued fashion
- Implement `exp` and its variants for i586 with inline assembly
- Implement `floor` and `ceil` in assembly on `i586`
### Other
- Significantly optimize `fmod` worst case performance ([#1002](https://github.com/rust-lang/compiler-builtins/pull/1002))
## [0.2.15](https://github.com/rust-lang/compiler-builtins/compare/libm-v0.2.14...libm-v0.2.15) - 2025-05-06

@@ -13,0 +29,0 @@

@@ -6,2 +6,3 @@ // Configuration shared with both libm and libm-test

#[derive(Debug)]
#[allow(dead_code)]

@@ -13,5 +14,6 @@ pub struct Config {

pub cargo_features: Vec<String>,
pub target_triple: String,
pub target_arch: String,
pub target_env: String,
pub target_family: Option<String>,
pub target_families: Vec<String>,
pub target_os: String,

@@ -21,2 +23,4 @@ pub target_string: String,

pub target_features: Vec<String>,
pub reliable_f128: bool,
pub reliable_f16: bool,
}

@@ -26,2 +30,6 @@

pub fn from_env() -> Self {
let target_triple = env::var("TARGET").unwrap();
let target_families = env::var("CARGO_CFG_TARGET_FAMILY")
.map(|feats| feats.split(',').map(ToOwned::to_owned).collect())
.unwrap_or_default();
let target_features = env::var("CARGO_CFG_TARGET_FEATURE")

@@ -36,2 +44,3 @@ .map(|feats| feats.split(',').map(ToOwned::to_owned).collect())

Self {
target_triple,
manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()),

@@ -43,3 +52,3 @@ out_dir: PathBuf::from(env::var("OUT_DIR").unwrap()),

target_env: env::var("CARGO_CFG_TARGET_ENV").unwrap(),
target_family: env::var("CARGO_CFG_TARGET_FAMILY").ok(),
target_families,
target_os: env::var("CARGO_CFG_TARGET_OS").unwrap(),

@@ -49,2 +58,6 @@ target_string: env::var("TARGET").unwrap(),

target_features,
// Note that these are unstable options, so only show up with the nightly compiler or
// with `RUSTC_BOOTSTRAP=1` (which is required to use the types anyway).
reliable_f128: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F128").is_some(),
reliable_f16: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F16").is_some(),
}

@@ -138,60 +151,16 @@ }

// Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means
// that the backend will not crash when using these types and generates code that can be called
// without crashing (no infinite recursion). This does not mean that the platform doesn't have
// ABI or other bugs.
//
// We do this here rather than in `rust-lang/rust` because configuring via cargo features is
// not straightforward.
//
// Original source of this list:
// <https://github.com/rust-lang/compiler-builtins/pull/652#issuecomment-2266151350>
let f16_enabled = match cfg.target_arch.as_str() {
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
"arm64ec" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/50374>
"s390x" => false,
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
// FIXME(llvm): loongarch fixed by <https://github.com/llvm/llvm-project/pull/107791>
"csky" => false,
"hexagon" => false,
"loongarch64" => false,
"mips" | "mips64" | "mips32r6" | "mips64r6" => false,
"powerpc" | "powerpc64" => false,
"sparc" | "sparc64" => false,
"wasm32" | "wasm64" => false,
// Most everything else works as of LLVM 19
_ => true,
};
/* See the compiler-builtins configure file for info about the meaning of these options */
let f128_enabled = match cfg.target_arch.as_str() {
// Unsupported (libcall is not supported) <https://github.com/llvm/llvm-project/issues/121122>
"amdgpu" => false,
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
"arm64ec" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/96432>
"mips64" | "mips64r6" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/95471>
"nvptx64" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/101545>
"powerpc64" if &cfg.target_os == "aix" => false,
// Selection failure <https://github.com/llvm/llvm-project/issues/41838>
"sparc" => false,
// Most everything else works as of LLVM 19
_ => true,
};
// If the feature is set, disable both of these types.
let no_f16_f128 = cfg.cargo_features.iter().any(|s| s == "no-f16-f128");
// If the feature is set, disable these types.
let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some();
println!("cargo:rustc-check-cfg=cfg(f16_enabled)");
println!("cargo:rustc-check-cfg=cfg(f128_enabled)");
if f16_enabled && !disable_both {
if cfg.reliable_f16 && !no_f16_f128 {
println!("cargo:rustc-cfg=f16_enabled");
}
if f128_enabled && !disable_both {
println!("cargo:rustc-check-cfg=cfg(f128_enabled)");
if cfg.reliable_f128 && !no_f16_f128 {
println!("cargo:rustc-cfg=f128_enabled");
}
}

@@ -37,3 +37,3 @@ # `libm`

Contributions are licensed under both the MIT license and the Apache License,
Version 2.0, available at <htps://www.apache.org/licenses/LICENSE-2.0>. Unless
Version 2.0, available at <https://www.apache.org/licenses/LICENSE-2.0>. Unless
you explicitly state otherwise, any contribution intentionally submitted for

@@ -40,0 +40,0 @@ inclusion in the work by you, as defined in the Apache-2.0 license, shall be

@@ -171,3 +171,3 @@ use core::marker::PhantomData;

(fn round(x: f64) -> (f64); => round);
(fn roundevem(x: f64) -> (f64); => roundeven);
(fn roundeven(x: f64) -> (f64); => roundeven);
(fn scalbn(x: f64, n: i32) -> (f64); => scalbn);

@@ -174,0 +174,0 @@ (fn sin(x: f64) -> (f64); => sin);

@@ -62,3 +62,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_acos.c */

/// Returns values in radians, in the range of 0 to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn acos(x: f64) -> f64 {

@@ -65,0 +65,0 @@ let x1p_120f = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ -120

@@ -36,3 +36,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_acosf.c */

/// Returns values in radians, in the range of 0 to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn acosf(x: f32) -> f32 {

@@ -39,0 +39,0 @@ let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)

@@ -10,3 +10,3 @@ use super::{log, log1p, sqrt};

/// `x` must be a number greater than or equal to 1.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn acosh(x: f64) -> f64 {

@@ -13,0 +13,0 @@ let u = x.to_bits();

@@ -10,3 +10,3 @@ use super::{log1pf, logf, sqrtf};

/// `x` must be a number greater than or equal to 1.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn acoshf(x: f32) -> f32 {

@@ -13,0 +13,0 @@ let u = x.to_bits();

@@ -33,2 +33,8 @@ //! Architecture-specific support for aarch64 with neon.

// NB: `frintx` is technically the correct instruction for C's `rint`. However, in Rust (and LLVM
// by default), `rint` is identical to `roundeven` (no fpenv interaction) so we use the
// side-effect-free `frintn`.
//
// In general, C code that calls Rust's libm should assume that fpenv is ignored.
pub fn rint(mut x: f64) -> f64 {

@@ -35,0 +41,0 @@ // SAFETY: `frintn` is available with neon and has no side effects.

//! Architecture-specific support for x86-32 without SSE2
//!
//! We use an alternative implementation on x86, because the
//! main implementation fails with the x87 FPU used by
//! debian i386, probably due to excess precision issues.
//!
//! See https://github.com/rust-lang/compiler-builtins/pull/976 for discussion on why these
//! functions are implemented in this way.
use super::super::fabs;
/// Use an alternative implementation on x86, because the
/// main implementation fails with the x87 FPU used by
/// debian i386, probably due to excess precision issues.
/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219.
pub fn ceil(x: f64) -> f64 {
if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() {
let truncated = x as i64 as f64;
if truncated < x {
return truncated + 1.0;
} else {
return truncated;
}
} else {
return x;
pub fn ceil(mut x: f64) -> f64 {
unsafe {
core::arch::asm!(
"fld qword ptr [{x}]",
// Save the FPU control word, using `x` as scratch space.
"fstcw [{x}]",
// Set rounding control to 0b10 (+∞).
"mov word ptr [{x} + 2], 0x0b7f",
"fldcw [{x} + 2]",
// Round.
"frndint",
// Restore FPU control word.
"fldcw [{x}]",
// Save rounded value to memory.
"fstp qword ptr [{x}]",
x = in(reg) &mut x,
// All the x87 FPU stack is used, all registers must be clobbered
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
}
x
}
/// Use an alternative implementation on x86, because the
/// main implementation fails with the x87 FPU used by
/// debian i386, probably due to excess precision issues.
/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219.
pub fn floor(x: f64) -> f64 {
if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() {
let truncated = x as i64 as f64;
if truncated > x {
return truncated - 1.0;
} else {
return truncated;
}
} else {
return x;
pub fn floor(mut x: f64) -> f64 {
unsafe {
core::arch::asm!(
"fld qword ptr [{x}]",
// Save the FPU control word, using `x` as scratch space.
"fstcw [{x}]",
// Set rounding control to 0b01 (-∞).
"mov word ptr [{x} + 2], 0x077f",
"fldcw [{x} + 2]",
// Round.
"frndint",
// Restore FPU control word.
"fldcw [{x}]",
// Save rounded value to memory.
"fstp qword ptr [{x}]",
x = in(reg) &mut x,
// All the x87 FPU stack is used, all registers must be clobbered
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
}
x
}
/// Implements the exponential functions with `x87` assembly.
///
/// This relies on the instruction `f2xm1`, which computes `2^x - 1` (for
/// |x| < 1). This transcendental instruction is documented to produce results
/// with error below 1ulp (in the native double-extended precision format). This
/// translates to correctly rounded results for f32, but results in f64 may have
/// 1ulp error, which may depend on the hardware.
macro_rules! x87exp {
($float_ty:ident, $word_size:literal, $fn_name:ident, $load_op:literal) => {
pub fn $fn_name(mut x: $float_ty) -> $float_ty { unsafe {
core::arch::asm!(
// Prepare the register stack as
// ```
// st(0) = y = x*log2(base)
// st(1) = 1.0
// st(2) = round(y)
// ```
concat!($load_op, " ", $word_size, " ptr [{x}]"),
"fld1",
"fld st(1)",
"frndint",
"fxch st(2)",
// Compare y with round(y) to determine if y is finite and
// not an integer. If so, compute `exp2(y - round(y))` into
// st(1). Otherwise skip ahead with `st(1) = 1.0`
"fucom st(2)",
"fstsw ax",
"test ax, 0x4000",
"jnz 2f",
"fsub st(0), st(2)", // st(0) = y - round(y)
"f2xm1", // st(0) = 2^st(0) - 1.0
"fadd st(1), st(0)", // st(1) = 1 + st(0) = exp2(y - round(y))
"2:",
// Finally, scale by `exp2(round(y))` and clear the stack.
"fstp st(0)",
"fscale",
concat!("fstp ", $word_size, " ptr [{x}]"),
"fstp st(0)",
x = in(reg) &mut x,
out("ax") _,
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
x
}}
};
}
x87exp!(f32, "dword", x87_exp2f, "fld");
x87exp!(f64, "qword", x87_exp2, "fld");
x87exp!(f32, "dword", x87_exp10f, "fldl2t\nfmul");
x87exp!(f64, "qword", x87_exp10, "fldl2t\nfmul");
x87exp!(f32, "dword", x87_expf, "fldl2e\nfmul");
x87exp!(f64, "qword", x87_exp, "fldl2e\nfmul");

@@ -51,1 +51,6 @@ //! Architecture-specific routines and operations.

}
cfg_if! {
if #[cfg(x86_no_sse)] {
pub use i586::{x87_exp10f, x87_exp10, x87_expf, x87_exp, x87_exp2f, x87_exp2};
}
}

@@ -42,2 +42,4 @@ // Using runtime feature detection requires atomics. Currently there are no x86 targets

/// [std-detect]: https://github.com/rust-lang/stdarch/blob/690b3a6334d482874163bd6fcef408e0518febe9/crates/std_detect/src/detect/os/x86.rs#L142
// FIXME(msrv): Remove unsafe block around __cpuid once https://github.com/rust-lang/stdarch/pull/1935 is available in MSRV.
#[allow(unused_unsafe)]
fn load_x86_features() -> Flags {

@@ -44,0 +46,0 @@ let mut value = Flags::empty();

@@ -69,3 +69,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_asin.c */

/// Returns values in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn asin(mut x: f64) -> f64 {

@@ -72,0 +72,0 @@ let z: f64;

@@ -38,3 +38,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_asinf.c */

/// Returns values in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn asinf(mut x: f32) -> f32 {

@@ -41,0 +41,0 @@ let x1p_120 = f64::from_bits(0x3870000000000000); // 0x1p-120 === 2 ^ (-120)

@@ -10,3 +10,3 @@ use super::{log, log1p, sqrt};

/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn asinh(mut x: f64) -> f64 {

@@ -13,0 +13,0 @@ let mut u = x.to_bits();

@@ -10,3 +10,3 @@ use super::{log1pf, logf, sqrtf};

/// Is defined as `sgn(x)*log(|x|+sqrt(x*x+1))`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn asinhf(mut x: f32) -> f32 {

@@ -13,0 +13,0 @@ let u = x.to_bits();

@@ -32,4 +32,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_atan.c */

use core::f64;
use super::fabs;

@@ -69,3 +67,3 @@

/// Returns a value in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn atan(x: f64) -> f64 {

@@ -139,3 +137,3 @@ let mut x = x;

mod tests {
use core::f64;
use core::f64::consts;

@@ -147,8 +145,8 @@ use super::atan;

for (input, answer) in [
(3.0_f64.sqrt() / 3.0, f64::consts::FRAC_PI_6),
(1.0, f64::consts::FRAC_PI_4),
(3.0_f64.sqrt(), f64::consts::FRAC_PI_3),
(-3.0_f64.sqrt() / 3.0, -f64::consts::FRAC_PI_6),
(-1.0, -f64::consts::FRAC_PI_4),
(-3.0_f64.sqrt(), -f64::consts::FRAC_PI_3),
(3.0_f64.sqrt() / 3.0, consts::FRAC_PI_6),
(1.0, consts::FRAC_PI_4),
(3.0_f64.sqrt(), consts::FRAC_PI_3),
(-3.0_f64.sqrt() / 3.0, -consts::FRAC_PI_6),
(-1.0, -consts::FRAC_PI_4),
(-3.0_f64.sqrt(), -consts::FRAC_PI_3),
]

@@ -174,3 +172,3 @@ .iter()

fn infinity() {
assert_eq!(atan(f64::INFINITY), f64::consts::FRAC_PI_2);
assert_eq!(atan(f64::INFINITY), consts::FRAC_PI_2);
}

@@ -180,3 +178,3 @@

fn minus_infinity() {
assert_eq!(atan(f64::NEG_INFINITY), -f64::consts::FRAC_PI_2);
assert_eq!(atan(f64::NEG_INFINITY), -consts::FRAC_PI_2);
}

@@ -183,0 +181,0 @@

@@ -50,3 +50,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_atan2.c */

/// Returns a value in radians, in the range of -pi to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn atan2(y: f64, x: f64) -> f64 {

@@ -53,0 +53,0 @@ if x.is_nan() || y.is_nan() {

@@ -26,3 +26,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_atan2f.c */

/// Returns a value in radians, in the range of -pi to pi.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn atan2f(y: f32, x: f32) -> f32 {

@@ -29,0 +29,0 @@ if x.is_nan() || y.is_nan() {

@@ -44,3 +44,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_atanf.c */

/// Returns a value in radians, in the range of -pi/2 to pi/2.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn atanf(mut x: f32) -> f32 {

@@ -47,0 +47,0 @@ let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)

@@ -8,3 +8,3 @@ use super::log1p;

/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn atanh(x: f64) -> f64 {

@@ -11,0 +11,0 @@ let u = x.to_bits();

@@ -8,3 +8,3 @@ use super::log1pf;

/// Is defined as `log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn atanhf(mut x: f32) -> f32 {

@@ -11,0 +11,0 @@ let mut u = x.to_bits();

@@ -11,3 +11,3 @@ /* SPDX-License-Identifier: MIT */

/// Compute the cube root of the argument.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cbrt(x: f64) -> f64 {

@@ -14,0 +14,0 @@ cbrt_round(x, Round::Nearest).val

@@ -20,4 +20,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */

use core::f32;
const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */

@@ -29,3 +27,3 @@ const B2: u32 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */

/// Computes the cube root of the argument.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cbrtf(x: f32) -> f32 {

@@ -32,0 +30,0 @@ let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24

@@ -5,3 +5,3 @@ /// Ceil (f16)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceilf16(x: f16) -> f16 {

@@ -14,3 +14,3 @@ super::generic::ceil(x)

/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceilf(x: f32) -> f32 {

@@ -29,3 +29,3 @@ select_implementation! {

/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceil(x: f64) -> f64 {

@@ -46,5 +46,5 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceilf128(x: f128) -> f128 {
super::generic::ceil(x)
}

@@ -6,3 +6,3 @@ /// Sign of Y, magnitude of X (f16)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysignf16(x: f16, y: f16) -> f16 {

@@ -16,3 +16,3 @@ super::generic::copysign(x, y)

/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysignf(x: f32, y: f32) -> f32 {

@@ -26,3 +26,3 @@ super::generic::copysign(x, y)

/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysign(x: f64, y: f64) -> f64 {

@@ -37,3 +37,3 @@ super::generic::copysign(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysignf128(x: f128, y: f128) -> f128 {

@@ -66,5 +66,13 @@ super::generic::copysign(x, y)

assert_biteq!(f(F::NAN, F::NAN), F::NAN);
assert_biteq!(f(F::NAN, F::ONE), F::NAN);
assert_biteq!(f(F::NAN, F::NEG_ONE), F::NEG_NAN);
assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN);
assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN);
assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN);
assert_biteq!(f(F::NEG_NAN, F::ONE), F::NAN);
assert_biteq!(f(F::NEG_NAN, F::NEG_ONE), F::NEG_NAN);
assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN);
assert_biteq!(f(F::ONE, F::NAN), F::ONE);
assert_biteq!(f(F::ONE, F::NEG_NAN), F::NEG_ONE);
assert_biteq!(f(F::NEG_ONE, F::NAN), F::ONE);
assert_biteq!(f(F::NEG_ONE, F::NEG_NAN), F::NEG_ONE);
}

@@ -71,0 +79,0 @@

@@ -48,3 +48,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cos(x: f64) -> f64 {

@@ -51,0 +51,0 @@ let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;

@@ -30,3 +30,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_cosf.c */

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cosf(x: f32) -> f32 {

@@ -33,0 +33,0 @@ let x64 = x as f64;

@@ -8,3 +8,3 @@ use super::{exp, expm1, k_expo2};

/// Angles are specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cosh(mut x: f64) -> f64 {

@@ -11,0 +11,0 @@ /* |x| */

@@ -8,3 +8,3 @@ use super::{expf, expm1f, k_expo2f};

/// Angles are specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn coshf(mut x: f32) -> f32 {

@@ -11,0 +11,0 @@ let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120

@@ -222,3 +222,3 @@ use super::{exp, fabs, get_high_word, with_set_low_word};

/// deviations of the mean (assuming a normal distribution).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn erf(x: f64) -> f64 {

@@ -225,0 +225,0 @@ let r: f64;

@@ -133,3 +133,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_erff.c */

/// deviations of the mean (assuming a normal distribution).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn erff(x: f32) -> f32 {

@@ -136,0 +136,0 @@ let r: f32;

@@ -84,4 +84,10 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_exp.c */

/// (where *e* is the base of the natural system of logarithms, approximately 2.71828).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn exp(mut x: f64) -> f64 {
select_implementation! {
name: x87_exp,
use_arch_required: x86_no_sse,
args: x,
}
let x1p1023 = f64::from_bits(0x7fe0000000000000); // 0x1p1023 === 2 ^ 1023

@@ -88,0 +94,0 @@ let x1p_149 = f64::from_bits(0x36a0000000000000); // 0x1p-149 === 2 ^ -149

@@ -10,4 +10,10 @@ use super::{exp2, modf, pow};

/// Calculates 10 raised to the power of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn exp10(x: f64) -> f64 {
select_implementation! {
name: x87_exp10,
use_arch_required: x86_no_sse,
args: x,
}
let (mut y, n) = modf(x);

@@ -14,0 +20,0 @@ let u: u64 = n.to_bits();

@@ -10,4 +10,10 @@ use super::{exp2, exp2f, modff};

/// Calculates 10 raised to the power of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn exp10f(x: f32) -> f32 {
select_implementation! {
name: x87_exp10f,
use_arch_required: x86_no_sse,
args: x,
}
let (mut y, n) = modff(x);

@@ -14,0 +20,0 @@ let u = n.to_bits();

@@ -325,4 +325,10 @@ // origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */

/// Calculate `2^x`, that is, 2 raised to the power `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn exp2(mut x: f64) -> f64 {
select_implementation! {
name: x87_exp2,
use_arch_required: x86_no_sse,
args: x,
}
let redux = f64::from_bits(0x4338000000000000) / TBLSIZE as f64;

@@ -329,0 +335,0 @@ let p1 = f64::from_bits(0x3fe62e42fefa39ef);

@@ -76,4 +76,10 @@ // origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c

/// Calculate `2^x`, that is, 2 raised to the power `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn exp2f(mut x: f32) -> f32 {
select_implementation! {
name: x87_exp2f,
use_arch_required: x86_no_sse,
args: x,
}
let redux = f32::from_bits(0x4b400000) / TBLSIZE as f32;

@@ -80,0 +86,0 @@ let p1 = f32::from_bits(0x3f317218);

@@ -33,4 +33,10 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */

/// (where *e* is the base of the natural system of logarithms, approximately 2.71828).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn expf(mut x: f32) -> f32 {
select_implementation! {
name: x87_expf,
use_arch_required: x86_no_sse,
args: x,
}
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127

@@ -37,0 +43,0 @@ let x1p_126 = f32::from_bits(0x800000); // 0x1p-126f === 2 ^ -126 /*original 0x1p-149f ??????????? */

@@ -13,4 +13,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */

use core::f64;
const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */

@@ -34,3 +32,3 @@ const LN2_HI: f64 = 6.93147180369123816490e-01; /* 0x3fe62e42, 0xfee00000 */

/// where using `exp(x)-1` would lose many significant digits.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn expm1(mut x: f64) -> f64 {

@@ -37,0 +35,0 @@ let hi: f64;

@@ -16,3 +16,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */

const O_THRESHOLD: f32 = 8.8721679688e+01; /* 0x42b17180 */
const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */

@@ -36,3 +35,3 @@ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */

/// where using `exp(x)-1` would lose many significant digits.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn expm1f(mut x: f32) -> f32 {

@@ -55,3 +54,4 @@ let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127

}
if x > O_THRESHOLD {
if hx > 0x42b17217 {
/* x > log(FLT_MAX) */
x *= x1p127;

@@ -58,0 +58,0 @@ return x;

use super::{combine_words, exp};
/* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn expo2(x: f64) -> f64 {

@@ -6,0 +6,0 @@ /* k is such that k*ln2 has minimal relative error and x - kln2 > log(DBL_MIN) */

@@ -6,3 +6,3 @@ /// Absolute value (magnitude) (f16)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabsf16(x: f16) -> f16 {

@@ -16,3 +16,3 @@ super::generic::fabs(x)

/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabsf(x: f32) -> f32 {

@@ -32,3 +32,3 @@ select_implementation! {

/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabs(x: f64) -> f64 {

@@ -49,3 +49,3 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabsf128(x: f128) -> f128 {

@@ -52,0 +52,0 @@ super::generic::fabs(x)

@@ -10,3 +10,3 @@ /// Positive difference (f16)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdimf16(x: f16, y: f16) -> f16 {

@@ -24,3 +24,3 @@ super::generic::fdim(x, y)

/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdimf(x: f32, y: f32) -> f32 {

@@ -38,3 +38,3 @@ super::generic::fdim(x, y)

/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdim(x: f64, y: f64) -> f64 {

@@ -53,5 +53,5 @@ super::generic::fdim(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdimf128(x: f128, y: f128) -> f128 {
super::generic::fdim(x, y)
}

@@ -5,3 +5,3 @@ /// Floor (f16)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn floorf16(x: f16) -> f16 {

@@ -14,3 +14,3 @@ return super::generic::floor(x);

/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn floor(x: f64) -> f64 {

@@ -30,3 +30,3 @@ select_implementation! {

/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn floorf(x: f32) -> f32 {

@@ -46,5 +46,5 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn floorf128(x: f128) -> f128 {
return super::generic::floor(x);
}

@@ -10,3 +10,3 @@ /* SPDX-License-Identifier: MIT */

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn fmaf16(_x: f16, _y: f16, _z: f16) -> f16 {

@@ -19,3 +19,3 @@ unimplemented!()

/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaf(x: f32, y: f32, z: f32) -> f32 {

@@ -37,3 +37,3 @@ select_implementation! {

/// Computes `(x*y)+z`, rounded as one ternary operation (i.e. calculated with infinite precision).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fma(x: f64, y: f64, z: f64) -> f64 {

@@ -56,3 +56,3 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaf128(x: f128, y: f128, z: f128) -> f128 {

@@ -59,0 +59,0 @@ generic::fma_round(x, y, z, Round::Nearest).val

@@ -6,3 +6,3 @@ /// Return the lesser of two arguments or, if either argument is NaN, the other argument.

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminf16(x: f16, y: f16) -> f16 {

@@ -16,3 +16,3 @@ super::generic::fmin(x, y)

/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminf(x: f32, y: f32) -> f32 {

@@ -26,3 +26,3 @@ super::generic::fmin(x, y)

/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmin(x: f64, y: f64) -> f64 {

@@ -37,3 +37,3 @@ super::generic::fmin(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminf128(x: f128, y: f128) -> f128 {

@@ -48,3 +48,3 @@ super::generic::fmin(x, y)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaxf16(x: f16, y: f16) -> f16 {

@@ -58,3 +58,3 @@ super::generic::fmax(x, y)

/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaxf(x: f32, y: f32) -> f32 {

@@ -68,3 +68,3 @@ super::generic::fmax(x, y)

/// the inputs are -0.0 and +0.0, either may be returned).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmax(x: f64, y: f64) -> f64 {

@@ -79,3 +79,3 @@ super::generic::fmax(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaxf128(x: f128, y: f128) -> f128 {

@@ -93,12 +93,60 @@ super::generic::fmax(x, y)

(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::ZERO, F::INFINITY, F::ZERO),
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
(F::ZERO, F::NAN, F::ZERO),
(F::ZERO, F::NEG_NAN, F::ZERO),
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
(F::ONE, F::ZERO, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ONE, F::NEG_ONE, F::NEG_ONE),
(F::ONE, F::INFINITY, F::ONE),
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
(F::ONE, F::NAN, F::ONE),
(F::ONE, F::NEG_NAN, F::ONE),
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
(F::NEG_ONE, F::ONE, F::NEG_ONE),
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_ONE, F::NAN, F::NEG_ONE),
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::ZERO),
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
(F::INFINITY, F::ONE, F::ONE),
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
(F::INFINITY, F::INFINITY, F::INFINITY),
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::INFINITY, F::NAN, F::INFINITY),
(F::INFINITY, F::NEG_NAN, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NAN, F::ONE, F::ONE),
(F::NAN, F::NEG_ONE, F::NEG_ONE),
(F::NAN, F::INFINITY, F::INFINITY),
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NAN, F::NAN, F::NAN),
(F::NEG_NAN, F::ZERO, F::ZERO),
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_NAN, F::ONE, F::ONE),
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
(F::NEG_NAN, F::INFINITY, F::INFINITY),
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
];

@@ -110,2 +158,9 @@

}
// Ordering between zeros and NaNs does not matter
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
assert!(f(F::NAN, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::NAN).is_nan());
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
}

@@ -138,12 +193,60 @@

(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::ONE, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::ZERO, F::INFINITY, F::INFINITY),
(F::ZERO, F::NEG_INFINITY, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::ZERO, F::NEG_NAN, F::ZERO),
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ONE, F::ONE),
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
(F::ONE, F::ZERO, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::ONE, F::NEG_ZERO, F::ONE),
(F::ONE, F::ONE, F::ONE),
(F::ONE, F::NEG_ONE, F::ONE),
(F::ONE, F::INFINITY, F::INFINITY),
(F::ONE, F::NEG_INFINITY, F::ONE),
(F::ONE, F::NAN, F::ONE),
(F::ONE, F::NEG_NAN, F::ONE),
(F::NEG_ONE, F::ZERO, F::ZERO),
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ONE, F::ONE, F::ONE),
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::INFINITY, F::INFINITY),
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
(F::NEG_ONE, F::NAN, F::NEG_ONE),
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::INFINITY),
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
(F::INFINITY, F::ONE, F::INFINITY),
(F::INFINITY, F::NEG_ONE, F::INFINITY),
(F::INFINITY, F::INFINITY, F::INFINITY),
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
(F::INFINITY, F::NAN, F::INFINITY),
(F::INFINITY, F::NEG_NAN, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::ZERO),
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_INFINITY, F::ONE, F::ONE),
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NAN, F::ONE, F::ONE),
(F::NAN, F::NEG_ONE, F::NEG_ONE),
(F::NAN, F::INFINITY, F::INFINITY),
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NAN, F::NAN, F::NAN),
(F::NEG_NAN, F::ZERO, F::ZERO),
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_NAN, F::ONE, F::ONE),
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
(F::NEG_NAN, F::INFINITY, F::INFINITY),
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
];

@@ -155,2 +258,9 @@

}
// Ordering between zeros and NaNs does not matter
assert_eq!(f(F::ZERO, F::NEG_ZERO), F::ZERO);
assert_eq!(f(F::NEG_ZERO, F::ZERO), F::ZERO);
assert!(f(F::NAN, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::NAN).is_nan());
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
}

@@ -157,0 +267,0 @@

@@ -5,3 +5,3 @@ /// Return the lesser of two arguments or, if either argument is NaN, NaN.

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimum_numf16(x: f16, y: f16) -> f16 {

@@ -14,3 +14,3 @@ super::generic::fminimum_num(x, y)

/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimum_numf(x: f32, y: f32) -> f32 {

@@ -23,3 +23,3 @@ super::generic::fminimum_num(x, y)

/// This coincides with IEEE 754-2019 `minimumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimum_num(x: f64, y: f64) -> f64 {

@@ -33,3 +33,3 @@ super::generic::fminimum_num(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimum_numf128(x: f128, y: f128) -> f128 {

@@ -43,3 +43,3 @@ super::generic::fminimum_num(x, y)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximum_numf16(x: f16, y: f16) -> f16 {

@@ -52,3 +52,3 @@ super::generic::fmaximum_num(x, y)

/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximum_numf(x: f32, y: f32) -> f32 {

@@ -61,3 +61,3 @@ super::generic::fmaximum_num(x, y)

/// This coincides with IEEE 754-2019 `maximumNumber`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximum_num(x: f64, y: f64) -> f64 {

@@ -71,3 +71,3 @@ super::generic::fmaximum_num(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximum_numf128(x: f128, y: f128) -> f128 {

@@ -85,20 +85,73 @@ super::generic::fmaximum_num(x, y)

(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::ZERO, F::ONE, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::ZERO, F::INFINITY, F::ZERO),
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
(F::ZERO, F::NAN, F::ZERO),
(F::ZERO, F::NEG_NAN, F::ZERO),
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
(F::ONE, F::ZERO, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ONE, F::NEG_ONE, F::NEG_ONE),
(F::ONE, F::INFINITY, F::ONE),
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
(F::ONE, F::NAN, F::ONE),
(F::ONE, F::NEG_NAN, F::ONE),
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
(F::NEG_ONE, F::ONE, F::NEG_ONE),
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_ONE, F::NAN, F::NEG_ONE),
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::ZERO),
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
(F::INFINITY, F::ONE, F::ONE),
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
(F::INFINITY, F::INFINITY, F::INFINITY),
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::INFINITY, F::NAN, F::INFINITY),
(F::INFINITY, F::NEG_NAN, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NAN, F::ONE, F::ONE),
(F::NAN, F::NEG_ONE, F::NEG_ONE),
(F::NAN, F::INFINITY, F::INFINITY),
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
(F::NEG_NAN, F::ZERO, F::ZERO),
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_NAN, F::ONE, F::ONE),
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
(F::NEG_NAN, F::INFINITY, F::INFINITY),
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fminimum_num({}, {})", Hexf(x), Hexf(y));
for (x, y, expected) in cases {
let actual = f(x, y);
assert_biteq!(actual, expected, "fminimum_num({}, {})", Hexf(x), Hexf(y));
}
// Ordering between NaNs does not matter
assert!(f(F::NAN, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::NAN).is_nan());
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
}

@@ -131,20 +184,73 @@

(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::NEG_ZERO, F::ZERO),
(F::ZERO, F::ONE, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::ZERO, F::INFINITY, F::INFINITY),
(F::ZERO, F::NEG_INFINITY, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::ZERO, F::NEG_NAN, F::ZERO),
(F::NEG_ZERO, F::ZERO, F::ZERO),
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ONE, F::ONE),
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
(F::NEG_ZERO, F::NAN, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_NAN, F::NEG_ZERO),
(F::ONE, F::ZERO, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::ONE, F::NEG_ZERO, F::ONE),
(F::ONE, F::ONE, F::ONE),
(F::ONE, F::NEG_ONE, F::ONE),
(F::ONE, F::INFINITY, F::INFINITY),
(F::ONE, F::NEG_INFINITY, F::ONE),
(F::ONE, F::NAN, F::ONE),
(F::ONE, F::NEG_NAN, F::ONE),
(F::NEG_ONE, F::ZERO, F::ZERO),
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ONE, F::ONE, F::ONE),
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::INFINITY, F::INFINITY),
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
(F::NEG_ONE, F::NAN, F::NEG_ONE),
(F::NEG_ONE, F::NEG_NAN, F::NEG_ONE),
(F::INFINITY, F::ZERO, F::INFINITY),
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
(F::INFINITY, F::ONE, F::INFINITY),
(F::INFINITY, F::NEG_ONE, F::INFINITY),
(F::INFINITY, F::INFINITY, F::INFINITY),
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
(F::INFINITY, F::NAN, F::INFINITY),
(F::INFINITY, F::NEG_NAN, F::INFINITY),
(F::NEG_INFINITY, F::ZERO, F::ZERO),
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_INFINITY, F::ONE, F::ONE),
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NAN, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_NAN, F::NEG_INFINITY),
(F::NAN, F::ZERO, F::ZERO),
(F::ZERO, F::NAN, F::ZERO),
(F::NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NAN, F::ONE, F::ONE),
(F::NAN, F::NEG_ONE, F::NEG_ONE),
(F::NAN, F::INFINITY, F::INFINITY),
(F::NAN, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::ZERO),
(F::NEG_ZERO, F::ZERO, F::ZERO),
(F::NEG_NAN, F::ZERO, F::ZERO),
(F::NEG_NAN, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_NAN, F::ONE, F::ONE),
(F::NEG_NAN, F::NEG_ONE, F::NEG_ONE),
(F::NEG_NAN, F::INFINITY, F::INFINITY),
(F::NEG_NAN, F::NEG_INFINITY, F::NEG_INFINITY),
];
for (x, y, res) in cases {
let val = f(x, y);
assert_biteq!(val, res, "fmaximum_num({}, {})", Hexf(x), Hexf(y));
for (x, y, expected) in cases {
let actual = f(x, y);
assert_biteq!(actual, expected, "fmaximum_num({}, {})", Hexf(x), Hexf(y));
}
// Ordering between NaNs does not matter
assert!(f(F::NAN, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::NAN).is_nan());
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
}

@@ -151,0 +257,0 @@

@@ -5,3 +5,3 @@ /// Return the lesser of two arguments or, if either argument is NaN, the other argument.

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimumf16(x: f16, y: f16) -> f16 {

@@ -14,3 +14,3 @@ super::generic::fminimum(x, y)

/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimum(x: f64, y: f64) -> f64 {

@@ -23,3 +23,3 @@ super::generic::fminimum(x, y)

/// This coincides with IEEE 754-2019 `minimum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimumf(x: f32, y: f32) -> f32 {

@@ -33,3 +33,3 @@ super::generic::fminimum(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fminimumf128(x: f128, y: f128) -> f128 {

@@ -43,3 +43,3 @@ super::generic::fminimum(x, y)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximumf16(x: f16, y: f16) -> f16 {

@@ -52,3 +52,3 @@ super::generic::fmaximum(x, y)

/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximumf(x: f32, y: f32) -> f32 {

@@ -61,3 +61,3 @@ super::generic::fmaximum(x, y)

/// This coincides with IEEE 754-2019 `maximum`. The result orders -0.0 < 0.0.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximum(x: f64, y: f64) -> f64 {

@@ -71,3 +71,3 @@ super::generic::fmaximum(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmaximumf128(x: f128, y: f128) -> f128 {

@@ -85,14 +85,50 @@ super::generic::fmaximum(x, y)

(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::ZERO, F::ONE, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::ZERO, F::INFINITY, F::ZERO),
(F::ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
(F::ZERO, F::NAN, F::NAN),
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ONE, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ZERO, F::INFINITY, F::NEG_ZERO),
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_ZERO, F::NAN, F::NAN),
(F::ONE, F::ZERO, F::ZERO),
(F::ZERO, F::NEG_ONE, F::NEG_ONE),
(F::ONE, F::NEG_ZERO, F::NEG_ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ONE, F::NEG_ONE, F::NEG_ONE),
(F::ONE, F::INFINITY, F::ONE),
(F::ONE, F::NEG_INFINITY, F::NEG_INFINITY),
(F::ONE, F::NAN, F::NAN),
(F::NEG_ONE, F::ZERO, F::NEG_ONE),
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ONE),
(F::NEG_ONE, F::ONE, F::NEG_ONE),
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::INFINITY, F::NEG_ONE),
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_ONE, F::NAN, F::NAN),
(F::INFINITY, F::ZERO, F::ZERO),
(F::INFINITY, F::NEG_ZERO, F::NEG_ZERO),
(F::INFINITY, F::ONE, F::ONE),
(F::INFINITY, F::NEG_ONE, F::NEG_ONE),
(F::INFINITY, F::INFINITY, F::INFINITY),
(F::INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::INFINITY, F::NAN, F::NAN),
(F::NEG_INFINITY, F::ZERO, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_INFINITY),
(F::NEG_INFINITY, F::ONE, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_INFINITY),
(F::NEG_INFINITY, F::INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NAN, F::NAN),
(F::NAN, F::ZERO, F::NAN),
(F::ZERO, F::NAN, F::NAN),
(F::NAN, F::NEG_ZERO, F::NAN),
(F::NAN, F::ONE, F::NAN),
(F::NAN, F::NEG_ONE, F::NAN),
(F::NAN, F::INFINITY, F::NAN),
(F::NAN, F::NEG_INFINITY, F::NAN),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ZERO, F::NEG_ZERO),
];

@@ -104,2 +140,19 @@

}
// Ordering between NaNs does not matter
assert!(f(F::NAN, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::NAN).is_nan());
assert!(f(F::ZERO, F::NEG_NAN).is_nan());
assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan());
assert!(f(F::ONE, F::NEG_NAN).is_nan());
assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan());
assert!(f(F::INFINITY, F::NEG_NAN).is_nan());
assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::ZERO).is_nan());
assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan());
assert!(f(F::NEG_NAN, F::ONE).is_nan());
assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan());
assert!(f(F::NEG_NAN, F::INFINITY).is_nan());
assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan());
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
}

@@ -132,14 +185,50 @@

(F::ZERO, F::ZERO, F::ZERO),
(F::ONE, F::ONE, F::ONE),
(F::ZERO, F::NEG_ZERO, F::ZERO),
(F::ZERO, F::ONE, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::ZERO, F::INFINITY, F::INFINITY),
(F::ZERO, F::NEG_INFINITY, F::ZERO),
(F::ZERO, F::NAN, F::NAN),
(F::NEG_ZERO, F::ZERO, F::ZERO),
(F::NEG_ZERO, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ZERO, F::ONE, F::ONE),
(F::NEG_ZERO, F::NEG_ONE, F::NEG_ZERO),
(F::NEG_ZERO, F::INFINITY, F::INFINITY),
(F::NEG_ZERO, F::NEG_INFINITY, F::NEG_ZERO),
(F::NEG_ZERO, F::NAN, F::NAN),
(F::ONE, F::ZERO, F::ONE),
(F::ZERO, F::NEG_ONE, F::ZERO),
(F::ONE, F::NEG_ZERO, F::ONE),
(F::ONE, F::ONE, F::ONE),
(F::ONE, F::NEG_ONE, F::ONE),
(F::ONE, F::INFINITY, F::INFINITY),
(F::ONE, F::NEG_INFINITY, F::ONE),
(F::ONE, F::NAN, F::NAN),
(F::NEG_ONE, F::ZERO, F::ZERO),
(F::NEG_ONE, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_ONE, F::ONE, F::ONE),
(F::NEG_ONE, F::NEG_ONE, F::NEG_ONE),
(F::NEG_ONE, F::INFINITY, F::INFINITY),
(F::NEG_ONE, F::NEG_INFINITY, F::NEG_ONE),
(F::NEG_ONE, F::NAN, F::NAN),
(F::INFINITY, F::ZERO, F::INFINITY),
(F::INFINITY, F::NEG_ZERO, F::INFINITY),
(F::INFINITY, F::ONE, F::INFINITY),
(F::INFINITY, F::NEG_ONE, F::INFINITY),
(F::INFINITY, F::INFINITY, F::INFINITY),
(F::INFINITY, F::NEG_INFINITY, F::INFINITY),
(F::INFINITY, F::NAN, F::NAN),
(F::NEG_INFINITY, F::ZERO, F::ZERO),
(F::NEG_INFINITY, F::NEG_ZERO, F::NEG_ZERO),
(F::NEG_INFINITY, F::ONE, F::ONE),
(F::NEG_INFINITY, F::NEG_ONE, F::NEG_ONE),
(F::NEG_INFINITY, F::INFINITY, F::INFINITY),
(F::NEG_INFINITY, F::NEG_INFINITY, F::NEG_INFINITY),
(F::NEG_INFINITY, F::NAN, F::NAN),
(F::NAN, F::ZERO, F::NAN),
(F::ZERO, F::NAN, F::NAN),
(F::NAN, F::NEG_ZERO, F::NAN),
(F::NAN, F::ONE, F::NAN),
(F::NAN, F::NEG_ONE, F::NAN),
(F::NAN, F::INFINITY, F::NAN),
(F::NAN, F::NEG_INFINITY, F::NAN),
(F::NAN, F::NAN, F::NAN),
(F::ZERO, F::NEG_ZERO, F::ZERO),
(F::NEG_ZERO, F::ZERO, F::ZERO),
];

@@ -151,2 +240,19 @@

}
// Ordering between NaNs does not matter
assert!(f(F::NAN, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::NAN).is_nan());
assert!(f(F::ZERO, F::NEG_NAN).is_nan());
assert!(f(F::NEG_ZERO, F::NEG_NAN).is_nan());
assert!(f(F::ONE, F::NEG_NAN).is_nan());
assert!(f(F::NEG_ONE, F::NEG_NAN).is_nan());
assert!(f(F::INFINITY, F::NEG_NAN).is_nan());
assert!(f(F::NEG_INFINITY, F::NEG_NAN).is_nan());
assert!(f(F::NEG_NAN, F::ZERO).is_nan());
assert!(f(F::NEG_NAN, F::NEG_ZERO).is_nan());
assert!(f(F::NEG_NAN, F::ONE).is_nan());
assert!(f(F::NEG_NAN, F::NEG_ONE).is_nan());
assert!(f(F::NEG_NAN, F::INFINITY).is_nan());
assert!(f(F::NEG_NAN, F::NEG_INFINITY).is_nan());
assert!(f(F::NEG_NAN, F::NEG_NAN).is_nan());
}

@@ -153,0 +259,0 @@

/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmodf16(x: f16, y: f16) -> f16 {

@@ -9,3 +9,3 @@ super::generic::fmod(x, y)

/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmodf(x: f32, y: f32) -> f32 {

@@ -16,3 +16,3 @@ super::generic::fmod(x, y)

/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmod(x: f64, y: f64) -> f64 {

@@ -24,5 +24,5 @@ super::generic::fmod(x, y)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fmodf128(x: f128, y: f128) -> f128 {
super::generic::fmod(x, y)
}

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn frexp(x: f64) -> (f64, i32) {

@@ -3,0 +3,0 @@ let mut y = x.to_bits();

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn frexpf(x: f32) -> (f32, i32) {

@@ -3,0 +3,0 @@ let mut y = x.to_bits();

@@ -22,4 +22,3 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */

let res = if x.is_nan() || x < y { y } else { x };
// Canonicalize
res * F::ONE
res.canonicalize()
}

@@ -7,6 +7,6 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */

//! - `y` if `y > x`
//! - +0.0 if x and y are zero with opposite signs
//! - Either `x` or `y` if `x == y` and the signs are the same
//! - Non-NaN if one operand is NaN
//! - Logic following +0.0 > -0.0
//! - Either `x` or `y` if `x == y` and the signs are the same
//! - qNaN if either operand is a NaN
//! - qNaN if both operands are NaNx
//!

@@ -19,11 +19,13 @@ //! Excluded from our implementation is sNaN handling.

pub fn fmaximum_num<F: Float>(x: F, y: F) -> F {
let res =
if x.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) {
y
} else {
x
};
let res = if x > y || y.is_nan() {
x
} else if y > x || x.is_nan() {
y
} else if x.is_sign_positive() {
x
} else {
y
};
// Canonicalize
res * F::ONE
res.canonicalize()
}

@@ -7,4 +7,4 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */

//! - `y` if `y > x`
//! - +0.0 if x and y are zero with opposite signs
//! - qNaN if either operation is NaN
//! - Logic following +0.0 > -0.0
//!

@@ -21,3 +21,3 @@ //! Excluded from our implementation is sNaN handling.

y
} else if x > y || (y.to_bits() == F::NEG_ZERO.to_bits() && x.is_sign_positive()) {
} else if x > y || (y.biteq(F::NEG_ZERO) && x.is_sign_positive()) {
x

@@ -28,4 +28,3 @@ } else {

// Canonicalize
res * F::ONE
res.canonicalize()
}

@@ -22,4 +22,3 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */

let res = if y.is_nan() || x < y { x } else { y };
// Canonicalize
res * F::ONE
res.canonicalize()
}

@@ -7,6 +7,6 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */

//! - `y` if `y < x`
//! - -0.0 if x and y are zero with opposite signs
//! - Either `x` or `y` if `x == y` and the signs are the same
//! - Non-NaN if one operand is NaN
//! - Logic following +0.0 > -0.0
//! - Either `x` or `y` if `x == y` and the signs are the same
//! - qNaN if either operand is a NaN
//! - qNaN if both operands are NaNx
//!

@@ -19,11 +19,13 @@ //! Excluded from our implementation is sNaN handling.

pub fn fminimum_num<F: Float>(x: F, y: F) -> F {
let res =
if y.is_nan() || x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) {
x
} else {
y
};
let res = if x > y || x.is_nan() {
y
} else if y > x || y.is_nan() {
x
} else if x.is_sign_positive() {
y
} else {
x
};
// Canonicalize
res * F::ONE
res.canonicalize()
}

@@ -7,4 +7,4 @@ /* SPDX-License-Identifier: MIT OR Apache-2.0 */

//! - `y` if `y < x`
//! - -0.0 if x and y are zero with opposite signs
//! - qNaN if either operation is NaN
//! - Logic following +0.0 > -0.0
//!

@@ -21,3 +21,3 @@ //! Excluded from our implementation is sNaN handling.

y
} else if x < y || (x.to_bits() == F::NEG_ZERO.to_bits() && y.is_sign_positive()) {
} else if x < y || (x.biteq(F::NEG_ZERO) && y.is_sign_positive()) {
x

@@ -28,4 +28,3 @@ } else {

// Canonicalize
res * F::ONE
res.canonicalize()
}
/* SPDX-License-Identifier: MIT OR Apache-2.0 */
use crate::support::{CastFrom, Float, Int, MinInt};
use crate::support::{CastFrom, CastInto, Float, HInt, Int, MinInt, NarrowingDiv};
#[inline]
pub fn fmod<F: Float>(x: F, y: F) -> F {
pub fn fmod<F: Float>(x: F, y: F) -> F
where
F::Int: HInt,
<F::Int as HInt>::D: NarrowingDiv,
{
let _1 = F::Int::ONE;

@@ -32,3 +36,3 @@ let sx = x.to_bits() & F::SIGN_MASK;

// evaluate `rem = (num << (ex - ey)) % div` ...
let rem = reduction(num, ex - ey, div);
let rem = reduction::<F>(num, ex - ey, div);
// ... so the result will be `rem << ey`

@@ -62,9 +66,53 @@

/// Compute the remainder `(x * 2.pow(e)) % y` without overflow.
fn reduction<I: Int>(mut x: I, e: u32, y: I) -> I {
x %= y;
for _ in 0..e {
x <<= 1;
x = x.checked_sub(y).unwrap_or(x);
fn reduction<F>(mut x: F::Int, e: u32, y: F::Int) -> F::Int
where
F: Float,
F::Int: HInt,
<<F as Float>::Int as HInt>::D: NarrowingDiv,
{
// `f16` only has 5 exponent bits, so even `f16::MAX = 65504.0` is only
// a 40-bit integer multiple of the smallest subnormal.
if F::BITS == 16 {
debug_assert!(F::EXP_MAX - F::EXP_MIN == 29);
debug_assert!(e <= 29);
let u: u16 = x.cast();
let v: u16 = y.cast();
let u = (u as u64) << e;
let v = v as u64;
return F::Int::cast_from((u % v) as u16);
}
x
// Ensure `x < 2y` for later steps
if x >= (y << 1) {
// This case is only reached with subnormal divisors,
// but it might be better to just normalize all significands
// to make this unnecessary. The further calls could potentially
// benefit from assuming a specific fixed leading bit position.
x %= y;
}
// The simple implementation seems to be fastest for a short reduction
// at this size. The limit here was chosen empirically on an Intel Nehalem.
// Less old CPUs that have faster `u64 * u64 -> u128` might not benefit,
// and 32-bit systems or architectures without hardware multipliers might
// want to do this in more cases.
if F::BITS == 64 && e < 32 {
// Assumes `x < 2y`
for _ in 0..e {
x = x.checked_sub(y).unwrap_or(x);
x <<= 1;
}
return x.checked_sub(y).unwrap_or(x);
}
// Fast path for short reductions
if e < F::BITS {
let w = x.widen() << e;
if let Some((_, r)) = w.checked_narrowing_div_rem(y) {
return r;
}
}
// Assumes `x < 2y`
crate::support::linear_mul_reduction(x, e, y)
}

@@ -99,3 +99,3 @@ use crate::support::{CastFrom, CastInto, Float, IntTy, MinInt};

// since it needs to construct the scale, but works better in the general case.
let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32);
let add = -(n + sig_total_bits as i32).max(exp_min);
let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero);

@@ -107,3 +107,3 @@

if n < exp_min {
let add = -(n + sig_total_bits as i32).clamp(exp_min, sig_total_bits as i32);
let add = -(n + sig_total_bits as i32).max(exp_min);
let mul = F::from_parts(false, (F::EXP_BIAS as i32 - add) as u32, zero);

@@ -110,0 +110,0 @@

@@ -1,3 +0,1 @@

use core::f64;
use super::sqrt;

@@ -20,3 +18,3 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn hypot(mut x: f64, mut y: f64) -> f64 {

@@ -23,0 +21,0 @@ let x1p700 = f64::from_bits(0x6bb0000000000000); // 0x1p700 === 2 ^ 700

@@ -1,6 +0,4 @@

use core::f32;
use super::sqrtf;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn hypotf(mut x: f32, mut y: f32) -> f32 {

@@ -7,0 +5,0 @@ let x1p90 = f32::from_bits(0x6c800000); // 0x1p90f === 2 ^ 90

const FP_ILOGBNAN: i32 = -1 - 0x7fffffff;
const FP_ILOGB0: i32 = FP_ILOGBNAN;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ilogb(x: f64) -> i32 {

@@ -6,0 +6,0 @@ let mut i: u64 = x.to_bits();

const FP_ILOGBNAN: i32 = -1 - 0x7fffffff;
const FP_ILOGB0: i32 = FP_ILOGBNAN;
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ilogbf(x: f32) -> i32 {

@@ -6,0 +6,0 @@ let mut i = x.to_bits();

@@ -113,3 +113,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j0.c */

/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn j0(mut x: f64) -> f64 {

@@ -169,3 +169,3 @@ let z: f64;

/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn y0(x: f64) -> f64 {

@@ -172,0 +172,0 @@ let z: f64;

@@ -66,3 +66,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j0f.c */

/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn j0f(mut x: f32) -> f32 {

@@ -114,3 +114,3 @@ let z: f32;

/// Zeroth order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn y0f(x: f32) -> f32 {

@@ -117,0 +117,0 @@ let z: f32;

@@ -117,3 +117,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j1.c */

/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn j1(x: f64) -> f64 {

@@ -165,3 +165,3 @@ let mut z: f64;

/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn y1(x: f64) -> f64 {

@@ -168,0 +168,0 @@ let z: f64;

@@ -67,3 +67,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_j1f.c */

/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn j1f(x: f32) -> f32 {

@@ -114,3 +114,3 @@ let mut z: f32;

/// First order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn y1f(x: f32) -> f32 {

@@ -366,4 +366,2 @@ let z: f32;

// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
#[cfg(not(target_arch = "powerpc64"))]
#[cfg(test)]

@@ -377,2 +375,3 @@ mod tests {

}
#[test]

@@ -379,0 +378,0 @@ fn test_y1f_2002() {

@@ -42,3 +42,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_jn.c */

/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn jn(n: i32, mut x: f64) -> f64 {

@@ -253,3 +253,3 @@ let mut ix: u32;

/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn yn(n: i32, x: f64) -> f64 {

@@ -256,0 +256,0 @@ let mut ix: u32;

@@ -19,3 +19,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_jnf.c */

/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the first kind (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn jnf(n: i32, mut x: f32) -> f32 {

@@ -196,3 +196,3 @@ let mut ix: u32;

/// Integer order of the [Bessel function](https://en.wikipedia.org/wiki/Bessel_function) of the second kind (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ynf(n: i32, x: f32) -> f32 {

@@ -199,0 +199,0 @@ let mut ix: u32;

@@ -54,3 +54,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/k_cos.c

// any extra precision in w.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_cos(x: f64, y: f64) -> f64 {

@@ -57,0 +57,0 @@ let z = x * x;

@@ -23,3 +23,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_cosf(x: f64) -> f32 {

@@ -26,0 +26,0 @@ let z = x * x;

@@ -7,3 +7,3 @@ use super::exp;

/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_expo2(x: f64) -> f64 {

@@ -10,0 +10,0 @@ let k_ln2 = f64::from_bits(0x40962066151add8b);

@@ -7,3 +7,3 @@ use super::expf;

/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_expo2f(x: f32) -> f32 {

@@ -10,0 +10,0 @@ let k_ln2 = f32::from_bits(0x4322e3bc);

@@ -46,3 +46,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/k_sin.c

// sin(x) = x + (S1*x + (x *(r-y/2)+y))
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 {

@@ -49,0 +49,0 @@ let z = x * x;

@@ -23,3 +23,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_sinf(x: f64) -> f32 {

@@ -26,0 +26,0 @@ let z = x * x;

@@ -61,3 +61,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_tan(mut x: f64, mut y: f64, odd: i32) -> f64 {

@@ -64,0 +64,0 @@ let hx = (f64::to_bits(x) >> 32) as u32;

@@ -22,3 +22,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn k_tanf(x: f64, odd: bool) -> f32 {

@@ -25,0 +25,0 @@ let z = x * x;

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ldexpf16(x: f16, n: i32) -> f16 {

@@ -7,3 +7,3 @@ super::scalbnf16(x, n)

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ldexpf(x: f32, n: i32) -> f32 {

@@ -13,3 +13,3 @@ super::scalbnf(x, n)

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ldexp(x: f64, n: i32) -> f64 {

@@ -20,5 +20,5 @@ super::scalbn(x, n)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ldexpf128(x: f128, n: i32) -> f128 {
super::scalbnf128(x, n)
}

@@ -168,3 +168,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn lgamma_r(mut x: f64) -> (f64, i32) {

@@ -171,0 +171,0 @@ let u: u64 = x.to_bits();

@@ -5,5 +5,5 @@ use super::lgamma_r;

/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn lgamma(x: f64) -> f64 {
lgamma_r(x).0
}

@@ -103,3 +103,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn lgammaf_r(mut x: f32) -> (f32, i32) {

@@ -106,0 +106,0 @@ let u = x.to_bits();

@@ -5,5 +5,5 @@ use super::lgammaf_r;

/// [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn lgammaf(x: f32) -> f32 {
lgammaf_r(x).0
}

@@ -74,3 +74,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log.c */

/// The natural logarithm of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log(mut x: f64) -> f64 {

@@ -77,0 +77,0 @@ let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54

@@ -20,4 +20,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */

use core::f64;
const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */

@@ -36,3 +34,3 @@ const IVLN10LO: f64 = 2.50829467116452752298e-11; /* 0x3dbb9438, 0xca9aadd5 */

/// The base 10 logarithm of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log10(mut x: f64) -> f64 {

@@ -39,0 +37,0 @@ let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54

@@ -16,4 +16,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */

use core::f32;
const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */

@@ -30,3 +28,3 @@ const IVLN10LO: f32 = -3.1689971365e-05; /* 0xb804ead9 */

/// The base 10 logarithm of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log10f(mut x: f32) -> f32 {

@@ -33,0 +31,0 @@ let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25

@@ -56,4 +56,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */

use core::f64;
const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */

@@ -70,3 +68,3 @@ const LN2_LO: f64 = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */

/// The natural logarithm of 1+`x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log1p(x: f64) -> f64 {

@@ -73,0 +71,0 @@ let mut ui: u64 = x.to_bits();

@@ -13,4 +13,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */

use core::f32;
const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */

@@ -25,3 +23,3 @@ const LN2_LO: f32 = 9.0580006145e-06; /* 0x3717f7d1 */

/// The natural logarithm of 1+`x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log1pf(x: f32) -> f32 {

@@ -28,0 +26,0 @@ let mut ui: u32 = x.to_bits();

@@ -20,4 +20,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */

use core::f64;
const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */

@@ -34,3 +32,3 @@ const IVLN2LO: f64 = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */

/// The base 2 logarithm of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log2(mut x: f64) -> f64 {

@@ -37,0 +35,0 @@ let x1p54 = f64::from_bits(0x4350000000000000); // 0x1p54 === 2 ^ 54

@@ -16,4 +16,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */

use core::f32;
const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */

@@ -28,3 +26,3 @@ const IVLN2LO: f32 = -1.7605285393e-04; /* 0xb9389ad4 */

/// The base 2 logarithm of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn log2f(mut x: f32) -> f32 {

@@ -31,0 +29,0 @@ let x1p25f = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25

@@ -25,3 +25,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_logf.c */

/// The natural logarithm of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn logf(mut x: f32) -> f32 {

@@ -28,0 +28,0 @@ let x1p25 = f32::from_bits(0x4c000000); // 0x1p25f === 2 ^ 25

@@ -0,1 +1,3 @@

#![allow(clippy::approx_constant)] // many false positives
macro_rules! force_eval {

@@ -2,0 +4,0 @@ ($e:expr) => {

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn modf(x: f64) -> (f64, f64) {

@@ -3,0 +3,0 @@ let rv2: f64;

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn modff(x: f32) -> (f32, f32) {

@@ -3,0 +3,0 @@ let rv2: f32;

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn nextafter(x: f64, y: f64) -> f64 {

@@ -3,0 +3,0 @@ if x.is_nan() || y.is_nan() {

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn nextafterf(x: f32, y: f32) -> f32 {

@@ -3,0 +3,0 @@ if x.is_nan() || y.is_nan() {

@@ -93,3 +93,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_pow.c */

/// Returns `x` to the power of `y` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn pow(x: f64, y: f64) -> f64 {

@@ -96,0 +96,0 @@ let t1: f64;

@@ -49,3 +49,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_powf.c */

/// Returns `x` to the power of `y` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn powf(x: f32, y: f32) -> f32 {

@@ -52,0 +52,0 @@ let mut z: f32;

@@ -14,3 +14,3 @@ #![allow(unused_unsafe)]

use super::{floor, scalbn};
use super::scalbn;

@@ -150,3 +150,3 @@ // initial value for jk

//
// y[] ouput result in an array of double precision numbers.
// y[] output result in an array of double precision numbers.
// The dimension of y[] is:

@@ -226,4 +226,12 @@ // 24-bit precision 1

/// independent of the exponent of the input.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn rem_pio2_large(x: &[f64], y: &mut [f64], e0: i32, prec: usize) -> i32 {
// FIXME(rust-lang/rust#144518): Inline assembly would cause `no_panic` to fail
// on the callers of this function. As a workaround, avoid inlining `floor` here
// when implemented with assembly.
#[cfg_attr(x86_no_sse, inline(never))]
extern "C" fn floor(x: f64) -> f64 {
super::floor(x)
}
let x1p24 = f64::from_bits(0x4170000000000000); // 0x1p24 === 2 ^ 24

@@ -230,0 +238,0 @@ let x1p_24 = f64::from_bits(0x3e70000000000000); // 0x1p_24 === 2 ^ (-24)

@@ -44,3 +44,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c

// caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn rem_pio2(x: f64) -> (i32, f64, f64) {

@@ -199,3 +199,3 @@ let x1p24 = f64::from_bits(0x4170000000000000);

// FIXME(correctness): inaccurate results on i586
#[cfg_attr(all(target_arch = "x86", not(target_feature = "sse")), ignore)]
#[cfg_attr(x86_no_sse, ignore)]
fn test_near_pi() {

@@ -202,0 +202,0 @@ let arg = 3.141592025756836;

@@ -17,4 +17,2 @@ /* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */

use core::f64;
use super::rem_pio2_large;

@@ -35,3 +33,3 @@

/// use __rem_pio2_large() for large x
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub(crate) fn rem_pio2f(x: f32) -> (i32, f64) {

@@ -38,0 +36,0 @@ let x64 = x as f64;

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn remainder(x: f64, y: f64) -> f64 {

@@ -3,0 +3,0 @@ let (result, _) = super::remquo(x, y);

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn remainderf(x: f32, y: f32) -> f32 {

@@ -3,0 +3,0 @@ let (result, _) = super::remquof(x, y);

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn remquo(mut x: f64, mut y: f64) -> (f64, i32) {

@@ -3,0 +3,0 @@ let ux: u64 = x.to_bits();

@@ -1,2 +0,2 @@

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn remquof(mut x: f32, mut y: f32) -> (f32, i32) {

@@ -3,0 +3,0 @@ let ux: u32 = x.to_bits();

@@ -5,3 +5,3 @@ use super::support::Round;

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn rintf16(x: f16) -> f16 {

@@ -18,3 +18,3 @@ select_implementation! {

/// Round `x` to the nearest integer, breaking ties toward even.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn rintf(x: f32) -> f32 {

@@ -34,3 +34,3 @@ select_implementation! {

/// Round `x` to the nearest integer, breaking ties toward even.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn rint(x: f64) -> f64 {

@@ -51,5 +51,5 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn rintf128(x: f128) -> f128 {
super::generic::rint_round(x, Round::Nearest).val
}
/// Round `x` to the nearest integer, breaking ties away from zero.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundf16(x: f16) -> f16 {

@@ -9,3 +9,3 @@ super::generic::round(x)

/// Round `x` to the nearest integer, breaking ties away from zero.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundf(x: f32) -> f32 {

@@ -16,3 +16,3 @@ super::generic::round(x)

/// Round `x` to the nearest integer, breaking ties away from zero.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn round(x: f64) -> f64 {

@@ -24,5 +24,5 @@ super::generic::round(x)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundf128(x: f128) -> f128 {
super::generic::round(x)
}

@@ -6,3 +6,3 @@ use super::support::{Float, Round};

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundevenf16(x: f16) -> f16 {

@@ -14,3 +14,3 @@ roundeven_impl(x)

/// `roundToIntegralTiesToEven`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundevenf(x: f32) -> f32 {

@@ -22,3 +22,3 @@ roundeven_impl(x)

/// `roundToIntegralTiesToEven`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundeven(x: f64) -> f64 {

@@ -31,3 +31,3 @@ roundeven_impl(x)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn roundevenf128(x: f128) -> f128 {

@@ -34,0 +34,0 @@ roundeven_impl(x)

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn scalbnf16(x: f16, n: i32) -> f16 {

@@ -7,3 +7,3 @@ super::generic::scalbn(x, n)

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn scalbnf(x: f32, n: i32) -> f32 {

@@ -13,3 +13,3 @@ super::generic::scalbn(x, n)

#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn scalbn(x: f64, n: i32) -> f64 {

@@ -20,3 +20,3 @@ super::generic::scalbn(x, n)

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn scalbnf128(x: f128, n: i32) -> f128 {

@@ -23,0 +23,0 @@ super::generic::scalbn(x, n)

@@ -47,3 +47,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sin(x: f64) -> f64 {

@@ -50,0 +50,0 @@ let x1p120 = f64::from_bits(0x4770000000000000); // 0x1p120f === 2 ^ 120

@@ -18,3 +18,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */

/// `x` is specified in radians and the return value is (sin(x), cos(x)).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sincos(x: f64) -> (f64, f64) {

@@ -21,0 +21,0 @@ let s: f64;

@@ -29,3 +29,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */

/// `x` is specified in radians and the return value is (sin(x), cos(x)).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sincosf(x: f32) -> (f32, f32) {

@@ -32,0 +32,0 @@ let s: f32;

@@ -30,3 +30,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sinf(x: f32) -> f32 {

@@ -33,0 +33,0 @@ let x64 = x as f64;

@@ -9,3 +9,3 @@ use super::{expm1, expo2};

/// The hyperbolic sine of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sinh(x: f64) -> f64 {

@@ -12,0 +12,0 @@ // union {double f; uint64_t i;} u = {.f = x};

use super::{expm1f, k_expo2f};
/// The hyperbolic sine of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sinhf(x: f32) -> f32 {

@@ -6,0 +6,0 @@ let mut h = 0.5f32;

/// The square root of `x` (f16).
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sqrtf16(x: f16) -> f16 {

@@ -15,3 +15,3 @@ select_implementation! {

/// The square root of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sqrtf(x: f32) -> f32 {

@@ -32,3 +32,3 @@ select_implementation! {

/// The square root of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sqrt(x: f64) -> f64 {

@@ -50,5 +50,5 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn sqrtf128(x: f128) -> f128 {
return super::generic::sqrt(x);
}

@@ -14,6 +14,6 @@ //! Integers used for wide operations, larger than `u128`.

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct u256 {
pub hi: u128,
pub lo: u128,
pub hi: u128,
}

@@ -32,3 +32,3 @@

lo: self.lo,
hi: self.hi,
hi: self.hi as i128,
}

@@ -40,6 +40,6 @@ }

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct i256 {
pub hi: i128,
pub lo: u128,
pub hi: u128,
}

@@ -53,3 +53,3 @@

lo: self.lo,
hi: self.hi,
hi: self.hi as u128,
}

@@ -80,3 +80,3 @@ }

const SIGNED: bool = false;
const SIGNED: bool = true;
const BITS: u32 = 256;

@@ -86,8 +86,8 @@ const ZERO: Self = Self { lo: 0, hi: 0 };

const MIN: Self = Self {
lo: 0,
hi: 1 << 127,
lo: u128::MIN,
hi: i128::MIN,
};
const MAX: Self = Self {
lo: u128::MAX,
hi: u128::MAX << 1,
hi: i128::MAX,
};

@@ -118,56 +118,82 @@ }

impl ops::Shl<u32> for $ty {
impl ops::Add<Self> for $ty {
type Output = Self;
fn shl(self, _rhs: u32) -> Self::Output {
unimplemented!("only used to meet trait bounds")
fn add(self, rhs: Self) -> Self::Output {
let (lo, carry) = self.lo.overflowing_add(rhs.lo);
let (hi, of) = Int::carrying_add(self.hi, rhs.hi, carry);
debug_assert!(!of, "attempt to add with overflow");
Self { lo, hi }
}
}
};
}
impl_common!(i256);
impl_common!(u256);
impl ops::Sub<Self> for $ty {
type Output = Self;
impl ops::Add<Self> for u256 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let (lo, borrow) = self.lo.overflowing_sub(rhs.lo);
let (hi, of) = Int::borrowing_sub(self.hi, rhs.hi, borrow);
debug_assert!(!of, "attempt to subtract with overflow");
Self { lo, hi }
}
}
fn add(self, rhs: Self) -> Self::Output {
let (lo, carry) = self.lo.overflowing_add(rhs.lo);
let hi = self.hi.wrapping_add(carry as u128).wrapping_add(rhs.hi);
impl ops::Shl<u32> for $ty {
type Output = Self;
Self { lo, hi }
}
}
fn shl(mut self, rhs: u32) -> Self::Output {
debug_assert!(rhs < Self::BITS, "attempt to shift left with overflow");
impl ops::Shr<u32> for u256 {
type Output = Self;
let half_bits = Self::BITS / 2;
let low_mask = half_bits - 1;
let s = rhs & low_mask;
fn shr(mut self, rhs: u32) -> Self::Output {
debug_assert!(rhs < Self::BITS, "attempted to shift right with overflow");
if rhs >= Self::BITS {
return Self::ZERO;
}
let lo = self.lo;
let hi = self.hi;
if rhs == 0 {
return self;
}
self.lo = lo << s;
if rhs < 128 {
self.lo >>= rhs;
self.lo |= self.hi << (128 - rhs);
} else {
self.lo = self.hi >> (rhs - 128);
if rhs & half_bits == 0 {
self.hi = (lo >> (low_mask ^ s) >> 1) as _;
self.hi |= hi << s;
} else {
self.hi = self.lo as _;
self.lo = 0;
}
self
}
}
if rhs < 128 {
self.hi >>= rhs;
} else {
self.hi = 0;
impl ops::Shr<u32> for $ty {
type Output = Self;
fn shr(mut self, rhs: u32) -> Self::Output {
debug_assert!(rhs < Self::BITS, "attempt to shift right with overflow");
let half_bits = Self::BITS / 2;
let low_mask = half_bits - 1;
let s = rhs & low_mask;
let lo = self.lo;
let hi = self.hi;
self.hi = hi >> s;
#[allow(unused_comparisons)]
if rhs & half_bits == 0 {
self.lo = (hi << (low_mask ^ s) << 1) as _;
self.lo |= lo >> s;
} else {
self.lo = self.hi as _;
self.hi = if hi < 0 { !0 } else { 0 };
}
self
}
}
self
}
};
}
impl_common!(i256);
impl_common!(u256);
impl HInt for u128 {

@@ -210,3 +236,3 @@ type D = u256;

fn widen_hi(self) -> Self::D {
self.widen() << <Self as MinInt>::BITS
u256 { lo: 0, hi: self }
}

@@ -219,7 +245,6 @@ }

fn widen(self) -> Self::D {
let mut ret = self.unsigned().zero_widen().signed();
if self.is_negative() {
ret.hi = u128::MAX;
i256 {
lo: self as u128,
hi: if self < 0 { -1 } else { 0 },
}
ret
}

@@ -240,3 +265,3 @@

fn widen_hi(self) -> Self::D {
self.widen() << <Self as MinInt>::BITS
i256 { lo: 0, hi: self }
}

@@ -265,4 +290,4 @@ }

fn hi(self) -> Self::H {
self.hi as i128
self.hi
}
}

@@ -6,2 +6,3 @@ extern crate std;

use super::{HInt, MinInt, i256, u256};
use crate::support::{Int as _, NarrowingDiv};

@@ -40,3 +41,3 @@ const LOHI_SPLIT: u128 = 0xaaaaaaaaaaaaaaaaffffffffffffffff;

lo: LOHI_SPLIT,
hi: u128::MAX
hi: -1,
}

@@ -280,1 +281,87 @@ );

}
#[test]
fn u256_ord() {
let _1 = u256::ONE;
let _2 = _1 + _1;
for x in u8::MIN..u8::MAX {
let y = x + 1;
let wx = (x as u128).widen_hi();
let wy = (y as u128).widen_hi();
assert!([wx, wx + _1, wx + _2, wy, wy + _1, wy + _2].is_sorted());
}
}
#[test]
fn i256_ord() {
let _1 = i256::ONE;
let _2 = _1 + _1;
for x in i8::MIN..i8::MAX {
let y = x + 1;
let wx = (x as i128).widen_hi();
let wy = (y as i128).widen_hi();
assert!([wx, wx + _1, wx + _2, wy - _2, wy - _1, wy].is_sorted());
}
}
#[test]
fn u256_shifts() {
let _1 = u256::ONE;
for k in 0..255 {
let x = _1 << k;
let x2 = _1 << (k + 1);
assert!(x < x2);
assert_eq!(x << 1, x2);
assert_eq!(x + x, x2);
assert_eq!(x >> k, _1);
assert_eq!(x2 >> (k + 1), _1);
}
}
#[test]
fn i256_shifts() {
let _1 = i256::ONE;
for k in 0..254 {
let x = _1 << k;
let x2 = _1 << (k + 1);
assert!(x < x2);
assert_eq!(x << 1, x2);
assert_eq!(x + x, x2);
assert_eq!(x >> k, _1);
assert_eq!(x2 >> (k + 1), _1);
}
let min = _1 << 255;
assert_eq!(min, i256::MIN);
let mut x = min;
for k in 0..255 {
assert_eq!(x, min >> k);
let y = x >> 1;
assert_eq!(y + y, x);
assert!(x < y);
x = y;
}
}
#[test]
fn div_u256_by_u128() {
for j in i8::MIN..=i8::MAX {
let y: u128 = (j as i128).rotate_right(4).unsigned();
if y == 0 {
continue;
}
for i in i8::MIN..=i8::MAX {
let x: u128 = (i as i128).rotate_right(4).unsigned();
let xy = x.widen_mul(y);
assert_eq!(xy.checked_narrowing_div_rem(y), Some((x, 0)));
if y != 1 {
assert_eq!((xy + u256::ONE).checked_narrowing_div_rem(y), Some((x, 1)));
}
if x != 0 {
assert_eq!(
(xy - u256::ONE).checked_narrowing_div_rem(y),
Some((x - 1, y - 1))
);
}
let r = ((y as f64) * 0.12345) as u128;
assert_eq!((xy + r.widen()).checked_narrowing_div_rem(y), Some((x, r)));
}
}
}

@@ -9,2 +9,3 @@ #![allow(unknown_lints)] // FIXME(msrv) we shouldn't need this

// #[allow(dead_code)]
#[allow(dead_code)] // Some constants are only used with tests
pub trait Float:

@@ -193,2 +194,11 @@ Copy

}
/// Make a best-effort attempt to canonicalize the number. Note that this is allowed
/// to be a nop and does not always quiet sNaNs.
fn canonicalize(self) -> Self {
// FIXME: LLVM often removes this. We should determine whether we can remove the operation,
// or switch to something based on `llvm.canonicalize` (which has crashes,
// <https://github.com/llvm/llvm-project/issues/32650>).
self * Self::ONE
}
}

@@ -284,3 +294,6 @@

if #[cfg(intrinsics_enabled)] {
unsafe{ core::intrinsics::$fma_intrinsic(self, y, z) }
// FIXME(msrv,bench): once our benchmark rustc version is above the
// 2022-09-23 nightly, this can be removed.
#[allow(unused_unsafe)]
unsafe { core::intrinsics::$fma_intrinsic(self, y, z) }
} else {

@@ -359,2 +372,3 @@ super::super::$fma_fn(self, y, z)

/// `f32::to_bits`
#[allow(dead_code)] // workaround for false positive RUST-144060
#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust

@@ -374,2 +388,3 @@ pub const fn f32_to_bits(x: f32) -> u32 {

/// `f64::to_bits`
#[allow(dead_code)] // workaround for false positive RUST-144060
#[allow(unnecessary_transmutes)] // lint appears in newer versions of Rust

@@ -376,0 +391,0 @@ pub const fn f64_to_bits(x: f64) -> u64 {

//! Utilities for working with hex float formats.
use core::fmt;
use super::{Round, Status, f32_from_bits, f64_from_bits};
use super::{Float, Round, Status, f32_from_bits, f64_from_bits};
/// Construct a 16-bit float from hex float representation (C-style)

@@ -355,124 +353,131 @@ #[cfg(f16_enabled)]

/// Format a floating point number as its IEEE hex (`%a`) representation.
pub struct Hexf<F>(pub F);
#[cfg(any(test, feature = "unstable-public-internals"))]
mod hex_fmt {
use core::fmt;
// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs
#[cfg(not(feature = "compiler-builtins"))]
fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if x.is_sign_negative() {
write!(f, "-")?;
}
use crate::support::Float;
if x.is_nan() {
return write!(f, "NaN");
} else if x.is_infinite() {
return write!(f, "inf");
} else if *x == F::ZERO {
return write!(f, "0x0p+0");
}
/// Format a floating point number as its IEEE hex (`%a`) representation.
pub struct Hexf<F>(pub F);
let mut exponent = x.exp_unbiased();
let sig = x.to_bits() & F::SIG_MASK;
// Adapted from https://github.com/ericseppanen/hexfloat2/blob/a5c27932f0ff/src/format.rs
#[cfg(not(feature = "compiler-builtins"))]
pub(super) fn fmt_any_hex<F: Float>(x: &F, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if x.is_sign_negative() {
write!(f, "-")?;
}
let bias = F::EXP_BIAS as i32;
// The mantissa MSB needs to be shifted up to the nearest nibble.
let mshift = (4 - (F::SIG_BITS % 4)) % 4;
let sig = sig << mshift;
// The width is rounded up to the nearest char (4 bits)
let mwidth = (F::SIG_BITS as usize + 3) / 4;
let leading = if exponent == -bias {
// subnormal number means we shift our output by 1 bit.
exponent += 1;
"0."
} else {
"1."
};
if x.is_nan() {
return write!(f, "NaN");
} else if x.is_infinite() {
return write!(f, "inf");
} else if *x == F::ZERO {
return write!(f, "0x0p+0");
}
write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}")
}
let mut exponent = x.exp_unbiased();
let sig = x.to_bits() & F::SIG_MASK;
#[cfg(feature = "compiler-builtins")]
fn fmt_any_hex<F: Float>(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
unimplemented!()
}
let bias = F::EXP_BIAS as i32;
// The mantissa MSB needs to be shifted up to the nearest nibble.
let mshift = (4 - (F::SIG_BITS % 4)) % 4;
let sig = sig << mshift;
// The width is rounded up to the nearest char (4 bits)
let mwidth = (F::SIG_BITS as usize + 3) / 4;
let leading = if exponent == -bias {
// subnormal number means we shift our output by 1 bit.
exponent += 1;
"0."
} else {
"1."
};
impl<F: Float> fmt::LowerHex for Hexf<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt_any_hex(&self.0, f)
write!(f, "0x{leading}{sig:0mwidth$x}p{exponent:+}")
}
#[cfg(feature = "compiler-builtins")]
pub(super) fn fmt_any_hex<F: Float>(_x: &F, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
unimplemented!()
}
impl<F: Float> fmt::LowerHex for Hexf<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt_any_hex(&self.0, f)
}
}
}
}
}
impl<F: Float> fmt::LowerHex for Hexf<(F, F)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
impl<F: Float> fmt::LowerHex for Hexf<(F, F)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
}
}
}
}
}
impl<F: Float> fmt::LowerHex for Hexf<(F, i32)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
impl<F: Float> fmt::LowerHex for Hexf<(F, i32)> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
write!(f, "({:x}, {:x})", Hexf(self.0.0), Hexf(self.0.1))
}
}
}
}
}
impl fmt::LowerHex for Hexf<i32> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(&self.0, f)
impl fmt::LowerHex for Hexf<i32> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(&self.0, f)
}
}
}
}
}
impl<T> fmt::Debug for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
impl<T> fmt::Debug for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
}
}
}
}
}
impl<T> fmt::Display for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
impl<T> fmt::Display for Hexf<T>
where
Hexf<T>: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
cfg_if! {
if #[cfg(feature = "compiler-builtins")] {
let _ = f;
unimplemented!()
} else {
fmt::LowerHex::fmt(self, f)
}
}

@@ -483,2 +488,5 @@ }

#[cfg(any(test, feature = "unstable-public-internals"))]
pub use hex_fmt::*;
#[cfg(test)]

@@ -1069,2 +1077,3 @@ mod parse_tests {

use super::*;
use crate::support::Float;

@@ -1071,0 +1080,0 @@ #[test]

use core::{cmp, fmt, ops};
mod narrowing_div;
pub use narrowing_div::NarrowingDiv;
/// Minimal integer implementations needed on all integer types, including wide integers.
#[allow(dead_code)] // Some constants are only used with tests
pub trait MinInt:

@@ -39,4 +43,2 @@ Copy

+ fmt::LowerHex
+ PartialEq
+ PartialOrd
+ ops::AddAssign

@@ -82,2 +84,3 @@ + ops::SubAssign

fn abs(self) -> Self;
fn unsigned_abs(self) -> Self::Unsigned;

@@ -105,3 +108,6 @@ fn from_bool(b: bool) -> Self;

fn overflowing_sub(self, other: Self) -> (Self, bool);
fn carrying_add(self, other: Self, carry: bool) -> (Self, bool);
fn borrowing_sub(self, other: Self, borrow: bool) -> (Self, bool);
fn leading_zeros(self) -> u32;
fn trailing_zeros(self) -> u32;
fn ilog2(self) -> u32;

@@ -172,2 +178,6 @@ }

fn trailing_zeros(self) -> u32 {
<Self>::trailing_zeros(self)
}
fn ilog2(self) -> u32 {

@@ -179,2 +189,16 @@ // On our older MSRV, this resolves to the trait method. Which won't actually work,

}
fn carrying_add(self, other: Self, carry: bool) -> (Self, bool) {
let (ab, of1) = self.overflowing_add(other);
let (abc, of2) = ab.overflowing_add(Self::from_bool(carry));
// `of1 && of2` is possible with signed integers if a negative sum
// overflows to `MAX` and adding the carry overflows again back to `MIN`
(abc, of1 ^ of2)
}
fn borrowing_sub(self, other: Self, borrow: bool) -> (Self, bool) {
let (ab, of1) = self.overflowing_sub(other);
let (abc, of2) = ab.overflowing_sub(Self::from_bool(borrow));
(abc, of1 ^ of2)
}
};

@@ -211,2 +235,6 @@ }

fn unsigned_abs(self) -> Self {
unimplemented!()
}
// It makes writing macros easier if this is implemented for both signed and unsigned

@@ -251,2 +279,6 @@ #[allow(clippy::wrong_self_convention)]

fn unsigned_abs(self) -> Self::Unsigned {
self.unsigned_abs()
}
fn from_unsigned(me: $uty) -> Self {

@@ -274,3 +306,10 @@ me as $ity

/// primitives except for `u8`, because there is not a smaller primitive.
pub trait DInt: MinInt {
pub trait DInt:
MinInt
+ ops::Add<Output = Self>
+ ops::Sub<Output = Self>
+ ops::Shl<u32, Output = Self>
+ ops::Shr<u32, Output = Self>
+ Ord
{
/// Integer that is half the bit width of the integer this trait is implemented for

@@ -376,5 +415,9 @@ type H: HInt<D = Self>;

/// By default, casts should be exact.
#[track_caller]
fn cast(self) -> T;
/// Call for casts that are expected to truncate.
///
/// In practice, this is exactly the same as `cast`; the main difference is to document intent
/// in code. `cast` may panic in debug mode.
fn cast_lossy(self) -> T;

@@ -385,2 +428,3 @@ }

/// By default, casts should be exact.
#[track_caller]
fn cast_from(value: T) -> Self;

@@ -387,0 +431,0 @@

@@ -140,12 +140,14 @@ /// `libm` cannot have dependencies, so this is vendored directly from the `cfg-if` crate

($left:expr, $right:expr, $($tt:tt)*) => {{
use $crate::support::Int;
let l = $left;
let r = $right;
let bits = Int::leading_zeros(l.to_bits() - l.to_bits()); // hack to get the width from the value
// hack to get width from a value
let bits = $crate::support::Int::leading_zeros(l.to_bits() - l.to_bits());
assert!(
l.biteq(r),
"{}\nl: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})",
$crate::support::Float::biteq(l, r),
"{}\nl: {l:?} ({lb:#0width$x} {lh})\nr: {r:?} ({rb:#0width$x} {rh})",
format_args!($($tt)*),
lb = l.to_bits(),
lh = $crate::support::Hexf(l),
rb = r.to_bits(),
rh = $crate::support::Hexf(r),
width = ((bits / 4) + 2) as usize,

@@ -152,0 +154,0 @@

@@ -11,5 +11,9 @@ #[macro_use]

mod int_traits;
mod modular;
#[allow(unused_imports)]
pub use big::{i256, u256};
// Clippy seems to have a false positive
#[allow(unused_imports, clippy::single_component_path_imports)]
pub(crate) use cfg_if;
pub use env::{FpResult, Round, Status};

@@ -19,2 +23,4 @@ #[allow(unused_imports)]

pub(crate) use float_traits::{f32_from_bits, f64_from_bits};
#[cfg(any(test, feature = "unstable-public-internals"))]
pub use hex_float::Hexf;
#[cfg(f16_enabled)]

@@ -27,4 +33,5 @@ #[allow(unused_imports)]

#[allow(unused_imports)]
pub use hex_float::{Hexf, hf32, hf64};
pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt};
pub use hex_float::{hf32, hf64};
pub use int_traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt, NarrowingDiv};
pub use modular::linear_mul_reduction;

@@ -31,0 +38,0 @@ /// Hint to the compiler that the current path is cold.

@@ -46,3 +46,3 @@ // origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn tan(x: f64) -> f64 {

@@ -49,0 +49,0 @@ let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120

@@ -30,3 +30,3 @@ /* origin: FreeBSD /usr/src/lib/msun/src/s_tanf.c */

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn tanf(x: f32) -> f32 {

@@ -33,0 +33,0 @@ let x64 = x as f64;

@@ -11,3 +11,3 @@ use super::expm1;

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn tanh(mut x: f64) -> f64 {

@@ -14,0 +14,0 @@ let mut uf: f64 = x;

@@ -6,3 +6,3 @@ use super::expm1f;

/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn tanhf(mut x: f32) -> f32 {

@@ -9,0 +9,0 @@ /* x = |x| */

@@ -134,3 +134,3 @@ /*

/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn tgamma(mut x: f64) -> f64 {

@@ -137,0 +137,0 @@ let u: u64 = x.to_bits();

use super::tgamma;
/// The [Gamma function](https://en.wikipedia.org/wiki/Gamma_function) (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn tgammaf(x: f32) -> f32 {
tgamma(x as f64) as f32
}

@@ -5,3 +5,3 @@ /// Rounds the number toward 0 to the closest integral value (f16).

#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn truncf16(x: f16) -> f16 {

@@ -14,3 +14,3 @@ super::generic::trunc(x)

/// This effectively removes the decimal part of the number, leaving the integral part.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn truncf(x: f32) -> f32 {

@@ -29,3 +29,3 @@ select_implementation! {

/// This effectively removes the decimal part of the number, leaving the integral part.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn trunc(x: f64) -> f64 {

@@ -45,3 +45,3 @@ select_implementation! {

#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn truncf128(x: f128) -> f128 {

@@ -48,0 +48,0 @@ super::generic::trunc(x)

/// Sign of Y, magnitude of X (f32)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf(x: f32, y: f32) -> f32 {
super::generic::copysign(x, y)
}
/// Sign of Y, magnitude of X (f128)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf128(x: f128, y: f128) -> f128 {
super::generic::copysign(x, y)
}
/// Sign of Y, magnitude of X (f16)
///
/// Constructs a number with the magnitude (absolute value) of its
/// first argument, `x`, and the sign of its second argument, `y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn copysignf16(x: f16, y: f16) -> f16 {
super::generic::copysign(x, y)
}
/// Absolute value (magnitude) (f32)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf(x: f32) -> f32 {
select_implementation! {
name: fabsf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
super::generic::fabs(x)
}
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
#[cfg(not(target_arch = "powerpc64"))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(fabsf(-1.0), 1.0);
assert_eq!(fabsf(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn spec_tests() {
assert!(fabsf(f32::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(fabsf(f), 0.0);
}
for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() {
assert_eq!(fabsf(f), f32::INFINITY);
}
}
}
/// Absolute value (magnitude) (f128)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf128(x: f128) -> f128 {
super::generic::fabs(x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(fabsf128(-1.0), 1.0);
assert_eq!(fabsf128(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn spec_tests() {
assert!(fabsf128(f128::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(fabsf128(f), 0.0);
}
for f in [f128::INFINITY, f128::NEG_INFINITY].iter().copied() {
assert_eq!(fabsf128(f), f128::INFINITY);
}
}
}
/// Absolute value (magnitude) (f16)
///
/// Calculates the absolute value (magnitude) of the argument `x`,
/// by direct manipulation of the bit representation of `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fabsf16(x: f16) -> f16 {
super::generic::fabs(x)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_check() {
assert_eq!(fabsf16(-1.0), 1.0);
assert_eq!(fabsf16(2.8), 2.8);
}
/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs
#[test]
fn spec_tests() {
assert!(fabsf16(f16::NAN).is_nan());
for f in [0.0, -0.0].iter().copied() {
assert_eq!(fabsf16(f), 0.0);
}
for f in [f16::INFINITY, f16::NEG_INFINITY].iter().copied() {
assert_eq!(fabsf16(f), f16::INFINITY);
}
}
}
/// Positive difference (f32)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf(x: f32, y: f32) -> f32 {
super::generic::fdim(x, y)
}
/// Positive difference (f128)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf128(x: f128, y: f128) -> f128 {
super::generic::fdim(x, y)
}
/// Positive difference (f16)
///
/// Determines the positive difference between arguments, returning:
/// * x - y if x > y, or
/// * +0 if x <= y, or
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fdimf16(x: f16, y: f16) -> f16 {
super::generic::fdim(x, y)
}
/// Floor (f32)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf(x: f32) -> f32 {
select_implementation! {
name: floorf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
return super::generic::floor(x);
}
/// Floor (f128)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf128(x: f128) -> f128 {
return super::generic::floor(x);
}
/// Floor (f16)
///
/// Finds the nearest integer less than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn floorf16(x: f16) -> f16 {
return super::generic::floor(x);
}
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf(x: f32, y: f32) -> f32 {
super::generic::fmod(x, y)
}
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf128(x: f128, y: f128) -> f128 {
super::generic::fmod(x, y)
}
/// Calculate the remainder of `x / y`, the precise result of `x - trunc(x / y) * y`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn fmodf16(x: f16, y: f16) -> f16 {
super::generic::fmod(x, y)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ldexpf(x: f32, n: i32) -> f32 {
super::scalbnf(x, n)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ldexpf128(x: f128, n: i32) -> f128 {
super::scalbnf128(x, n)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn ldexpf16(x: f16, n: i32) -> f16 {
super::scalbnf16(x, n)
}
/// Round `x` to the nearest integer, breaking ties away from zero.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn roundf(x: f32) -> f32 {
super::generic::round(x)
}
/// Round `x` to the nearest integer, breaking ties away from zero.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn roundf128(x: f128) -> f128 {
super::generic::round(x)
}
/// Round `x` to the nearest integer, breaking ties away from zero.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn roundf16(x: f16) -> f16 {
super::generic::round(x)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn scalbnf(x: f32, n: i32) -> f32 {
super::generic::scalbn(x, n)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn scalbnf128(x: f128, n: i32) -> f128 {
super::generic::scalbn(x, n)
}
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn scalbnf16(x: f16, n: i32) -> f16 {
super::generic::scalbn(x, n)
}
/// The square root of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrtf(x: f32) -> f32 {
select_implementation! {
name: sqrtf,
use_arch: any(
all(target_arch = "aarch64", target_feature = "neon"),
all(target_arch = "wasm32", intrinsics_enabled),
target_feature = "sse2"
),
args: x,
}
super::generic::sqrt(x)
}
/// The square root of `x` (f128).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrtf128(x: f128) -> f128 {
return super::generic::sqrt(x);
}
/// The square root of `x` (f16).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn sqrtf16(x: f16) -> f16 {
select_implementation! {
name: sqrtf16,
use_arch: all(target_arch = "aarch64", target_feature = "fp16"),
args: x,
}
return super::generic::sqrt(x);
}
/// Rounds the number toward 0 to the closest integral value (f32).
///
/// This effectively removes the decimal part of the number, leaving the integral part.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn truncf(x: f32) -> f32 {
select_implementation! {
name: truncf,
use_arch: all(target_arch = "wasm32", intrinsics_enabled),
args: x,
}
super::generic::trunc(x)
}
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
#[cfg(not(target_arch = "powerpc64"))]
#[cfg(test)]
mod tests {
#[test]
fn sanity_check() {
assert_eq!(super::truncf(1.1), 1.0);
}
}
/// Rounds the number toward 0 to the closest integral value (f128).
///
/// This effectively removes the decimal part of the number, leaving the integral part.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn truncf128(x: f128) -> f128 {
super::generic::trunc(x)
}
/// Rounds the number toward 0 to the closest integral value (f16).
///
/// This effectively removes the decimal part of the number, leaving the integral part.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
pub fn truncf16(x: f16) -> f16 {
super::generic::trunc(x)
}

Sorry, the diff of this file is not supported yet