Run cargo fmt on all projects

Apply the same formatting rules to both `libm` and `compiler-builtins`.
This commit is contained in:
Trevor Gross 2025-04-19 22:39:00 +00:00 committed by Trevor Gross
parent 569b40209d
commit 8d70be87e6
71 changed files with 1070 additions and 283 deletions

View file

@ -480,6 +480,7 @@ mod intrinsics {
fn run() {
use core::hint::black_box as bb;
use intrinsics::*;
// FIXME(f16_f128): some PPC f128 <-> int conversion functions have the wrong names

View file

@ -1,9 +1,8 @@
#![cfg_attr(f128_enabled, feature(f128))]
use builtins_test::float_bench;
use criterion::{Criterion, criterion_main};
use compiler_builtins::float::cmp;
use criterion::{Criterion, criterion_main};
/// `gt` symbols are allowed to return differing results, they just get compared
/// to 0.

View file

@ -239,9 +239,10 @@ mod mcmp {
}
mod mmove {
use super::*;
use Spread::{Aligned, Large, Medium, Small};
use super::*;
struct Cfg {
len: usize,
spread: Spread,

View file

@ -1,6 +1,6 @@
use alloc::vec::Vec;
use core::cell::RefCell;
use alloc::vec::Vec;
use compiler_builtins::float::Float;
/// Fuzz with these many items to ensure equal functions

View file

@ -21,7 +21,6 @@ extern crate alloc;
use compiler_builtins::float::Float;
use compiler_builtins::int::{Int, MinInt};
use rand_xoshiro::Xoshiro128StarStar;
use rand_xoshiro::rand_core::{RngCore, SeedableRng};

View file

@ -97,7 +97,6 @@ mod float_comparisons {
__eqkf2 as __eqtf2, __gekf2 as __getf2, __gtkf2 as __gttf2, __lekf2 as __letf2,
__ltkf2 as __lttf2, __nekf2 as __netf2, __unordkf2 as __unordtf2,
};
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
use compiler_builtins::float::cmp::{
__eqtf2, __getf2, __gttf2, __letf2, __lttf2, __netf2, __unordtf2,

View file

@ -1,11 +1,10 @@
#![feature(f128)]
#![allow(unused_macros)]
use builtins_test::*;
use compiler_builtins::int::sdiv::{__divmoddi4, __divmodsi4, __divmodti4};
use compiler_builtins::int::udiv::{__udivmoddi4, __udivmodsi4, __udivmodti4, u128_divide_sparc};
use builtins_test::*;
// Division algorithms have by far the nastiest and largest number of edge cases, and experience shows
// that sometimes 100_000 iterations of the random fuzzer is needed.

View file

@ -1,8 +1,11 @@
mod configure;
use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering};
use std::collections::BTreeMap;
use std::env;
use std::path::PathBuf;
use std::sync::atomic::Ordering;
use configure::{configure_aliases, configure_f16_f128, Target};
use configure::{Target, configure_aliases, configure_f16_f128};
fn main() {
println!("cargo::rerun-if-changed=build.rs");

View file

@ -1,6 +1,5 @@
use core::arch;
use core::mem;
use core::sync::atomic::{AtomicU32, Ordering};
use core::{arch, mem};
// Kernel-provided user-mode helper functions:
// https://www.kernel.org/doc/Documentation/arm/kernel_user_helpers.txt

View file

@ -1,8 +1,7 @@
use core::ops::Neg;
use crate::int::{CastFrom, CastInto, Int, MinInt};
use super::Float;
use crate::int::{CastFrom, CastInto, Int, MinInt};
/// Conversions from integers to floats.
///

View file

@ -79,11 +79,12 @@
//!
//! [Newton-Raphson method]: https://en.wikipedia.org/wiki/Newton%27s_method
use core::mem::size_of;
use core::ops;
use super::HalfRep;
use crate::float::Float;
use crate::int::{CastFrom, CastInto, DInt, HInt, Int, MinInt};
use core::mem::size_of;
use core::ops;
fn div<F: Float>(a: F, b: F) -> F
where
@ -487,7 +488,7 @@ where
};
residual_lo += abs_result & one; // tie to even
// conditionally turns the below LT comparison into LTE
// conditionally turns the below LT comparison into LTE
abs_result += u8::from(residual_lo > b_significand).into();
if F::BITS == 128 || (F::BITS == 32 && half_iterations > 0) {

View file

@ -11,6 +11,5 @@ pub mod trunc;
#[cfg(not(feature = "public-test-deps"))]
pub(crate) use traits::{Float, HalfRep};
#[cfg(feature = "public-test-deps")]
pub use traits::{Float, HalfRep};

View file

@ -18,11 +18,7 @@ fn pow<F: Float>(a: F, b: i32) -> F {
a *= a;
}
if recip {
F::ONE / mul
} else {
mul
}
if recip { F::ONE / mul } else { mul }
}
intrinsics! {

View file

@ -2,9 +2,10 @@
#![allow(unused)]
use crate::int::{DInt, HInt, Int, MinInt};
use core::{fmt, ops};
use crate::int::{DInt, HInt, Int, MinInt};
const WORD_LO_MASK: u64 = 0x00000000ffffffff;
const WORD_HI_MASK: u64 = 0xffffffff00000000;
const WORD_FULL_MASK: u64 = 0xffffffffffffffff;

View file

@ -60,11 +60,7 @@ mod implementation {
}
// the last two bisections are combined into one conditional
t = x >> 1;
if t != T::ZERO {
z - 2
} else {
z - x.cast()
}
if t != T::ZERO { z - 2 } else { z - x.cast() }
// We could potentially save a few cycles by using the LUT trick from
// "https://embeddedgurus.com/state-space/2014/09/

View file

@ -12,9 +12,7 @@ mod traits;
pub mod udiv;
pub use big::{i256, u256};
#[cfg(not(feature = "public-test-deps"))]
pub(crate) use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt};
#[cfg(feature = "public-test-deps")]
pub use traits::{CastFrom, CastInto, DInt, HInt, Int, MinInt};

View file

@ -58,7 +58,6 @@ mod delegate;
#[allow(unused_imports)]
#[cfg(not(feature = "public-test-deps"))]
pub(crate) use self::delegate::u128_divide_sparc;
#[cfg(feature = "public-test-deps")]
pub use self::delegate::u128_divide_sparc;

View file

@ -1,6 +1,5 @@
#[cfg(not(feature = "public-test-deps"))]
pub(crate) use crate::int::specialized_div_rem::*;
#[cfg(feature = "public-test-deps")]
pub use crate::int::specialized_div_rem::*;

View file

@ -17,8 +17,7 @@
// Note that ERMSB does not enhance the backwards (DF=1) "rep movsb".
use core::arch::asm;
use core::intrinsics;
use core::mem;
use core::{intrinsics, mem};
#[inline(always)]
#[cfg(target_feature = "ermsb")]

View file

@ -26,7 +26,10 @@ pub fn function_enum(
};
if let Some(tt) = attr.next() {
return Err(syn::Error::new(tt.span(), "unexpected token after identifier"));
return Err(syn::Error::new(
tt.span(),
"unexpected token after identifier",
));
}
let enum_name = &item.ident;
@ -46,8 +49,12 @@ pub fn function_enum(
// Match arm for `fn base_name(self)` matcher
base_arms.push(quote! { Self::#ident => #base_enum::#bname_ident });
let variant =
Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None };
let variant = Variant {
attrs: Vec::new(),
ident,
fields: Fields::Unit,
discriminant: None,
};
item.variants.push(variant);
}
@ -108,7 +115,10 @@ pub fn base_name_enum(
return Err(syn::Error::new(sp.span(), "no attributes expected"));
}
let mut base_names: Vec<_> = ALL_OPERATIONS.iter().map(|func| base_name(func.name)).collect();
let mut base_names: Vec<_> = ALL_OPERATIONS
.iter()
.map(|func| base_name(func.name))
.collect();
base_names.sort_unstable();
base_names.dedup();
@ -121,8 +131,12 @@ pub fn base_name_enum(
// Match arm for `fn as_str(self)` matcher
as_str_arms.push(quote! { Self::#ident => #base_name });
let variant =
Variant { attrs: Vec::new(), ident, fields: Fields::Unit, discriminant: None };
let variant = Variant {
attrs: Vec::new(),
ident,
fields: Fields::Unit,
discriminant: None,
};
item.variants.push(variant);
}
@ -147,7 +161,10 @@ pub fn base_name_enum(
/// Verify that an enum is empty, otherwise return an error
fn expect_empty_enum(item: &ItemEnum) -> syn::Result<()> {
if !item.variants.is_empty() {
Err(syn::Error::new(item.variants.span(), "expected an empty enum"))
Err(syn::Error::new(
item.variants.span(),
"expected an empty enum",
))
} else {
Ok(())
}

View file

@ -11,7 +11,9 @@ use syn::spanned::Spanned;
use syn::visit_mut::VisitMut;
use syn::{Ident, ItemEnum};
const KNOWN_TYPES: &[&str] = &["FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet"];
const KNOWN_TYPES: &[&str] = &[
"FTy", "CFn", "CArgs", "CRet", "RustFn", "RustArgs", "RustRet",
];
/// Populate an enum with a variant representing function. Names are in upper camel case.
///
@ -142,10 +144,17 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>
.flat_map(|map_list| map_list.iter())
.flat_map(|attr_map| attr_map.names.iter());
let only_mentions = input.only.iter().flat_map(|only_list| only_list.iter());
let fn_extra_mentions =
input.fn_extra.iter().flat_map(|v| v.keys()).filter(|name| *name != "_");
let all_mentioned_fns =
input.skip.iter().chain(only_mentions).chain(attr_mentions).chain(fn_extra_mentions);
let fn_extra_mentions = input
.fn_extra
.iter()
.flat_map(|v| v.keys())
.filter(|name| *name != "_");
let all_mentioned_fns = input
.skip
.iter()
.chain(only_mentions)
.chain(attr_mentions)
.chain(fn_extra_mentions);
// Make sure that every function mentioned is a real function
for mentioned in all_mentioned_fns {
@ -171,7 +180,11 @@ fn validate(input: &mut StructuredInput) -> syn::Result<Vec<&'static MathOpInfo>
for func in ALL_OPERATIONS.iter() {
let fn_name = func.name;
// If we have an `only` list and it does _not_ contain this function name, skip it
if input.only.as_ref().is_some_and(|only| !only.iter().any(|o| o == fn_name)) {
if input
.only
.as_ref()
.is_some_and(|only| !only.iter().any(|o| o == fn_name))
{
continue;
}
@ -296,8 +309,11 @@ fn expand(input: StructuredInput, fn_list: &[&MathOpInfo]) -> syn::Result<pm2::T
// Prepare function-specific extra in a `fn_extra: ...` field, running the replacer
let fn_extra_field = match input.fn_extra {
Some(ref map) => {
let mut fn_extra =
map.get(&fn_name).or_else(|| map.get(&default_ident)).unwrap().clone();
let mut fn_extra = map
.get(&fn_name)
.or_else(|| map.get(&default_ident))
.unwrap()
.clone();
let mut v = MacroReplace::new(func.name);
v.visit_expr_mut(&mut fn_extra);
@ -357,7 +373,11 @@ struct MacroReplace {
impl MacroReplace {
fn new(name: &'static str) -> Self {
let norm_name = base_name(name);
Self { fn_name: name, norm_name: norm_name.to_owned(), error: None }
Self {
fn_name: name,
norm_name: norm_name.to_owned(),
error: None,
}
}
fn finish(self) -> syn::Result<()> {
@ -377,8 +397,10 @@ impl MacroReplace {
"MACRO_FN_NAME" => *i = Ident::new(self.fn_name, i.span()),
"MACRO_FN_NAME_NORMALIZED" => *i = Ident::new(&self.norm_name, i.span()),
_ => {
self.error =
Some(syn::Error::new(i.span(), format!("unrecognized meta expression `{s}`")));
self.error = Some(syn::Error::new(
i.span(),
format!("unrecognized meta expression `{s}`"),
));
}
}
}

View file

@ -16,7 +16,9 @@ pub struct Invocation {
impl Parse for Invocation {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self { fields: input.parse_terminated(Mapping::parse, Token![,])? })
Ok(Self {
fields: input.parse_terminated(Mapping::parse, Token![,])?,
})
}
}
@ -30,7 +32,11 @@ struct Mapping {
impl Parse for Mapping {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self { name: input.parse()?, _sep: input.parse()?, expr: input.parse()? })
Ok(Self {
name: input.parse()?,
_sep: input.parse()?,
expr: input.parse()?,
})
}
}
@ -133,7 +139,13 @@ fn extract_fn_extra_field(expr: Expr) -> syn::Result<BTreeMap<Ident, Expr>> {
return Err(e);
};
let ExprMatch { attrs, match_token: _, expr, brace_token: _, arms } = mexpr;
let ExprMatch {
attrs,
match_token: _,
expr,
brace_token: _,
arms,
} = mexpr;
expect_empty_attrs(&attrs)?;
@ -146,7 +158,14 @@ fn extract_fn_extra_field(expr: Expr) -> syn::Result<BTreeMap<Ident, Expr>> {
let mut res = BTreeMap::new();
for arm in arms {
let Arm { attrs, pat, guard, fat_arrow_token: _, body, comma: _ } = arm;
let Arm {
attrs,
pat,
guard,
fat_arrow_token: _,
body,
comma: _,
} = arm;
expect_empty_attrs(&attrs)?;
@ -177,15 +196,20 @@ fn expect_empty_attrs(attrs: &[Attribute]) -> syn::Result<()> {
return Ok(());
}
let e =
syn::Error::new(attrs.first().unwrap().span(), "no attributes allowed in this position");
let e = syn::Error::new(
attrs.first().unwrap().span(),
"no attributes allowed in this position",
);
Err(e)
}
/// Extract a named field from a map, raising an error if it doesn't exist.
fn expect_field(v: &mut Vec<Mapping>, name: &str) -> syn::Result<Expr> {
let pos = v.iter().position(|v| v.name == name).ok_or_else(|| {
syn::Error::new(Span::call_site(), format!("missing expected field `{name}`"))
syn::Error::new(
Span::call_site(),
format!("missing expected field `{name}`"),
)
})?;
Ok(v.remove(pos).expr)

View file

@ -7,7 +7,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `fn(f16) -> f16`
FloatTy::F16,
Signature { args: &[Ty::F16], returns: &[Ty::F16] },
Signature {
args: &[Ty::F16],
returns: &[Ty::F16],
},
None,
&[
"ceilf16",
@ -23,7 +26,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `fn(f32) -> f32`
FloatTy::F32,
Signature { args: &[Ty::F32], returns: &[Ty::F32] },
Signature {
args: &[Ty::F32],
returns: &[Ty::F32],
},
None,
&[
"acosf",
@ -68,7 +74,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `(f64) -> f64`
FloatTy::F64,
Signature { args: &[Ty::F64], returns: &[Ty::F64] },
Signature {
args: &[Ty::F64],
returns: &[Ty::F64],
},
None,
&[
"acos",
@ -113,7 +122,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `fn(f128) -> f128`
FloatTy::F128,
Signature { args: &[Ty::F128], returns: &[Ty::F128] },
Signature {
args: &[Ty::F128],
returns: &[Ty::F128],
},
None,
&[
"ceilf128",
@ -129,7 +141,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `(f16, f16) -> f16`
FloatTy::F16,
Signature { args: &[Ty::F16, Ty::F16], returns: &[Ty::F16] },
Signature {
args: &[Ty::F16, Ty::F16],
returns: &[Ty::F16],
},
None,
&[
"copysignf16",
@ -146,7 +161,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `(f32, f32) -> f32`
FloatTy::F32,
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32] },
Signature {
args: &[Ty::F32, Ty::F32],
returns: &[Ty::F32],
},
None,
&[
"atan2f",
@ -168,7 +186,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `(f64, f64) -> f64`
FloatTy::F64,
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64] },
Signature {
args: &[Ty::F64, Ty::F64],
returns: &[Ty::F64],
},
None,
&[
"atan2",
@ -190,7 +211,10 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `(f128, f128) -> f128`
FloatTy::F128,
Signature { args: &[Ty::F128, Ty::F128], returns: &[Ty::F128] },
Signature {
args: &[Ty::F128, Ty::F128],
returns: &[Ty::F128],
},
None,
&[
"copysignf128",
@ -207,134 +231,215 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option<Signature>, &[&str])]
(
// `(f32, f32, f32) -> f32`
FloatTy::F32,
Signature { args: &[Ty::F32, Ty::F32, Ty::F32], returns: &[Ty::F32] },
Signature {
args: &[Ty::F32, Ty::F32, Ty::F32],
returns: &[Ty::F32],
},
None,
&["fmaf"],
),
(
// `(f64, f64, f64) -> f64`
FloatTy::F64,
Signature { args: &[Ty::F64, Ty::F64, Ty::F64], returns: &[Ty::F64] },
Signature {
args: &[Ty::F64, Ty::F64, Ty::F64],
returns: &[Ty::F64],
},
None,
&["fma"],
),
(
// `(f128, f128, f128) -> f128`
FloatTy::F128,
Signature { args: &[Ty::F128, Ty::F128, Ty::F128], returns: &[Ty::F128] },
Signature {
args: &[Ty::F128, Ty::F128, Ty::F128],
returns: &[Ty::F128],
},
None,
&["fmaf128"],
),
(
// `(f32) -> i32`
FloatTy::F32,
Signature { args: &[Ty::F32], returns: &[Ty::I32] },
Signature {
args: &[Ty::F32],
returns: &[Ty::I32],
},
None,
&["ilogbf"],
),
(
// `(f64) -> i32`
FloatTy::F64,
Signature { args: &[Ty::F64], returns: &[Ty::I32] },
Signature {
args: &[Ty::F64],
returns: &[Ty::I32],
},
None,
&["ilogb"],
),
(
// `(i32, f32) -> f32`
FloatTy::F32,
Signature { args: &[Ty::I32, Ty::F32], returns: &[Ty::F32] },
Signature {
args: &[Ty::I32, Ty::F32],
returns: &[Ty::F32],
},
None,
&["jnf", "ynf"],
),
(
// `(i32, f64) -> f64`
FloatTy::F64,
Signature { args: &[Ty::I32, Ty::F64], returns: &[Ty::F64] },
Signature {
args: &[Ty::I32, Ty::F64],
returns: &[Ty::F64],
},
None,
&["jn", "yn"],
),
(
// `(f16, i32) -> f16`
FloatTy::F16,
Signature { args: &[Ty::F16, Ty::I32], returns: &[Ty::F16] },
Signature {
args: &[Ty::F16, Ty::I32],
returns: &[Ty::F16],
},
None,
&["ldexpf16", "scalbnf16"],
),
(
// `(f32, i32) -> f32`
FloatTy::F32,
Signature { args: &[Ty::F32, Ty::I32], returns: &[Ty::F32] },
Signature {
args: &[Ty::F32, Ty::I32],
returns: &[Ty::F32],
},
None,
&["ldexpf", "scalbnf"],
),
(
// `(f64, i64) -> f64`
FloatTy::F64,
Signature { args: &[Ty::F64, Ty::I32], returns: &[Ty::F64] },
Signature {
args: &[Ty::F64, Ty::I32],
returns: &[Ty::F64],
},
None,
&["ldexp", "scalbn"],
),
(
// `(f128, i32) -> f128`
FloatTy::F128,
Signature { args: &[Ty::F128, Ty::I32], returns: &[Ty::F128] },
Signature {
args: &[Ty::F128, Ty::I32],
returns: &[Ty::F128],
},
None,
&["ldexpf128", "scalbnf128"],
),
(
// `(f32, &mut f32) -> f32` as `(f32) -> (f32, f32)`
FloatTy::F32,
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
Some(Signature { args: &[Ty::F32, Ty::MutF32], returns: &[Ty::F32] }),
Signature {
args: &[Ty::F32],
returns: &[Ty::F32, Ty::F32],
},
Some(Signature {
args: &[Ty::F32, Ty::MutF32],
returns: &[Ty::F32],
}),
&["modff"],
),
(
// `(f64, &mut f64) -> f64` as `(f64) -> (f64, f64)`
FloatTy::F64,
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
Some(Signature { args: &[Ty::F64, Ty::MutF64], returns: &[Ty::F64] }),
Signature {
args: &[Ty::F64],
returns: &[Ty::F64, Ty::F64],
},
Some(Signature {
args: &[Ty::F64, Ty::MutF64],
returns: &[Ty::F64],
}),
&["modf"],
),
(
// `(f32, &mut c_int) -> f32` as `(f32) -> (f32, i32)`
FloatTy::F32,
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::I32] },
Some(Signature { args: &[Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
Signature {
args: &[Ty::F32],
returns: &[Ty::F32, Ty::I32],
},
Some(Signature {
args: &[Ty::F32, Ty::MutCInt],
returns: &[Ty::F32],
}),
&["frexpf", "lgammaf_r"],
),
(
// `(f64, &mut c_int) -> f64` as `(f64) -> (f64, i32)`
FloatTy::F64,
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::I32] },
Some(Signature { args: &[Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
Signature {
args: &[Ty::F64],
returns: &[Ty::F64, Ty::I32],
},
Some(Signature {
args: &[Ty::F64, Ty::MutCInt],
returns: &[Ty::F64],
}),
&["frexp", "lgamma_r"],
),
(
// `(f32, f32, &mut c_int) -> f32` as `(f32, f32) -> (f32, i32)`
FloatTy::F32,
Signature { args: &[Ty::F32, Ty::F32], returns: &[Ty::F32, Ty::I32] },
Some(Signature { args: &[Ty::F32, Ty::F32, Ty::MutCInt], returns: &[Ty::F32] }),
Signature {
args: &[Ty::F32, Ty::F32],
returns: &[Ty::F32, Ty::I32],
},
Some(Signature {
args: &[Ty::F32, Ty::F32, Ty::MutCInt],
returns: &[Ty::F32],
}),
&["remquof"],
),
(
// `(f64, f64, &mut c_int) -> f64` as `(f64, f64) -> (f64, i32)`
FloatTy::F64,
Signature { args: &[Ty::F64, Ty::F64], returns: &[Ty::F64, Ty::I32] },
Some(Signature { args: &[Ty::F64, Ty::F64, Ty::MutCInt], returns: &[Ty::F64] }),
Signature {
args: &[Ty::F64, Ty::F64],
returns: &[Ty::F64, Ty::I32],
},
Some(Signature {
args: &[Ty::F64, Ty::F64, Ty::MutCInt],
returns: &[Ty::F64],
}),
&["remquo"],
),
(
// `(f32, &mut f32, &mut f32)` as `(f32) -> (f32, f32)`
FloatTy::F32,
Signature { args: &[Ty::F32], returns: &[Ty::F32, Ty::F32] },
Some(Signature { args: &[Ty::F32, Ty::MutF32, Ty::MutF32], returns: &[] }),
Signature {
args: &[Ty::F32],
returns: &[Ty::F32, Ty::F32],
},
Some(Signature {
args: &[Ty::F32, Ty::MutF32, Ty::MutF32],
returns: &[],
}),
&["sincosf"],
),
(
// `(f64, &mut f64, &mut f64)` as `(f64) -> (f64, f64)`
FloatTy::F64,
Signature { args: &[Ty::F64], returns: &[Ty::F64, Ty::F64] },
Some(Signature { args: &[Ty::F64, Ty::MutF64, Ty::MutF64], returns: &[] }),
Signature {
args: &[Ty::F64],
returns: &[Ty::F64, Ty::F64],
},
Some(Signature {
args: &[Ty::F64, Ty::MutF64, Ty::MutF64],
returns: &[],
}),
&["sincos"],
),
];

View file

@ -8,7 +8,10 @@ const LIB_NAME: &str = "musl_math_prefixed";
/// Files that have more than one symbol. Map of file names to the symbols defined in that file.
const MULTIPLE_SYMBOLS: &[(&str, &[&str])] = &[
("__invtrigl", &["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"]),
(
"__invtrigl",
&["__invtrigl", "__invtrigl_R", "__pio2_hi", "__pio2_lo"],
),
("__polevll", &["__polevll", "__p1evll"]),
("erf", &["erf", "erfc"]),
("erff", &["erff", "erfcf"]),
@ -82,9 +85,16 @@ impl Config {
let musl_dir = manifest_dir.join("musl");
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let musl_arch = if target_arch == "x86" { "i386".to_owned() } else { target_arch.clone() };
let musl_arch = if target_arch == "x86" {
"i386".to_owned()
} else {
target_arch.clone()
};
println!("cargo::rerun-if-changed={}/c_patches", manifest_dir.display());
println!(
"cargo::rerun-if-changed={}/c_patches",
manifest_dir.display()
);
println!("cargo::rerun-if-changed={}", musl_dir.display());
Self {
@ -108,7 +118,10 @@ fn build_musl_math(cfg: &Config) {
let musl_dir = &cfg.musl_dir;
let math = musl_dir.join("src/math");
let arch_dir = musl_dir.join("arch").join(&cfg.musl_arch);
assert!(math.exists(), "musl source not found. Is the submodule up to date?");
assert!(
math.exists(),
"musl source not found. Is the submodule up to date?"
);
let source_map = find_math_source(&math, cfg);
let out_path = cfg.out_dir.join(format!("lib{LIB_NAME}.a"));
@ -125,7 +138,11 @@ fn build_musl_math(cfg: &Config) {
.stderr(Stdio::inherit())
.output()
.unwrap();
assert!(sed_stat.status.success(), "sed command failed: {:?}", sed_stat.status);
assert!(
sed_stat.status.success(),
"sed command failed: {:?}",
sed_stat.status
);
fs::write(obj_include.join("bits/alltypes.h"), sed_stat.stdout).unwrap();
@ -163,8 +180,9 @@ fn build_musl_math(cfg: &Config) {
// Trickery! Redefine the symbol names to have the prefix `musl_`, which allows us to
// differentiate these symbols from whatever we provide.
if let Some((_names, syms)) =
MULTIPLE_SYMBOLS.iter().find(|(name, _syms)| *name == sym_name)
if let Some((_names, syms)) = MULTIPLE_SYMBOLS
.iter()
.find(|(name, _syms)| *name == sym_name)
{
// Handle the occasional file that defines multiple symbols
for sym in *syms {
@ -291,21 +309,34 @@ fn validate_archive_symbols(out_path: &Path) {
];
// List global undefined symbols
let out =
Command::new("nm").arg("-guj").arg(out_path).stderr(Stdio::inherit()).output().unwrap();
let out = Command::new("nm")
.arg("-guj")
.arg(out_path)
.stderr(Stdio::inherit())
.output()
.unwrap();
let undef = str::from_utf8(&out.stdout).unwrap();
let mut undef = undef.lines().collect::<Vec<_>>();
undef.retain(|sym| {
// Account for file formats that add a leading `_`
!ALLOWED_UNDEF_PFX.iter().any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx))
!ALLOWED_UNDEF_PFX
.iter()
.any(|pfx| sym.starts_with(pfx) || sym[1..].starts_with(pfx))
});
assert!(undef.is_empty(), "found disallowed undefined symbols: {undef:#?}");
assert!(
undef.is_empty(),
"found disallowed undefined symbols: {undef:#?}"
);
// Find any symbols that are missing the `_musl_` prefix`
let out =
Command::new("nm").arg("-gUj").arg(out_path).stderr(Stdio::inherit()).output().unwrap();
let out = Command::new("nm")
.arg("-gUj")
.arg(out_path)
.stderr(Stdio::inherit())
.output()
.unwrap();
let defined = str::from_utf8(&out.stdout).unwrap();
let mut defined = defined.lines().collect::<Vec<_>>();

View file

@ -221,7 +221,11 @@ macro_rules! impl_parse_tuple_via_rug {
impl ParseTuple for ($ty, $ty, $ty) {
fn parse(input: &[&str]) -> Self {
assert_eq!(input.len(), 3, "expected three arguments, got {input:?}");
(parse_rug(input, 0), parse_rug(input, 1), parse_rug(input, 2))
(
parse_rug(input, 0),
parse_rug(input, 1),
parse_rug(input, 2),
)
}
}
};

View file

@ -7,7 +7,11 @@ use libm_test::generate::random::RandomInput;
use libm_test::{CheckBasis, CheckCtx, GeneratorKind, MathOp, TupleCall};
/// Benchmark with this many items to get a variety
const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") { 50 } else { 500 };
const BENCH_ITER_ITEMS: usize = if cfg!(feature = "short-benchmarks") {
50
} else {
500
};
/// Extra parameters we only care about if we are benchmarking against musl.
#[allow(dead_code)]
@ -53,8 +57,10 @@ where
let name = Op::NAME;
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl, GeneratorKind::Random);
let benchvec: Vec<_> =
random::get_test_cases::<Op::RustArgs>(&ctx).0.take(BENCH_ITER_ITEMS).collect();
let benchvec: Vec<_> = random::get_test_cases::<Op::RustArgs>(&ctx)
.0
.take(BENCH_ITER_ITEMS)
.collect();
// Perform a sanity check that we are benchmarking the same thing
// Don't test against musl if it is not available
@ -73,7 +79,10 @@ where
let musl_res = input.call(musl_fn);
let crate_res = input.call(Op::ROUTINE);
crate_res.validate(musl_res, input, &ctx).context(name).unwrap();
crate_res
.validate(musl_res, input, &ctx)
.context(name)
.unwrap();
}
#[cfg(not(feature = "build-musl"))]

View file

@ -56,7 +56,13 @@ where
Op::RustArgs: SpacedInput<Op>,
{
let mut ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Mpfr, GeneratorKind::QuickSpaced);
plot_one_generator(out_dir, &ctx, "logspace", config, spaced::get_test_cases::<Op>(&ctx).0);
plot_one_generator(
out_dir,
&ctx,
"logspace",
config,
spaced::get_test_cases::<Op>(&ctx).0,
);
ctx.gen_kind = GeneratorKind::EdgeCases;
plot_one_generator(
out_dir,

View file

@ -67,16 +67,25 @@ impl<F: fmt::Debug, I: fmt::Debug> EitherPrim<F, I> {
/// Convenience 1-dimensional float domains.
impl<F: Float> Domain<F> {
/// x ∈
const UNBOUNDED: Self =
Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None };
const UNBOUNDED: Self = Self {
start: Bound::Unbounded,
end: Bound::Unbounded,
check_points: None,
};
/// x ∈ >= 0
const POSITIVE: Self =
Self { start: Bound::Included(F::ZERO), end: Bound::Unbounded, check_points: None };
const POSITIVE: Self = Self {
start: Bound::Included(F::ZERO),
end: Bound::Unbounded,
check_points: None,
};
/// x ∈ > 0
const STRICTLY_POSITIVE: Self =
Self { start: Bound::Excluded(F::ZERO), end: Bound::Unbounded, check_points: None };
const STRICTLY_POSITIVE: Self = Self {
start: Bound::Excluded(F::ZERO),
end: Bound::Unbounded,
check_points: None,
};
/// Wrap in the float variant of [`EitherPrim`].
const fn into_prim_float<I>(self) -> EitherPrim<Self, Domain<I>> {
@ -87,8 +96,11 @@ impl<F: Float> Domain<F> {
/// Convenience 1-dimensional integer domains.
impl<I: Int> Domain<I> {
/// x ∈
const UNBOUNDED_INT: Self =
Self { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None };
const UNBOUNDED_INT: Self = Self {
start: Bound::Unbounded,
end: Bound::Unbounded,
check_points: None,
};
/// Wrap in the int variant of [`EitherPrim`].
const fn into_prim_int<F>(self) -> EitherPrim<Domain<F>, Self> {
@ -99,13 +111,18 @@ impl<I: Int> Domain<I> {
/// Multidimensional domains, represented as an array of 1-D domains.
impl<F: Float, I: Int> EitherPrim<Domain<F>, Domain<I>> {
/// x ∈
const UNBOUNDED1: [Self; 1] =
[Domain { start: Bound::Unbounded, end: Bound::Unbounded, check_points: None }
.into_prim_float()];
const UNBOUNDED1: [Self; 1] = [Domain {
start: Bound::Unbounded,
end: Bound::Unbounded,
check_points: None,
}
.into_prim_float()];
/// {x1, x2} ∈
const UNBOUNDED2: [Self; 2] =
[Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED.into_prim_float()];
const UNBOUNDED2: [Self; 2] = [
Domain::UNBOUNDED.into_prim_float(),
Domain::UNBOUNDED.into_prim_float(),
];
/// {x1, x2, x3} ∈
const UNBOUNDED3: [Self; 3] = [
@ -115,8 +132,10 @@ impl<F: Float, I: Int> EitherPrim<Domain<F>, Domain<I>> {
];
/// {x1, x2} ∈ , one float and one int
const UNBOUNDED_F_I: [Self; 2] =
[Domain::UNBOUNDED.into_prim_float(), Domain::UNBOUNDED_INT.into_prim_int()];
const UNBOUNDED_F_I: [Self; 2] = [
Domain::UNBOUNDED.into_prim_float(),
Domain::UNBOUNDED_INT.into_prim_int(),
];
/// x ∈ >= 0
const POSITIVE: [Self; 1] = [Domain::POSITIVE.into_prim_float()];
@ -133,9 +152,12 @@ impl<F: Float, I: Int> EitherPrim<Domain<F>, Domain<I>> {
.into_prim_float()];
/// Domain for `acosh`
const ACOSH: [Self; 1] =
[Domain { start: Bound::Included(F::ONE), end: Bound::Unbounded, check_points: None }
.into_prim_float()];
const ACOSH: [Self; 1] = [Domain {
start: Bound::Included(F::ONE),
end: Bound::Unbounded,
check_points: None,
}
.into_prim_float()];
/// Domain for `atanh`
const ATANH: [Self; 1] = [Domain {
@ -157,9 +179,12 @@ impl<F: Float, I: Int> EitherPrim<Domain<F>, Domain<I>> {
const LOG: [Self; 1] = Self::STRICTLY_POSITIVE;
/// Domain for `log1p` i.e. `log(1 + x)`
const LOG1P: [Self; 1] =
[Domain { start: Bound::Excluded(F::NEG_ONE), end: Bound::Unbounded, check_points: None }
.into_prim_float()];
const LOG1P: [Self; 1] = [Domain {
start: Bound::Excluded(F::NEG_ONE),
end: Bound::Unbounded,
check_points: None,
}
.into_prim_float()];
/// Domain for `sqrt`
const SQRT: [Self; 1] = Self::POSITIVE;
@ -187,8 +212,10 @@ impl<F: Float, I: Int> EitherPrim<Domain<F>, Domain<I>> {
/// Domain for `jn` and `yn`.
// FIXME: the domain should provide some sort of "reasonable range" so we don't actually test
// the entire system unbounded.
const BESSEL_N: [Self; 2] =
[Domain::UNBOUNDED_INT.into_prim_int(), Domain::UNBOUNDED.into_prim_float()];
const BESSEL_N: [Self; 2] = [
Domain::UNBOUNDED_INT.into_prim_int(),
Domain::UNBOUNDED.into_prim_float(),
];
}
/// Get the domain for a given function.

View file

@ -498,6 +498,8 @@ impl fmt::LowerHex for f8 {
}
pub const fn hf8(s: &str) -> f8 {
let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else { panic!() };
let Ok(bits) = libm::support::hex_float::parse_hex_exact(s, 8, 3) else {
panic!()
};
f8(bits as u8)
}

View file

@ -16,7 +16,11 @@ pub struct KnownSize<I> {
impl<I> KnownSize<I> {
pub fn new(iter: I, total: u64) -> Self {
Self { total, current: 0, iter }
Self {
total,
current: 0,
iter,
}
}
}
@ -30,7 +34,10 @@ impl<I: Iterator> Iterator for KnownSize<I> {
return next;
}
assert_eq!(self.current, self.total, "total items did not match expected");
assert_eq!(
self.current, self.total,
"total items did not match expected"
);
None
}

View file

@ -20,14 +20,21 @@ pub struct TestCase<Op: MathOp> {
impl<Op: MathOp> TestCase<Op> {
#[expect(dead_code)]
fn append_inputs(v: &mut Vec<Self>, l: &[Op::RustArgs]) {
v.extend(l.iter().copied().map(|input| Self { input, output: None }));
v.extend(l.iter().copied().map(|input| Self {
input,
output: None,
}));
}
fn append_pairs(v: &mut Vec<Self>, l: &[(Op::RustArgs, Option<Op::RustRet>)])
where
Op::RustRet: Copy,
{
v.extend(l.iter().copied().map(|(input, output)| Self { input, output }));
v.extend(
l.iter()
.copied()
.map(|(input, output)| Self { input, output }),
);
}
}
@ -603,9 +610,15 @@ fn rint_cases() -> Vec<TestCase<op::rint::Routine>> {
&[
// Known failure on i586
#[cfg(not(x86_no_sse))]
((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))),
(
(hf64!("-0x1.e3f13ff995ffcp+38"),),
Some(hf64!("-0x1.e3f13ff994000p+38")),
),
#[cfg(x86_no_sse)]
((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))),
(
(hf64!("-0x1.e3f13ff995ffcp+38"),),
Some(hf64!("-0x1.e3f13ff998000p+38")),
),
],
);
v
@ -655,9 +668,15 @@ fn roundeven_cases() -> Vec<TestCase<op::roundeven::Routine>> {
&[
// Known failure on i586
#[cfg(not(x86_no_sse))]
((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff994000p+38"))),
(
(hf64!("-0x1.e3f13ff995ffcp+38"),),
Some(hf64!("-0x1.e3f13ff994000p+38")),
),
#[cfg(x86_no_sse)]
((hf64!("-0x1.e3f13ff995ffcp+38"),), Some(hf64!("-0x1.e3f13ff998000p+38"))),
(
(hf64!("-0x1.e3f13ff995ffcp+38"),),
Some(hf64!("-0x1.e3f13ff998000p+38")),
),
],
);
v
@ -832,7 +851,9 @@ where
{
assert_eq!(ctx.basis, CheckBasis::None);
assert_eq!(ctx.gen_kind, GeneratorKind::List);
Op::get_cases().into_iter().filter_map(|x| x.output.map(|o| (x.input, o)))
Op::get_cases()
.into_iter()
.filter_map(|x| x.output.map(|o| (x.input, o)))
}
/// Opposite of the above; extract only test cases that don't have a known output, to be run
@ -847,7 +868,18 @@ where
assert_eq!(ctx.gen_kind, GeneratorKind::List);
let cases = Op::get_cases();
let count: u64 = cases.iter().filter(|case| case.output.is_none()).count().try_into().unwrap();
let count: u64 = cases
.iter()
.filter(|case| case.output.is_none())
.count()
.try_into()
.unwrap();
(cases.into_iter().filter(|x| x.output.is_none()).map(|x| x.input), count)
(
cases
.into_iter()
.filter(|x| x.output.is_none())
.map(|x| x.input),
count,
)
}

View file

@ -249,7 +249,11 @@ macro_rules! impl_edge_case_input {
.flat_map(move |(first, second)| {
iter2.clone().map(move |third| (first, second, third))
});
let count = steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap();
let count = steps0
.checked_mul(steps1)
.unwrap()
.checked_mul(steps2)
.unwrap();
(iter, count)
}

View file

@ -117,7 +117,10 @@ impl_random_input!(f128);
/// Create a test case iterator.
pub fn get_test_cases<RustArgs: RandomInput>(
ctx: &CheckCtx,
) -> (impl Iterator<Item = RustArgs> + Send + use<'_, RustArgs>, u64) {
) -> (
impl Iterator<Item = RustArgs> + Send + use<'_, RustArgs>,
u64,
) {
let (iter, count) = RustArgs::get_cases(ctx);
// Wrap in `KnownSize` so we get an assertion if the cuunt is wrong.

View file

@ -70,7 +70,9 @@ fn value_count<F: Float>() -> Option<u64>
where
u64: TryFrom<F::Int>,
{
u64::try_from(F::Int::MAX).ok().and_then(|max| max.checked_add(1))
u64::try_from(F::Int::MAX)
.ok()
.and_then(|max| max.checked_add(1))
}
/// Returns an iterator of every possible value of type `F`.
@ -162,8 +164,11 @@ macro_rules! impl_spaced_input {
.flat_map(move |(first, second)| {
iter2.clone().map(move |third| (first, second, third))
});
let count =
steps0.checked_mul(steps1).unwrap().checked_mul(steps2).unwrap();
let count = steps0
.checked_mul(steps1)
.unwrap()
.checked_mul(steps2)
.unwrap();
(EitherIter::B(iter), count)
}

View file

@ -71,7 +71,12 @@ pub fn test_log(s: &str) {
return None;
};
PathBuf::from(x).parent().unwrap().parent().unwrap().join("target")
PathBuf::from(x)
.parent()
.unwrap()
.parent()
.unwrap()
.join("target")
}
};
let outfile = target_dir.join("test-log.txt");
@ -81,7 +86,9 @@ pub fn test_log(s: &str) {
.append(true)
.open(outfile)
.expect("failed to open logfile");
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
writeln!(f, "\n\nTest run at {}", now.as_secs()).unwrap();
writeln!(f, "arch: {}", env::consts::ARCH).unwrap();

View file

@ -180,8 +180,17 @@ impl<F: FloatExt> Consts<F> {
neg_max_snan,
} = self;
[pos_nan, neg_nan, max_qnan, min_snan, max_snan, neg_max_qnan, neg_min_snan, neg_max_snan]
.into_iter()
[
pos_nan,
neg_nan,
max_qnan,
min_snan,
max_snan,
neg_max_qnan,
neg_min_snan,
neg_max_snan,
]
.into_iter()
}
}
@ -229,7 +238,9 @@ where
assert!(!end.is_nan());
assert!(end >= start);
let steps = steps.checked_sub(F::Int::ONE).expect("`steps` must be at least 2");
let steps = steps
.checked_sub(F::Int::ONE)
.expect("`steps` must be at least 2");
let between = ulp_between(start, end).expect("`start` or `end` is NaN");
let spacing = (between / steps).max(F::Int::ONE);
let steps = steps.min(between); // At maximum, one step per ULP
@ -283,15 +294,22 @@ mod tests {
if i == 0 {
assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} next_down({v:#010b})");
} else {
let expected =
if v == f8::ZERO { 1 | f8::SIGN_MASK } else { f8::ALL[i - 1].to_bits() };
let expected = if v == f8::ZERO {
1 | f8::SIGN_MASK
} else {
f8::ALL[i - 1].to_bits()
};
assert_eq!(down, expected, "{i} next_down({v:#010b})");
}
if i == f8::ALL_LEN - 1 {
assert_eq!(up, f8::INFINITY.to_bits(), "{i} next_up({v:#010b})");
} else {
let expected = if v == f8::NEG_ZERO { 1 } else { f8::ALL[i + 1].to_bits() };
let expected = if v == f8::NEG_ZERO {
1
} else {
f8::ALL[i + 1].to_bits()
};
assert_eq!(up, expected, "{i} next_up({v:#010b})");
}
}
@ -300,8 +318,14 @@ mod tests {
#[test]
fn test_next_up_down_inf_nan() {
assert_eq!(f8::NEG_INFINITY.next_up().to_bits(), f8::ALL[0].to_bits(),);
assert_eq!(f8::NEG_INFINITY.next_down().to_bits(), f8::NEG_INFINITY.to_bits(),);
assert_eq!(f8::INFINITY.next_down().to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits(),);
assert_eq!(
f8::NEG_INFINITY.next_down().to_bits(),
f8::NEG_INFINITY.to_bits(),
);
assert_eq!(
f8::INFINITY.next_down().to_bits(),
f8::ALL[f8::ALL_LEN - 1].to_bits(),
);
assert_eq!(f8::INFINITY.next_up().to_bits(), f8::INFINITY.to_bits(),);
assert_eq!(f8::NAN.next_up().to_bits(), f8::NAN.to_bits(),);
assert_eq!(f8::NAN.next_down().to_bits(), f8::NAN.to_bits(),);
@ -321,7 +345,10 @@ mod tests {
// Check across zero
assert_eq!(f8::from_bits(0b1_0000_111).n_up(8).to_bits(), 0b0_0000_001);
assert_eq!(f8::from_bits(0b0_0000_111).n_down(8).to_bits(), 0b1_0000_001);
assert_eq!(
f8::from_bits(0b0_0000_111).n_down(8).to_bits(),
0b1_0000_001
);
}
#[test]
@ -337,13 +364,25 @@ mod tests {
#[test]
fn test_n_up_down_inf_nan_zero() {
assert_eq!(f8::NEG_INFINITY.n_up(1).to_bits(), f8::ALL[0].to_bits());
assert_eq!(f8::NEG_INFINITY.n_up(239).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits());
assert_eq!(
f8::NEG_INFINITY.n_up(239).to_bits(),
f8::ALL[f8::ALL_LEN - 1].to_bits()
);
assert_eq!(f8::NEG_INFINITY.n_up(240).to_bits(), f8::INFINITY.to_bits());
assert_eq!(f8::NEG_INFINITY.n_down(u8::MAX).to_bits(), f8::NEG_INFINITY.to_bits());
assert_eq!(
f8::NEG_INFINITY.n_down(u8::MAX).to_bits(),
f8::NEG_INFINITY.to_bits()
);
assert_eq!(f8::INFINITY.n_down(1).to_bits(), f8::ALL[f8::ALL_LEN - 1].to_bits());
assert_eq!(
f8::INFINITY.n_down(1).to_bits(),
f8::ALL[f8::ALL_LEN - 1].to_bits()
);
assert_eq!(f8::INFINITY.n_down(239).to_bits(), f8::ALL[0].to_bits());
assert_eq!(f8::INFINITY.n_down(240).to_bits(), f8::NEG_INFINITY.to_bits());
assert_eq!(
f8::INFINITY.n_down(240).to_bits(),
f8::NEG_INFINITY.to_bits()
);
assert_eq!(f8::INFINITY.n_up(u8::MAX).to_bits(), f8::INFINITY.to_bits());
assert_eq!(f8::NAN.n_up(u8::MAX).to_bits(), f8::NAN.to_bits());
@ -381,7 +420,11 @@ mod tests {
assert_eq!(down, expected, "{i} {n} n_down({v:#010b})");
} else {
// Overflow to -inf
assert_eq!(down, f8::NEG_INFINITY.to_bits(), "{i} {n} n_down({v:#010b})");
assert_eq!(
down,
f8::NEG_INFINITY.to_bits(),
"{i} {n} n_down({v:#010b})"
);
}
let mut up_exp_idx = i + n;
@ -438,13 +481,22 @@ mod tests {
#[test]
fn test_ulp_between_inf_nan_zero() {
assert_eq!(ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(), f8::ALL_LEN as u8);
assert_eq!(ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(), f8::ALL_LEN as u8);
assert_eq!(
ulp_between(f8::NEG_INFINITY, f8::INFINITY).unwrap(),
f8::ALL_LEN as u8
);
assert_eq!(
ulp_between(f8::INFINITY, f8::NEG_INFINITY).unwrap(),
f8::ALL_LEN as u8
);
assert_eq!(
ulp_between(f8::NEG_INFINITY, f8::ALL[f8::ALL_LEN - 1]).unwrap(),
f8::ALL_LEN as u8 - 1
);
assert_eq!(ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(), f8::ALL_LEN as u8 - 1);
assert_eq!(
ulp_between(f8::INFINITY, f8::ALL[0]).unwrap(),
f8::ALL_LEN as u8 - 1
);
assert_eq!(ulp_between(f8::ZERO, f8::NEG_ZERO).unwrap(), 0);
assert_eq!(ulp_between(f8::NAN, f8::ZERO), None);
@ -469,7 +521,12 @@ mod tests {
// of steps.
let (ls, count) = logspace(f8::from_bits(0x0), f8::from_bits(0x3), 10);
let ls: Vec<_> = ls.collect();
let exp = [f8::from_bits(0x0), f8::from_bits(0x1), f8::from_bits(0x2), f8::from_bits(0x3)];
let exp = [
f8::from_bits(0x0),
f8::from_bits(0x1),
f8::from_bits(0x2),
f8::from_bits(0x3),
];
assert_eq!(ls, exp);
assert_eq!(ls.len(), usize::from(count));
}

View file

@ -16,7 +16,7 @@
use std::fmt;
use std::panic::{RefUnwindSafe, UnwindSafe};
pub use shared::{FloatTy, MathOpInfo, Ty, ALL_OPERATIONS};
pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty};
use crate::{CheckOutput, Float, TupleCall};

View file

@ -15,7 +15,9 @@ pub const EXTENSIVE_ITER_ENV: &str = "LIBM_EXTENSIVE_ITERATIONS";
/// The override value, if set by the above environment.
static EXTENSIVE_ITER_OVERRIDE: LazyLock<Option<u64>> = LazyLock::new(|| {
env::var(EXTENSIVE_ITER_ENV).map(|v| v.parse().expect("failed to parse iteration count")).ok()
env::var(EXTENSIVE_ITER_ENV)
.map(|v| v.parse().expect("failed to parse iteration count"))
.ok()
});
/// Specific tests that need to have a reduced amount of iterations to complete in a reasonable
@ -115,7 +117,10 @@ static EXTENSIVE: LazyLock<Vec<Identifier>> = LazyLock::new(|| {
let mut ret = Vec::new();
let append_ty_ops = |ret: &mut Vec<_>, fty: FloatTy| {
let iter = Identifier::ALL.iter().filter(move |id| id.math_op().float_ty == fty).copied();
let iter = Identifier::ALL
.iter()
.filter(move |id| id.math_op().float_ty == fty)
.copied();
ret.extend(iter);
};
@ -276,7 +281,10 @@ pub fn iteration_count(ctx: &CheckCtx, argnum: usize) -> u64 {
let seed_msg = match ctx.gen_kind {
GeneratorKind::QuickSpaced | GeneratorKind::Extensive => String::new(),
GeneratorKind::Random => {
format!(" using `{SEED_ENV}={}`", str::from_utf8(SEED.as_slice()).unwrap())
format!(
" using `{SEED_ENV}={}`",
str::from_utf8(SEED.as_slice()).unwrap()
)
}
GeneratorKind::EdgeCases | GeneratorKind::List => unimplemented!(),
};
@ -303,7 +311,10 @@ pub fn int_range(ctx: &CheckCtx, argnum: usize) -> RangeInclusive<i32> {
return i32::MIN..=i32::MAX;
}
assert_eq!(argnum, 0, "For `jn`/`yn`, only the first argument takes an integer");
assert_eq!(
argnum, 0,
"For `jn`/`yn`, only the first argument takes an integer"
);
// The integer argument to `jn` is an iteration count. Limit this to ensure tests can be
// completed in a reasonable amount of time.
@ -331,7 +342,11 @@ pub fn check_point_count(ctx: &CheckCtx) -> usize {
"check_point_count is intended for edge case tests"
);
let t_env = TestEnv::from_env(ctx);
if t_env.slow_platform || !cfg!(optimizations_enabled) { 4 } else { 10 }
if t_env.slow_platform || !cfg!(optimizations_enabled) {
4
} else {
10
}
}
/// When validating points of interest (e.g. asymptotes, inflection points, extremes), also check

View file

@ -328,7 +328,10 @@ where
// Check when both are NaNs
if actual.is_nan() && expected.is_nan() {
if require_biteq && ctx.basis == CheckBasis::None {
ensure!(actual.to_bits() == expected.to_bits(), "mismatched NaN bitpatterns");
ensure!(
actual.to_bits() == expected.to_bits(),
"mismatched NaN bitpatterns"
);
}
// By default, NaNs have nothing special to check.
return Ok(());
@ -340,7 +343,10 @@ where
// Make sure that the signs are the same before checing ULP to avoid wraparound
let act_sig = actual.signum();
let exp_sig = expected.signum();
ensure!(act_sig == exp_sig, "mismatched signs {act_sig:?} {exp_sig:?}");
ensure!(
act_sig == exp_sig,
"mismatched signs {act_sig:?} {exp_sig:?}"
);
if actual.is_infinite() ^ expected.is_infinite() {
bail!("mismatched infinities");

View file

@ -40,7 +40,10 @@ fn from_bigint(bx: &mut BigInt) -> u256 {
let mut bres = [0u128, 0];
bx.write_digits(&mut bres, Order::Lsf);
bx.assign(0);
u256 { lo: bres[0], hi: bres[1] }
u256 {
lo: bres[0],
hi: bres[1],
}
}
fn check_one(
@ -142,6 +145,11 @@ fn mp_u256_widen_mul() {
by.assign(y);
let actual = x.widen_mul(y);
bx *= &by;
check_one(|| format!("{x:#034x}"), || Some(format!("{y:#034x}")), actual, &mut bx);
check_one(
|| format!("{x:#034x}"),
|| Some(format!("{y:#034x}")),
actual,
&mut bx,
);
}
}

View file

@ -28,8 +28,15 @@ pub fn run() {
// With default parallelism, the CPU doesn't saturate. We don't need to be nice to
// other processes, so do 1.5x to make sure we use all available resources.
let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2;
rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap();
let threads = std::thread::available_parallelism()
.map(Into::into)
.unwrap_or(0)
* 3
/ 2;
rayon::ThreadPoolBuilder::new()
.num_threads(threads)
.build_global()
.unwrap();
libtest_mimic::run(&args, tests).exit();
}
@ -134,7 +141,9 @@ where
});
// Run the actual tests
let res = chunks.par_bridge().try_for_each_init(Op::new_mp, test_single_chunk);
let res = chunks
.par_bridge()
.try_for_each_init(Op::new_mp, test_single_chunk);
let real_total = completed.load(Ordering::Relaxed);
pb.complete(real_total);
@ -179,7 +188,12 @@ impl Progress {
let pb = ProgressBar::new(total);
pb.set_style(initial_style);
Self { pb, final_style, name_padded, is_tty }
Self {
pb,
final_style,
name_padded,
is_tty,
}
}
fn update(&self, completed: u64, input: impl fmt::Debug) {

View file

@ -107,9 +107,15 @@ fn emit_cfg_shorthands(cfg: &Config) {
/// Reemit config that we make use of for test logging.
fn emit_cfg_env(cfg: &Config) {
println!("cargo:rustc-env=CFG_CARGO_FEATURES={:?}", cfg.cargo_features);
println!(
"cargo:rustc-env=CFG_CARGO_FEATURES={:?}",
cfg.cargo_features
);
println!("cargo:rustc-env=CFG_OPT_LEVEL={}", cfg.opt_level);
println!("cargo:rustc-env=CFG_TARGET_FEATURES={:?}", cfg.target_features);
println!(
"cargo:rustc-env=CFG_TARGET_FEATURES={:?}",
cfg.target_features
);
}
/// Configure whether or not `f16` and `f128` support should be enabled.

View file

@ -2,7 +2,10 @@
#![no_std]
#![cfg_attr(intrinsics_enabled, allow(internal_features))]
#![cfg_attr(intrinsics_enabled, feature(core_intrinsics))]
#![cfg_attr(all(intrinsics_enabled, target_family = "wasm"), feature(wasm_numeric_instr))]
#![cfg_attr(
all(intrinsics_enabled, target_family = "wasm"),
feature(wasm_numeric_instr)
)]
#![cfg_attr(f128_enabled, feature(f128))]
#![cfg_attr(f16_enabled, feature(f16))]
#![allow(clippy::assign_op_pattern)]

View file

@ -29,8 +29,13 @@ const ATAN_LO: [f32; 4] = [
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
];
const A_T: [f32; 5] =
[3.3333328366e-01, -1.9999158382e-01, 1.4253635705e-01, -1.0648017377e-01, 6.1687607318e-02];
const A_T: [f32; 5] = [
3.3333328366e-01,
-1.9999158382e-01,
1.4253635705e-01,
-1.0648017377e-01,
6.1687607318e-02,
];
/// Arctangent (f32)
///

View file

@ -171,7 +171,11 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult<f64> {
for (a, b) in wlist {
if azz == a {
let tmp = if round as u64 + sign == 2 { hf64!("0x1p-52") } else { 0.0 };
let tmp = if round as u64 + sign == 2 {
hf64!("0x1p-52")
} else {
0.0
};
y1 = (b + tmp).copysign(zz);
}
}

View file

@ -306,5 +306,9 @@ pub fn erfc(x: f64) -> f64 {
}
let x1p_1022 = f64::from_bits(0x0010000000000000);
if sign != 0 { 2.0 - x1p_1022 } else { x1p_1022 * x1p_1022 }
if sign != 0 {
2.0 - x1p_1022
} else {
x1p_1022 * x1p_1022
}
}

View file

@ -218,5 +218,9 @@ pub fn erfcf(x: f32) -> f32 {
}
let x1p_120 = f32::from_bits(0x03800000);
if sign != 0 { 2.0 - x1p_120 } else { x1p_120 * x1p_120 }
if sign != 0 {
2.0 - x1p_120
} else {
x1p_120 * x1p_120
}
}

View file

@ -2,8 +2,9 @@ use super::{exp2, exp2f, modff};
const LN10_F32: f32 = 3.32192809488736234787031942948939;
const LN10_F64: f64 = 3.32192809488736234787031942948939;
const P10: &[f32] =
&[1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7];
const P10: &[f32] = &[
1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
];
/// Calculates 10 raised to the power of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]

View file

@ -126,5 +126,9 @@ pub fn expm1f(mut x: f32) -> f32 {
return y - 1.;
}
let uf = f32::from_bits(((0x7f - k) << 23) as u32); /* 2^-k */
if k < 23 { (x - e + (1. - uf)) * twopk } else { (x - (e + uf) + 1.) * twopk }
if k < 23 {
(x - e + (1. - uf)) * twopk
} else {
(x - (e + uf) + 1.) * twopk
}
}

View file

@ -387,11 +387,17 @@ mod tests {
#[test]
fn fma_sbb() {
assert_eq!(fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN), -3991680619069439e277);
assert_eq!(
fma(-(1.0 - f64::EPSILON), f64::MIN, f64::MIN),
-3991680619069439e277
);
}
#[test]
fn fma_underflow() {
assert_eq!(fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320), 0.0,);
assert_eq!(
fma(1.1102230246251565e-16, -9.812526705433188e-305, 1.0894e-320),
0.0,
);
}
}

View file

@ -75,11 +75,18 @@ where
}
}
return FpResult { val: result.narrow(), status };
return FpResult {
val: result.narrow(),
status,
};
}
let neg = ui >> (B::BITS - 1) != IntTy::<B>::ZERO;
let err = if neg == (zb > xy) { xy - result + zb } else { zb - result + xy };
let err = if neg == (zb > xy) {
xy - result + zb
} else {
zb - result + xy
};
if neg == (err < B::ZERO) {
ui += one;
} else {

View file

@ -75,7 +75,14 @@ mod tests {
/// Test against https://en.cppreference.com/w/cpp/numeric/math/ceil
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY];
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = ceil_status(x);

View file

@ -75,7 +75,14 @@ mod tests {
/// Test against https://en.cppreference.com/w/cpp/numeric/math/floor
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY];
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = floor_status(x);

View file

@ -15,7 +15,11 @@ pub fn rint_round<F: Float>(x: F, _round: Round) -> FpResult<F> {
// On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise,
// the excess precission from x87 would cause an incorrect final result.
let force = |x| {
if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) { force_eval!(x) } else { x }
if cfg!(x86_no_sse) && (F::BITS == 32 || F::BITS == 64) {
force_eval!(x)
} else {
x
}
};
let res = if e >= F::EXP_BIAS + F::SIG_BITS {
@ -47,7 +51,14 @@ mod tests {
use crate::support::{Hexf, Status};
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY];
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = rint_round(x, Round::Nearest);

View file

@ -521,7 +521,10 @@ mod tests {
f128::from_bits(0x400c3880000000000000000000000000),
0x40059000000000000000000000000000_u128,
),
(f128::from_bits(0x0000000f), 0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128),
(
f128::from_bits(0x0000000f),
0x1fc9efbdeb14f4ed9b17ae807907e1e9_u128,
),
(f128::INFINITY, f128::INFINITY.to_bits()),
];

View file

@ -36,7 +36,11 @@ pub fn trunc_status<F: Float>(x: F) -> FpResult<F> {
// C5: Otherwise the result is inexact and we will truncate. Raise `FE_INEXACT`, mask the
// result, and return.
let status = if xi & F::SIG_MASK == F::Int::ZERO { Status::OK } else { Status::INEXACT };
let status = if xi & F::SIG_MASK == F::Int::ZERO {
Status::OK
} else {
Status::INEXACT
};
xi &= mask;
FpResult::new(F::from_bits(xi), status)
}
@ -47,7 +51,14 @@ mod tests {
use crate::support::Hexf;
fn spec_test<F: Float>(cases: &[(F, F, Status)]) {
let roundtrip = [F::ZERO, F::ONE, F::NEG_ONE, F::NEG_ZERO, F::INFINITY, F::NEG_INFINITY];
let roundtrip = [
F::ZERO,
F::ONE,
F::NEG_ONE,
F::NEG_ZERO,
F::INFINITY,
F::NEG_INFINITY,
];
for x in roundtrip {
let FpResult { val, status } = trunc_status(x);

View file

@ -21,7 +21,11 @@ pub fn ilogb(x: f64) -> i32 {
e
} else if e == 0x7ff {
force_eval!(0.0 / 0.0);
if (i << 12) != 0 { FP_ILOGBNAN } else { i32::MAX }
if (i << 12) != 0 {
FP_ILOGBNAN
} else {
i32::MAX
}
} else {
e - 0x3ff
}

View file

@ -49,5 +49,9 @@ pub(crate) fn k_sin(x: f64, y: f64, iy: i32) -> f64 {
let w = z * z;
let r = S2 + z * (S3 + z * S4) + z * w * (S5 + z * S6);
let v = z * x;
if iy == 0 { x + v * (S1 + z * r) } else { x - ((z * (0.5 * y - v * r) - y) - v * S1) }
if iy == 0 {
x + v * (S1 + z * r)
} else {
x - ((z * (0.5 * y - v * r) - y) - v * S1)
}
}

View file

@ -118,7 +118,11 @@ pub fn log1p(x: f64) -> f64 {
k = (hu >> 20) as i32 - 0x3ff;
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
if k < 54 {
c = if k >= 2 { 1. - (f64::from_bits(ui) - x) } else { x - (f64::from_bits(ui) - 1.) };
c = if k >= 2 {
1. - (f64::from_bits(ui) - x)
} else {
x - (f64::from_bits(ui) - 1.)
};
c /= f64::from_bits(ui);
} else {
c = 0.;

View file

@ -73,7 +73,11 @@ pub fn log1pf(x: f32) -> f32 {
k = (iu >> 23) as i32 - 0x7f;
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
if k < 25 {
c = if k >= 2 { 1. - (f32::from_bits(ui) - x) } else { x - (f32::from_bits(ui) - 1.) };
c = if k >= 2 {
1. - (f32::from_bits(ui) - x)
} else {
x - (f32::from_bits(ui) - 1.)
};
c /= f32::from_bits(ui);
} else {
c = 0.;

View file

@ -239,10 +239,18 @@ pub fn pow(x: f64, y: f64) -> f64 {
/* over/underflow if x is not close to one */
if ix < 0x3fefffff {
return if hy < 0 { s * HUGE * HUGE } else { s * TINY * TINY };
return if hy < 0 {
s * HUGE * HUGE
} else {
s * TINY * TINY
};
}
if ix > 0x3ff00000 {
return if hy > 0 { s * HUGE * HUGE } else { s * TINY * TINY };
return if hy > 0 {
s * HUGE * HUGE
} else {
s * TINY * TINY
};
}
/* now |1-x| is TINY <= 2**-20, suffice to compute
@ -439,7 +447,11 @@ mod tests {
fn pow_test(base: f64, exponent: f64, expected: f64) {
let res = pow(base, exponent);
assert!(
if expected.is_nan() { res.is_nan() } else { pow(base, exponent) == expected },
if expected.is_nan() {
res.is_nan()
} else {
pow(base, exponent) == expected
},
"{} ** {} was {} instead of {}",
base,
exponent,
@ -449,11 +461,13 @@ mod tests {
}
fn test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) {
sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected)));
sets.iter()
.for_each(|s| s.iter().for_each(|val| pow_test(*val, exponent, expected)));
}
fn test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) {
sets.iter().for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected)));
sets.iter()
.for_each(|s| s.iter().for_each(|val| pow_test(base, *val, expected)));
}
fn test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) {
@ -467,7 +481,11 @@ mod tests {
#[cfg(all(target_arch = "x86", not(target_feature = "sse2")))]
let res = force_eval!(res);
assert!(
if exp.is_nan() { res.is_nan() } else { exp == res },
if exp.is_nan() {
res.is_nan()
} else {
exp == res
},
"test for {} was {} instead of {}",
val,
res,
@ -515,7 +533,9 @@ mod tests {
// (-Infinity ^ anything but odd ints should be == -0 ^ (-anything))
// We can lump in pos/neg odd ints here because they don't seem to
// cause panics (div by zero) in release mode (I think).
test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| pow(-0.0, -v));
test_sets(ALL, &|v: f64| pow(f64::NEG_INFINITY, v), &|v: f64| {
pow(-0.0, -v)
});
}
#[test]
@ -582,11 +602,15 @@ mod tests {
// Factoring -1 out:
// (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer))
[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| {
int_set.iter().for_each(|int| {
test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| pow(-1.0, *int) * pow(v, *int));
})
});
[POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS]
.iter()
.for_each(|int_set| {
int_set.iter().for_each(|int| {
test_sets(ALL, &|v: f64| pow(-v, *int), &|v: f64| {
pow(-1.0, *int) * pow(v, *int)
});
})
});
// Negative base (imaginary results):
// (-anything except 0 and Infinity ^ non-integer should be NAN)

View file

@ -182,11 +182,19 @@ pub fn powf(x: f32, y: f32) -> f32 {
/* if |y| > 2**27 */
/* over/underflow if x is not close to one */
if ix < 0x3f7ffff8 {
return if hy < 0 { sn * HUGE * HUGE } else { sn * TINY * TINY };
return if hy < 0 {
sn * HUGE * HUGE
} else {
sn * TINY * TINY
};
}
if ix > 0x3f800007 {
return if hy > 0 { sn * HUGE * HUGE } else { sn * TINY * TINY };
return if hy > 0 {
sn * HUGE * HUGE
} else {
sn * TINY * TINY
};
}
/* now |1-x| is TINY <= 2**-20, suffice to compute

View file

@ -199,16 +199,28 @@ mod tests {
fn test_near_pi() {
let arg = 3.141592025756836;
let arg = force_eval!(arg);
assert_eq!(rem_pio2(arg), (2, -6.278329573009626e-7, -2.1125998133974653e-23));
assert_eq!(
rem_pio2(arg),
(2, -6.278329573009626e-7, -2.1125998133974653e-23)
);
let arg = 3.141592033207416;
let arg = force_eval!(arg);
assert_eq!(rem_pio2(arg), (2, -6.20382377148128e-7, -2.1125998133974653e-23));
assert_eq!(
rem_pio2(arg),
(2, -6.20382377148128e-7, -2.1125998133974653e-23)
);
let arg = 3.141592144966125;
let arg = force_eval!(arg);
assert_eq!(rem_pio2(arg), (2, -5.086236681942706e-7, -2.1125998133974653e-23));
assert_eq!(
rem_pio2(arg),
(2, -5.086236681942706e-7, -2.1125998133974653e-23)
);
let arg = 3.141592979431152;
let arg = force_eval!(arg);
assert_eq!(rem_pio2(arg), (2, 3.2584135866119817e-7, -2.1125998133974653e-23));
assert_eq!(
rem_pio2(arg),
(2, 3.2584135866119817e-7, -2.1125998133974653e-23)
);
}
#[test]

View file

@ -42,7 +42,11 @@ pub fn sinf(x: f32) -> f32 {
if ix < 0x39800000 {
/* |x| < 2**-12 */
/* raise inexact if x!=0 and underflow if subnormal */
force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 });
force_eval!(if ix < 0x00800000 {
x / x1p120
} else {
x + x1p120
});
return x;
}
return k_sinf(x64);
@ -57,7 +61,11 @@ pub fn sinf(x: f32) -> f32 {
return k_cosf(x64 - S1_PIO2);
}
}
return k_sinf(if sign { -(x64 + S2_PIO2) } else { -(x64 - S2_PIO2) });
return k_sinf(if sign {
-(x64 + S2_PIO2)
} else {
-(x64 - S2_PIO2)
});
}
if ix <= 0x40e231d5 {
/* |x| ~<= 9*pi/4 */

View file

@ -19,11 +19,17 @@ pub struct u256 {
impl u256 {
#[cfg(any(test, feature = "unstable-public-internals"))]
pub const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX };
pub const MAX: Self = Self {
lo: u128::MAX,
hi: u128::MAX,
};
/// Reinterpret as a signed integer
pub fn signed(self) -> i256 {
i256 { lo: self.lo, hi: self.hi }
i256 {
lo: self.lo,
hi: self.hi,
}
}
}
@ -39,7 +45,10 @@ impl i256 {
/// Reinterpret as an unsigned integer
#[cfg(any(test, feature = "unstable-public-internals"))]
pub fn unsigned(self) -> u256 {
u256 { lo: self.lo, hi: self.hi }
u256 {
lo: self.lo,
hi: self.hi,
}
}
}
@ -53,7 +62,10 @@ impl MinInt for u256 {
const ZERO: Self = Self { lo: 0, hi: 0 };
const ONE: Self = Self { lo: 1, hi: 0 };
const MIN: Self = Self { lo: 0, hi: 0 };
const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX };
const MAX: Self = Self {
lo: u128::MAX,
hi: u128::MAX,
};
}
impl MinInt for i256 {
@ -65,8 +77,14 @@ impl MinInt for i256 {
const BITS: u32 = 256;
const ZERO: Self = Self { lo: 0, hi: 0 };
const ONE: Self = Self { lo: 1, hi: 0 };
const MIN: Self = Self { lo: 0, hi: 1 << 127 };
const MAX: Self = Self { lo: u128::MAX, hi: u128::MAX << 1 };
const MIN: Self = Self {
lo: 0,
hi: 1 << 127,
};
const MAX: Self = Self {
lo: u128::MAX,
hi: u128::MAX << 1,
};
}
macro_rules! impl_common {

View file

@ -13,23 +13,62 @@ fn hexu(v: u256) -> String {
#[test]
fn widen_u128() {
assert_eq!(u128::MAX.widen(), u256 { lo: u128::MAX, hi: 0 });
assert_eq!(LOHI_SPLIT.widen(), u256 { lo: LOHI_SPLIT, hi: 0 });
assert_eq!(
u128::MAX.widen(),
u256 {
lo: u128::MAX,
hi: 0
}
);
assert_eq!(
LOHI_SPLIT.widen(),
u256 {
lo: LOHI_SPLIT,
hi: 0
}
);
}
#[test]
fn widen_i128() {
assert_eq!((-1i128).widen(), u256::MAX.signed());
assert_eq!((LOHI_SPLIT as i128).widen(), i256 { lo: LOHI_SPLIT, hi: u128::MAX });
assert_eq!(
(LOHI_SPLIT as i128).widen(),
i256 {
lo: LOHI_SPLIT,
hi: u128::MAX
}
);
assert_eq!((-1i128).zero_widen().unsigned(), (u128::MAX).widen());
}
#[test]
fn widen_mul_u128() {
let tests = [
(u128::MAX / 2, 2_u128, u256 { lo: u128::MAX - 1, hi: 0 }),
(u128::MAX, 2_u128, u256 { lo: u128::MAX - 1, hi: 1 }),
(u128::MAX, u128::MAX, u256 { lo: 1, hi: u128::MAX - 1 }),
(
u128::MAX / 2,
2_u128,
u256 {
lo: u128::MAX - 1,
hi: 0,
},
),
(
u128::MAX,
2_u128,
u256 {
lo: u128::MAX - 1,
hi: 1,
},
),
(
u128::MAX,
u128::MAX,
u256 {
lo: 1,
hi: u128::MAX - 1,
},
),
(0, 0, u256::ZERO),
(1234u128, 0, u256::ZERO),
(0, 1234, u256::ZERO),
@ -68,7 +107,13 @@ fn not_u256() {
#[test]
fn shr_u256() {
let only_low = [1, u16::MAX.into(), u32::MAX.into(), u64::MAX.into(), u128::MAX];
let only_low = [
1,
u16::MAX.into(),
u32::MAX.into(),
u64::MAX.into(),
u128::MAX,
];
let mut has_errors = false;
let mut add_error = |a, b, expected, actual| {
@ -99,23 +144,106 @@ fn shr_u256() {
}
let check = [
(u256::MAX, 1, u256 { lo: u128::MAX, hi: u128::MAX >> 1 }),
(u256::MAX, 5, u256 { lo: u128::MAX, hi: u128::MAX >> 5 }),
(u256::MAX, 63, u256 { lo: u128::MAX, hi: u64::MAX as u128 | (1 << 64) }),
(u256::MAX, 64, u256 { lo: u128::MAX, hi: u64::MAX as u128 }),
(u256::MAX, 65, u256 { lo: u128::MAX, hi: (u64::MAX >> 1) as u128 }),
(u256::MAX, 127, u256 { lo: u128::MAX, hi: 1 }),
(u256::MAX, 128, u256 { lo: u128::MAX, hi: 0 }),
(u256::MAX, 129, u256 { lo: u128::MAX >> 1, hi: 0 }),
(u256::MAX, 191, u256 { lo: u64::MAX as u128 | 1 << 64, hi: 0 }),
(u256::MAX, 192, u256 { lo: u64::MAX as u128, hi: 0 }),
(u256::MAX, 193, u256 { lo: u64::MAX as u128 >> 1, hi: 0 }),
(
u256::MAX,
1,
u256 {
lo: u128::MAX,
hi: u128::MAX >> 1,
},
),
(
u256::MAX,
5,
u256 {
lo: u128::MAX,
hi: u128::MAX >> 5,
},
),
(
u256::MAX,
63,
u256 {
lo: u128::MAX,
hi: u64::MAX as u128 | (1 << 64),
},
),
(
u256::MAX,
64,
u256 {
lo: u128::MAX,
hi: u64::MAX as u128,
},
),
(
u256::MAX,
65,
u256 {
lo: u128::MAX,
hi: (u64::MAX >> 1) as u128,
},
),
(
u256::MAX,
127,
u256 {
lo: u128::MAX,
hi: 1,
},
),
(
u256::MAX,
128,
u256 {
lo: u128::MAX,
hi: 0,
},
),
(
u256::MAX,
129,
u256 {
lo: u128::MAX >> 1,
hi: 0,
},
),
(
u256::MAX,
191,
u256 {
lo: u64::MAX as u128 | 1 << 64,
hi: 0,
},
),
(
u256::MAX,
192,
u256 {
lo: u64::MAX as u128,
hi: 0,
},
),
(
u256::MAX,
193,
u256 {
lo: u64::MAX as u128 >> 1,
hi: 0,
},
),
(u256::MAX, 254, u256 { lo: 0b11, hi: 0 }),
(u256::MAX, 255, u256 { lo: 1, hi: 0 }),
(
u256 { hi: LOHI_SPLIT, lo: 0 },
u256 {
hi: LOHI_SPLIT,
lo: 0,
},
64,
u256 { lo: 0xffffffffffffffff0000000000000000, hi: 0xaaaaaaaaaaaaaaaa },
u256 {
lo: 0xffffffffffffffff0000000000000000,
hi: 0xaaaaaaaaaaaaaaaa,
},
),
];

View file

@ -25,7 +25,10 @@ impl<T> FpResult<T> {
/// Return `val` with `Status::OK`.
pub fn ok(val: T) -> Self {
Self { val, status: Status::OK }
Self {
val,
status: Status::OK,
}
}
}

View file

@ -105,7 +105,11 @@ pub trait Float:
/// if `NaN` should not be treated separately.
#[allow(dead_code)]
fn eq_repr(self, rhs: Self) -> bool {
if self.is_nan() && rhs.is_nan() { true } else { self.biteq(rhs) }
if self.is_nan() && rhs.is_nan() {
true
} else {
self.biteq(rhs)
}
}
/// Returns true if the value is NaN.
@ -149,7 +153,11 @@ pub trait Float:
/// Constructs a `Self` from its parts. Inputs are treated as bits and shifted into position.
fn from_parts(negative: bool, exponent: u32, significand: Self::Int) -> Self {
let sign = if negative { Self::Int::ONE } else { Self::Int::ZERO };
let sign = if negative {
Self::Int::ONE
} else {
Self::Int::ZERO
};
Self::from_bits(
(sign << (Self::BITS - 1))
| (Self::Int::cast_from(exponent & Self::EXP_SAT) << Self::SIG_BITS)
@ -173,7 +181,11 @@ pub trait Float:
/// Returns a number that represents the sign of self.
#[allow(dead_code)]
fn signum(self) -> Self {
if self.is_nan() { self } else { Self::ONE.copysign(self) }
if self.is_nan() {
self
} else {
Self::ONE.copysign(self)
}
}
}
@ -273,18 +285,61 @@ macro_rules! float_impl {
}
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
let shift = significand.leading_zeros().wrapping_sub(Self::EXP_BITS);
(1i32.wrapping_sub(shift as i32), significand << shift as Self::Int)
(
1i32.wrapping_sub(shift as i32),
significand << shift as Self::Int,
)
}
}
};
}
#[cfg(f16_enabled)]
float_impl!(f16, u16, i16, 16, 10, f16::from_bits, f16::to_bits, fmaf16, fmaf16);
float_impl!(f32, u32, i32, 32, 23, f32_from_bits, f32_to_bits, fmaf, fmaf32);
float_impl!(f64, u64, i64, 64, 52, f64_from_bits, f64_to_bits, fma, fmaf64);
float_impl!(
f16,
u16,
i16,
16,
10,
f16::from_bits,
f16::to_bits,
fmaf16,
fmaf16
);
float_impl!(
f32,
u32,
i32,
32,
23,
f32_from_bits,
f32_to_bits,
fmaf,
fmaf32
);
float_impl!(
f64,
u64,
i64,
64,
52,
f64_from_bits,
f64_to_bits,
fma,
fmaf64
);
#[cfg(f128_enabled)]
float_impl!(f128, u128, i128, 128, 112, f128::from_bits, f128::to_bits, fmaf128, fmaf128);
float_impl!(
f128,
u128,
i128,
128,
112,
f128::from_bits,
f128::to_bits,
fmaf128,
fmaf128
);
/* FIXME(msrv): vendor some things that are not const stable at our MSRV */
@ -424,7 +479,10 @@ mod tests {
// `from_parts`
assert_biteq!(f32::from_parts(true, f32::EXP_BIAS, 0), -1.0f32);
assert_biteq!(f32::from_parts(false, 10 + f32::EXP_BIAS, 0), hf32!("0x1p10"));
assert_biteq!(
f32::from_parts(false, 10 + f32::EXP_BIAS, 0),
hf32!("0x1p10")
);
assert_biteq!(f32::from_parts(false, 0, 1), f32::from_bits(0x1));
}
@ -451,7 +509,10 @@ mod tests {
// `from_parts`
assert_biteq!(f64::from_parts(true, f64::EXP_BIAS, 0), -1.0f64);
assert_biteq!(f64::from_parts(false, 10 + f64::EXP_BIAS, 0), hf64!("0x1p10"));
assert_biteq!(
f64::from_parts(false, 10 + f64::EXP_BIAS, 0),
hf64!("0x1p10")
);
assert_biteq!(f64::from_parts(false, 0, 1), f64::from_bits(0x1));
}

View file

@ -234,7 +234,9 @@ const fn parse_hex(mut b: &[u8]) -> Result<Parsed, HexFloatParseError> {
match c {
b'.' => {
if seen_point {
return Err(HexFloatParseError("unexpected '.' parsing fractional digits"));
return Err(HexFloatParseError(
"unexpected '.' parsing fractional digits",
));
}
seen_point = true;
continue;
@ -294,7 +296,9 @@ const fn parse_hex(mut b: &[u8]) -> Result<Parsed, HexFloatParseError> {
}
if !some_digits {
return Err(HexFloatParseError("at least one exponent digit is required"));
return Err(HexFloatParseError(
"at least one exponent digit is required",
));
};
{
@ -542,7 +546,11 @@ mod parse_tests {
for k in -149..=127 {
let s = format!("0x1p{k}");
let x = hf32(&s);
let y = if k < 0 { 0.5f32.powi(-k) } else { 2.0f32.powi(k) };
let y = if k < 0 {
0.5f32.powi(-k)
} else {
2.0f32.powi(k)
};
assert_eq!(x, y);
}
@ -613,9 +621,14 @@ mod parse_tests {
fn rounding_extreme_underflow() {
for k in 1..1000 {
let s = format!("0x1p{}", -149 - k);
let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() };
let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else {
unreachable!()
};
assert_eq!(bits, 0, "{s} should round to zero, got bits={bits}");
assert!(status.underflow(), "should indicate underflow when parsing {s}");
assert!(
status.underflow(),
"should indicate underflow when parsing {s}"
);
assert!(status.inexact(), "should indicate inexact when parsing {s}");
}
}
@ -623,11 +636,15 @@ mod parse_tests {
fn long_tail() {
for k in 1..1000 {
let s = format!("0x1.{}p0", "0".repeat(k));
let Ok(bits) = parse_hex_exact(&s, 32, 23) else { panic!("parsing {s} failed") };
let Ok(bits) = parse_hex_exact(&s, 32, 23) else {
panic!("parsing {s} failed")
};
assert_eq!(f32::from_bits(bits as u32), 1.0);
let s = format!("0x1.{}1p0", "0".repeat(k));
let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else { unreachable!() };
let Ok((bits, status)) = parse_any(&s, 32, 23, Round::Nearest) else {
unreachable!()
};
if status.inexact() {
assert!(1.0 == f32::from_bits(bits as u32));
} else {
@ -839,7 +856,10 @@ mod parse_tests {
assert_eq!(hf32!("0x1.ffep+8").to_bits(), 0x43fff000_u32);
assert_eq!(hf64!("0x1.ffep+8").to_bits(), 0x407ffe0000000000_u64);
#[cfg(f128_enabled)]
assert_eq!(hf128!("0x1.ffep+8").to_bits(), 0x4007ffe0000000000000000000000000_u128);
assert_eq!(
hf128!("0x1.ffep+8").to_bits(),
0x4007ffe0000000000000000000000000_u128
);
}
}
@ -1143,8 +1163,14 @@ mod print_tests {
#[cfg(f128_enabled)]
{
assert_eq!(Hexf(f128::MAX).to_string(), "0x1.ffffffffffffffffffffffffffffp+16383");
assert_eq!(Hexf(f128::MIN).to_string(), "-0x1.ffffffffffffffffffffffffffffp+16383");
assert_eq!(
Hexf(f128::MAX).to_string(),
"0x1.ffffffffffffffffffffffffffffp+16383"
);
assert_eq!(
Hexf(f128::MIN).to_string(),
"-0x1.ffffffffffffffffffffffffffffp+16383"
);
assert_eq!(Hexf(f128::ZERO).to_string(), "0x0p+0");
assert_eq!(Hexf(f128::NEG_ZERO).to_string(), "-0x0p+0");
assert_eq!(Hexf(f128::NAN).to_string(), "NaN");

View file

@ -53,7 +53,11 @@ pub fn tan(x: f64) -> f64 {
if ix < 0x3e400000 {
/* |x| < 2**-27 */
/* raise inexact if x!=0 and underflow if subnormal */
force_eval!(if ix < 0x00100000 { x / x1p120 as f64 } else { x + x1p120 as f64 });
force_eval!(if ix < 0x00100000 {
x / x1p120 as f64
} else {
x + x1p120 as f64
});
return x;
}
return k_tan(x, 0.0, 0);

View file

@ -42,7 +42,11 @@ pub fn tanf(x: f32) -> f32 {
if ix < 0x39800000 {
/* |x| < 2**-12 */
/* raise inexact if x!=0 and underflow if subnormal */
force_eval!(if ix < 0x00800000 { x / x1p120 } else { x + x1p120 });
force_eval!(if ix < 0x00800000 {
x / x1p120
} else {
x + x1p120
});
return x;
}
return k_tanf(x64, false);