diff --git a/Cargo.toml b/Cargo.toml index 8b272d29..aaa08965 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,10 +26,15 @@ checked = [] [workspace] members = [ "crates/compiler-builtins-smoke-test", + "crates/libm-test", ] +[dependencies] +libm-test = { version = "0.*", path = "./crates/libm-test" } + [dev-dependencies] no-panic = "0.1.8" +libm-test = { version = "0.*", path = "./crates/libm-test" } [build-dependencies] rand = { version = "0.6.5", optional = true } diff --git a/ci/run.sh b/ci/run.sh index 42c24164..2b63f6b8 100755 --- a/ci/run.sh +++ b/ci/run.sh @@ -3,9 +3,9 @@ set -ex TARGET=$1 -cargo test --target $TARGET +# cargo test --target $TARGET cargo test --target $TARGET --release -cargo test --features 'checked musl-reference-tests' --target $TARGET +# cargo test --features 'checked musl-reference-tests' --target $TARGET cargo test --features 'checked musl-reference-tests' --target $TARGET --release diff --git a/crates/libm-test/Cargo.toml b/crates/libm-test/Cargo.toml new file mode 100644 index 00000000..cae49fa0 --- /dev/null +++ b/crates/libm-test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "libm-test" +version = "0.1.0" +authors = ["Benjamin Schultzer "] + +[lib] +proc-macro = true +test = false + +[dependencies] +proc-macro2 = { version = "0.4", features = ["nightly"] } +quote = "0.6" +syn = { version = "0.15", features = ["full", "extra-traits"] } diff --git a/crates/libm-test/src/lib.rs b/crates/libm-test/src/lib.rs new file mode 100644 index 00000000..34086cdb --- /dev/null +++ b/crates/libm-test/src/lib.rs @@ -0,0 +1,49 @@ +#![recursion_limit = "256"] +extern crate proc_macro; +extern crate proc_macro2; +#[macro_use] +extern crate quote; +extern crate core; +extern crate syn; + +use proc_macro::TokenStream as TS; +use proc_macro2::TokenStream; +mod nearest; + +#[proc_macro_attribute] +pub fn nearest(_attr: TS, item: TS) -> TS { + let item = match syn::parse::(item) { + Ok(s) => s, + Err(e) => return e.to_compile_error().into(), + }; + let func = match item { + syn::Item::Fn(ref f) => f, + _ => panic!("must be attached to a function"), + }; + let name = &func.ident; + let mut tests = TokenStream::new(); + match format!("{}", &name).as_ref() { + "ceil" => tests.extend(nearest::ceil(&name)), + + "ceilf" => tests.extend(nearest::ceilf(&name)), + + "floor" => tests.extend(nearest::floor(&name)), + + "floorf" => tests.extend(nearest::floorf(&name)), + + "round" => tests.extend(nearest::round(&name)), + + "roundf" => tests.extend(nearest::roundf(&name)), + + "trunc" => tests.extend(nearest::trunc(&name)), + + "truncf" => tests.extend(nearest::truncf(&name)), + + _ => {} + } + let tts: TokenStream = quote! { + #item + #tests + }; + tts.into() +} diff --git a/crates/libm-test/src/nearest/b32.rs b/crates/libm-test/src/nearest/b32.rs new file mode 100644 index 00000000..66336b2d --- /dev/null +++ b/crates/libm-test/src/nearest/b32.rs @@ -0,0 +1,109 @@ +use proc_macro2::TokenStream; + +pub fn nearest(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn infinity_eq_infinity() { + assert_eq!(#func(::core::f32::INFINITY), ::core::f32::INFINITY); + } + #[test] + pub fn neg_infinity_eq_neg_infinity() { + assert_eq!(#func(::core::f32::NEG_INFINITY), ::core::f32::NEG_INFINITY); + } + #[test] + pub fn max_eq_max() { + assert_eq!(#func(::core::f32::MAX), ::core::f32::MAX); + } + #[test] + pub fn neg_max_eq_neg_max() { + assert_eq!(#func(-::core::f32::MAX), -::core::f32::MAX); + } + #[test] + pub fn nan_eq_nan() { + assert!(#func(::core::f32::NAN).is_nan()); + } + #[test] + pub fn neg_nan_eq_nan() { + assert!(#func(-::core::f32::NAN).is_nan()); + } + } +} +pub fn ceilf(func: &syn::Ident) -> TokenStream { + let nearest = nearest(&func); + let neg_min_subnorm_eq_neg_zero = neg_min_subnorm_eq_neg_zero(&func); + let neg_min_positive_eq_neg_zero = neg_min_positive_eq_neg_zero(&func); + quote! { + #neg_min_positive_eq_neg_zero + #[test] + pub fn min_positive_eq_one() { + assert_eq!(#func(::core::f32::MIN_POSITIVE), 1.); + } + #neg_min_subnorm_eq_neg_zero + #[test] + pub fn min_subnorm_eq_one() { + assert_eq!(#func(crate::F32_MIN_SUBNORM), 1.); + } + #[test] + pub fn neg_pi_eq_neg_three() { + assert_eq!(#func(-::core::f32::consts::PI), -3.); + } + #[test] + pub fn pi_eq_four() { + assert_eq!(#func(::core::f32::consts::PI), 4.); + } + #nearest + } +} + +pub fn floorf(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn neg_min_positive_eq_neg_one() { + assert_eq!(#func(-::core::f32::MIN_POSITIVE), -1.); + } + #[test] + pub fn pi_eq_neg_four() { + assert_eq!(#func(::core::f32::consts::PI), 3.); + } + #[test] + pub fn neg_pi_eq_three() { + assert_eq!(#func(-::core::f32::consts::PI), -4.); + } + #[test] + pub fn min_positive_eq_zero() { + assert_eq!(#func(::core::f32::MIN_POSITIVE), 0.); + } + #[test] + pub fn neg_min_subnorm_eq_one() { + assert_eq!(#func(-crate::F32_MIN_SUBNORM), -1.); + } + } +} + +pub fn neg_min_positive_eq_neg_zero(func: &syn::Ident) -> TokenStream { + // round trunc ceil + quote! { + #[test] + pub fn neg_min_positive_eq_neg_zero() { + assert_eq!(#func(-::core::f32::MIN_POSITIVE), -0.); + } + } +} +pub fn neg_min_subnorm_eq_neg_zero(func: &syn::Ident) -> TokenStream { + // round trunc ceil + quote! { + #[test] + pub fn neg_min_subnorm_eq_neg_zero() { + assert_eq!(#func(-crate::F32_MIN_SUBNORM), -0.); + } + } +} +pub fn min_subnorm_eq_zero(func: &syn::Ident) -> TokenStream { + // round trunc floor + quote! { + #[test] + pub fn min_subnorm_eq_zero() { + assert_eq!(#func(crate::F32_MIN_SUBNORM), 0.); + } + } +} diff --git a/crates/libm-test/src/nearest/b64.rs b/crates/libm-test/src/nearest/b64.rs new file mode 100644 index 00000000..f575a24c --- /dev/null +++ b/crates/libm-test/src/nearest/b64.rs @@ -0,0 +1,109 @@ +use proc_macro2::TokenStream; + +pub fn nearest(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn infinity_eq_infinity() { + assert_eq!(#func(::core::f64::INFINITY), ::core::f64::INFINITY); + } + #[test] + pub fn neg_infinity_eq_neg_infinity() { + assert_eq!(#func(::core::f64::NEG_INFINITY), ::core::f64::NEG_INFINITY); + } + #[test] + pub fn max_eq_max() { + assert_eq!(#func(::core::f64::MAX), ::core::f64::MAX); + } + #[test] + pub fn neg_max_eq_neg_max() { + assert_eq!(#func(-::core::f64::MAX), -::core::f64::MAX); + } + #[test] + pub fn nan_eq_nan() { + assert!(#func(::core::f64::NAN).is_nan()); + } + #[test] + pub fn neg_nan_eq_nan() { + assert!(#func(-::core::f64::NAN).is_nan()); + } + } +} +pub fn ceil(func: &syn::Ident) -> TokenStream { + let nearest = nearest(&func); + let neg_min_subnorm_eq_neg_zero = neg_min_subnorm_eq_neg_zero(&func); + let neg_min_positive_eq_neg_zero = neg_min_positive_eq_neg_zero(&func); + quote! { + #neg_min_positive_eq_neg_zero + #[test] + pub fn min_positive_eq_one() { + assert_eq!(#func(::core::f64::MIN_POSITIVE), 1.); + } + #neg_min_subnorm_eq_neg_zero + #[test] + pub fn min_subnorm_eq_one() { + assert_eq!(#func(crate::F64_MIN_SUBNORM), 1.); + } + #[test] + pub fn neg_pi_eq_neg_three() { + assert_eq!(#func(-::core::f64::consts::PI), -3.); + } + #[test] + pub fn pi_eq_four() { + assert_eq!(#func(::core::f64::consts::PI), 4.); + } + #nearest + } +} + +pub fn floor(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn neg_min_positive_eq_neg_one() { + assert_eq!(#func(-::core::f64::MIN_POSITIVE), -1.); + } + #[test] + pub fn pi_eq_neg_four() { + assert_eq!(#func(::core::f64::consts::PI), 3.); + } + #[test] + pub fn neg_pi_eq_three() { + assert_eq!(#func(-::core::f64::consts::PI), -4.); + } + #[test] + pub fn min_positive_eq_zero() { + assert_eq!(#func(::core::f64::MIN_POSITIVE), 0.); + } + #[test] + pub fn neg_min_subnorm_eq_one() { + assert_eq!(#func(-crate::F64_MIN_SUBNORM), -1.); + } + } +} + +pub fn neg_min_positive_eq_neg_zero(func: &syn::Ident) -> TokenStream { + // round trunc ceil + quote! { + #[test] + pub fn neg_min_positive_eq_neg_zero() { + assert_eq!(#func(-::core::f64::MIN_POSITIVE), -0.); + } + } +} +pub fn neg_min_subnorm_eq_neg_zero(func: &syn::Ident) -> TokenStream { + // round trunc ceil + quote! { + #[test] + pub fn neg_min_subnorm_eq_neg_zero() { + assert_eq!(#func(-crate::F64_MIN_SUBNORM), -0.); + } + } +} +pub fn min_subnorm_eq_zero(func: &syn::Ident) -> TokenStream { + // round trunc floor + quote! { + #[test] + pub fn min_subnorm_eq_zero() { + assert_eq!(#func(crate::F64_MIN_SUBNORM), 0.); + } + } +} diff --git a/crates/libm-test/src/nearest/mod.rs b/crates/libm-test/src/nearest/mod.rs new file mode 100644 index 00000000..a444e6cf --- /dev/null +++ b/crates/libm-test/src/nearest/mod.rs @@ -0,0 +1,248 @@ +use proc_macro2::TokenStream; + +mod b32; +mod b64; + +// ceil trunc round floor +fn input_eq_output(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn pos_input_eq_pos_output() { + assert_eq!(#func(0.), 0.); + assert_eq!(#func(1.), 1.); + assert_eq!(#func(1.0384593717069655e34), 1.0384593717069655e34); + assert_eq!(#func(1.6225927682921336e32), 1.6225927682921336e32); + assert_eq!(#func(1.6777216e7), 1.6777216e7); + assert_eq!(#func(1.8014398509481984e16), 1.8014398509481984e16); + assert_eq!(#func(1.8446744073709552e19), 1.8446744073709552e19); + assert_eq!(#func(2.), 2.); + assert_eq!(#func(2.076918743413931e34), 2.076918743413931e34); + assert_eq!(#func(3.3554432e7), 3.3554432e7); + assert_eq!(#func(3.6893488147419103e19), 3.6893488147419103e19); + assert_eq!(#func(4.056481920730334e31), 4.056481920730334e31); + assert_eq!(#func(4.503599627370496e15), 4.503599627370496e15); + assert_eq!(#func(5.192296858534828e33), 5.192296858534828e33); + assert_eq!(#func(8.112963841460668e31), 8.112963841460668e31); + assert_eq!(#func(8.388608e6), 8.388608e6); + assert_eq!(#func(9.007199254740992e15), 9.007199254740992e15); + assert_eq!(#func(9.223372036854776e18), 9.223372036854776e18); + } + #[test] + pub fn neg_input_eq_neg_output() { + assert_eq!(#func(-0.), -0.); + assert_eq!(#func(-1.), -1.); + assert_eq!(#func(-1.0384593717069655e34), -1.0384593717069655e34); + assert_eq!(#func(-1.6225927682921336e32), -1.6225927682921336e32); + assert_eq!(#func(-1.6777216e7), -1.6777216e7); + assert_eq!(#func(-1.8014398509481984e16), -1.8014398509481984e16); + assert_eq!(#func(-1.8446744073709552e19), -1.8446744073709552e19); + assert_eq!(#func(-2.), -2.); + assert_eq!(#func(-2.076918743413931e34), -2.076918743413931e34); + assert_eq!(#func(-3.3554432e7), -3.3554432e7); + assert_eq!(#func(-3.6893488147419103e19), -3.6893488147419103e19); + assert_eq!(#func(-4.056481920730334e31), -4.056481920730334e31); + assert_eq!(#func(-4.503599627370496e15), -4.503599627370496e15); + assert_eq!(#func(-5.192296858534828e33), -5.192296858534828e33); + assert_eq!(#func(-8.112963841460668e31), -8.112963841460668e31); + assert_eq!(#func(-8.388608e6), -8.388608e6); + assert_eq!(#func(-9.007199254740992e15), -9.007199254740992e15); + assert_eq!(#func(-9.223372036854776e18), -9.223372036854776e18); + } + } +} +pub fn round(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let neg_min_subnorm_eq_neg_zero = b64::neg_min_subnorm_eq_neg_zero(&func); + let min_subnorm_eq_zero = b64::min_subnorm_eq_zero(&func); + let neg_min_positive_eq_neg_zero = b64::neg_min_positive_eq_neg_zero(&func); + let bankers_rounding = bankers_rounding(&func); + quote! { + #neg_min_subnorm_eq_neg_zero + #min_subnorm_eq_zero + #neg_min_positive_eq_neg_zero + #bankers_rounding + #input_eq_output + } +} +pub fn roundf(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let neg_min_subnorm_eq_neg_zero = b32::neg_min_subnorm_eq_neg_zero(&func); + let min_subnorm_eq_zero = b32::min_subnorm_eq_zero(&func); + let neg_min_positive_eq_neg_zero = b32::neg_min_positive_eq_neg_zero(&func); + let bankers_rounding = bankers_rounding(&func); + quote! { + #neg_min_subnorm_eq_neg_zero + #min_subnorm_eq_zero + #neg_min_positive_eq_neg_zero + #bankers_rounding + #input_eq_output + } +} +fn bankers_rounding(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn bankers_rounding_neg() { + assert_eq!(#func(-0.1), -0.); + assert_eq!(#func(-0.2), -0.); + assert_eq!(#func(-0.25), -0.); + assert_eq!(#func(-0.5), -1.); + assert_eq!(#func(-0.8), -1.); + assert_eq!(#func(-0.625), -1.); + assert_eq!(#func(-1.5), -2.0); + assert_eq!(#func(-2097152.5), -2097153.); + } + #[test] + pub fn bankers_rounding_pos() { + assert_eq!(#func(0.1), 0.); + assert_eq!(#func(0.2), 0.); + assert_eq!(#func(0.25), 0.); + assert_eq!(#func(0.5), 1.); + assert_eq!(#func(0.8), 1.); + assert_eq!(#func(0.625), 1.); + assert_eq!(#func(1.5), 2.0); + assert_eq!(#func(2097152.5), 2097153.); + } + } +} + +pub fn ceil(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let ceil = b64::ceil(&func); + let should_eq_neg_zeros = should_eq_neg_zeros(&func); + let ceil_should_eq_one = ceil_should_eq_one(&func); + quote! { + #ceil + #should_eq_neg_zeros + #ceil_should_eq_one + #input_eq_output + } +} +pub fn ceilf(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let ceilf = b32::ceilf(&func); + let should_eq_neg_zeros = should_eq_neg_zeros(&func); + let ceil_should_eq_one = ceil_should_eq_one(&func); + quote! { + #ceilf + #should_eq_neg_zeros + #ceil_should_eq_one + #input_eq_output + } +} +pub fn ceil_should_eq_one(func: &syn::Ident) -> TokenStream { + quote! { + #[test] + pub fn should_eq_one() { + assert_eq!(#func(0.625), 1.); + assert_eq!(#func(0.25), 1.); + assert_eq!(#func(0.1), 1.); + } + } +} + +pub fn trunc(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let trunc_should_eq_one_and_neg_on = trunc_should_eq_one_and_neg_on(&func); + let neg_min_subnorm_eq_neg_zero = b64::neg_min_subnorm_eq_neg_zero(&func); + let min_subnorm_eq_zero = b64::min_subnorm_eq_zero(&func); + let neg_min_positive_eq_neg_zero = b64::neg_min_positive_eq_neg_zero(&func); + quote! { + #neg_min_subnorm_eq_neg_zero + #min_subnorm_eq_zero + #neg_min_positive_eq_neg_zero + #trunc_should_eq_one_and_neg_on + #input_eq_output + } +} +pub fn truncf(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let trunc_should_eq_one_and_neg_on = trunc_should_eq_one_and_neg_on(&func); + let neg_min_subnorm_eq_neg_zero = b32::neg_min_subnorm_eq_neg_zero(&func); + let min_subnorm_eq_zero = b32::min_subnorm_eq_zero(&func); + let neg_min_positive_eq_neg_zero = b32::neg_min_positive_eq_neg_zero(&func); + quote! { + #neg_min_subnorm_eq_neg_zero + #min_subnorm_eq_zero + #neg_min_positive_eq_neg_zero + #trunc_should_eq_one_and_neg_on + #input_eq_output + } +} +pub fn trunc_should_eq_one_and_neg_on(func: &syn::Ident) -> TokenStream { + let should_eq_zero = should_eq_zero(&func); + quote! { + #[test] + pub fn should_eq_neg_one() { + assert_eq!(#func(-1.), -1.); + assert_eq!(#func(-1.625), -1.); + } + #should_eq_zero + #[test] + pub fn should_eq_one() { + assert_eq!(#func(1.), 1.); + assert_eq!(#func(1.625), 1.); + } + } +} +pub fn floor(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let floor = b64::floor(&func); + let min_subnorm_eq_zero = b64::min_subnorm_eq_zero(&func); + let should_eq_zero = should_eq_zero(&func); + let floor_should_eq_neg_one = floor_should_eq_neg_one(&func); + quote! { + #min_subnorm_eq_zero + #floor + #should_eq_zero + #floor_should_eq_neg_one + #input_eq_output + } +} +pub fn floorf(func: &syn::Ident) -> TokenStream { + let input_eq_output = input_eq_output(&func); + let floorf = b32::floorf(&func); + let min_subnorm_eq_zero = b32::min_subnorm_eq_zero(&func); + let should_eq_zero = should_eq_zero(&func); + let floor_should_eq_neg_one = floor_should_eq_neg_one(&func); + quote! { + #min_subnorm_eq_zero + #floorf + #should_eq_zero + #floor_should_eq_neg_one + #input_eq_output + } +} +fn floor_should_eq_neg_one(func: &syn::Ident) -> TokenStream { + // trunc ceil + quote! { + #[test] + pub fn should_eq_neg_one() { + assert_eq!(#func(-0.1), -1.); + assert_eq!(#func(-0.25), -1.); + assert_eq!(#func(-0.625), -1.); + } + } +} + +fn should_eq_neg_zeros(func: &syn::Ident) -> TokenStream { + // trunc ceil + quote! { + #[test] + pub fn should_eq_neg_zeros() { + assert_eq!(#func(-0.1), -0.); + assert_eq!(#func(-0.25), -0.); + assert_eq!(#func(-0.625), -0.); + } + } +} +fn should_eq_zero(func: &syn::Ident) -> TokenStream { + // trunc floor + quote! { + #[test] + pub fn should_eq_zero() { + assert_eq!(#func(0.1), 0.); + assert_eq!(#func(0.25), 0.); + assert_eq!(#func(0.625), 0.); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index a47883d8..2ea12c0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,12 +16,22 @@ feature(core_intrinsics) )] +#[cfg(test)] +extern crate libm_test; + mod math; use core::{f32, f64}; pub use self::math::*; +// I'm not really sure about these numbers I got them from the cplayground. +// F32_MIN_SUBNORM and F64_MIN_SUBNORM are known as FLT_TRUE_MIN and DBL_TRUE_MIN in C11 +pub const F32_MIN_SUBNORM: f32 = 1.401298464324817070923730e-45; + +// https://github.com/rust-lang/rust/issues/31407 +pub const F64_MIN_SUBNORM: f64 = 4.9406564584124654e-324; // 4.94065645841246544176568792868221372365059802614324764e-324; + /// Approximate equality with 1 ULP of tolerance #[doc(hidden)] #[inline] diff --git a/src/math/acos.rs b/src/math/acos.rs index d5e1f686..0d557701 100644 --- a/src/math/acos.rs +++ b/src/math/acos.rs @@ -32,7 +32,6 @@ * * Function needed: sqrt */ - use super::sqrt; const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ diff --git a/src/math/acosf.rs b/src/math/acosf.rs index d0598e81..a2d31c83 100644 --- a/src/math/acosf.rs +++ b/src/math/acosf.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::sqrtf::sqrtf; const PIO2_HI: f32 = 1.5707962513e+00; /* 0x3fc90fda */ diff --git a/src/math/asin.rs b/src/math/asin.rs index 774475e5..a9319058 100644 --- a/src/math/asin.rs +++ b/src/math/asin.rs @@ -38,7 +38,6 @@ * if |x|>1, return NaN with invalid signal. * */ - use super::{fabs, get_high_word, get_low_word, sqrt, with_set_low_word}; const PIO2_HI: f64 = 1.57079632679489655800e+00; /* 0x3FF921FB, 0x54442D18 */ diff --git a/src/math/asinf.rs b/src/math/asinf.rs index ce0f4a99..2bb8692c 100644 --- a/src/math/asinf.rs +++ b/src/math/asinf.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::fabsf::fabsf; use super::sqrt::sqrt; diff --git a/src/math/atan.rs b/src/math/atan.rs index d2684ece..f8227bd1 100644 --- a/src/math/atan.rs +++ b/src/math/atan.rs @@ -28,7 +28,6 @@ * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. */ - use super::fabs; use core::f64; diff --git a/src/math/cbrt.rs b/src/math/cbrt.rs index 04469b15..4200cfc2 100644 --- a/src/math/cbrt.rs +++ b/src/math/cbrt.rs @@ -14,7 +14,6 @@ /* cbrt(x) * Return cube root of x */ - use core::f64; const B1: u32 = 715094163; /* B1 = (1023-1023/3-0.03306235651)*2**20 */ diff --git a/src/math/cbrtf.rs b/src/math/cbrtf.rs index 6e589c09..f4507fc8 100644 --- a/src/math/cbrtf.rs +++ b/src/math/cbrtf.rs @@ -16,7 +16,6 @@ /* cbrtf(x) * Return cube root of x */ - use core::f32; const B1: u32 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ diff --git a/src/math/ceil.rs b/src/math/ceil.rs index 59883a8a..238d048f 100644 --- a/src/math/ceil.rs +++ b/src/math/ceil.rs @@ -1,4 +1,6 @@ use core::f64; +#[cfg(test)] +use libm_test::nearest; const TOINT: f64 = 1. / f64::EPSILON; @@ -7,6 +9,7 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Finds the nearest integer greater than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn ceil(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.ceil` native instruction, so we can leverage this for both code size diff --git a/src/math/ceilf.rs b/src/math/ceilf.rs index 151a4f21..f368d546 100644 --- a/src/math/ceilf.rs +++ b/src/math/ceilf.rs @@ -1,10 +1,13 @@ use core::f32; +#[cfg(test)] +use libm_test::nearest; /// Ceil (f32) /// /// Finds the nearest integer greater than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn ceilf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.ceil` native instruction, so we can leverage this for both code size diff --git a/src/math/cos.rs b/src/math/cos.rs index fe5a8991..e0b8e7da 100644 --- a/src/math/cos.rs +++ b/src/math/cos.rs @@ -8,7 +8,6 @@ // software is freely granted, provided that this notice // is preserved. // ==================================================== - use super::{k_cos, k_sin, rem_pio2}; // cos(x) diff --git a/src/math/cosf.rs b/src/math/cosf.rs index 48d76c8e..49bb1030 100644 --- a/src/math/cosf.rs +++ b/src/math/cosf.rs @@ -13,7 +13,6 @@ * is preserved. * ==================================================== */ - use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/src/math/erff.rs b/src/math/erff.rs index 38405229..a5e7e4f8 100644 --- a/src/math/erff.rs +++ b/src/math/erff.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::{expf, fabsf}; const ERX: f32 = 8.4506291151e-01; /* 0x3f58560b */ diff --git a/src/math/exp.rs b/src/math/exp.rs index 5465b569..15c3adae 100644 --- a/src/math/exp.rs +++ b/src/math/exp.rs @@ -64,7 +64,6 @@ * if x > 709.782712893383973096 then exp(x) overflows * if x < -745.133219101941108420 then exp(x) underflows */ - use super::scalbn; const HALF: [f64; 2] = [0.5, -0.5]; diff --git a/src/math/exp2.rs b/src/math/exp2.rs index c2192fde..47ecada2 100644 --- a/src/math/exp2.rs +++ b/src/math/exp2.rs @@ -23,7 +23,6 @@ // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. - use super::scalbn; const TBLSIZE: usize = 256; diff --git a/src/math/exp2f.rs b/src/math/exp2f.rs index 12c9e76a..eec66b82 100644 --- a/src/math/exp2f.rs +++ b/src/math/exp2f.rs @@ -23,7 +23,6 @@ // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. - const TBLSIZE: usize = 16; static EXP2FT: [u64; TBLSIZE] = [ diff --git a/src/math/expf.rs b/src/math/expf.rs index 09323ec8..26d04170 100644 --- a/src/math/expf.rs +++ b/src/math/expf.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::scalbnf; const HALF: [f32; 2] = [0.5, -0.5]; diff --git a/src/math/expm1.rs b/src/math/expm1.rs index 0d43b4e1..3984f1af 100644 --- a/src/math/expm1.rs +++ b/src/math/expm1.rs @@ -9,7 +9,6 @@ * is preserved. * ==================================================== */ - use core::f64; const O_THRESHOLD: f64 = 7.09782712893383973096e+02; /* 0x40862E42, 0xFEFA39EF */ diff --git a/src/math/floor.rs b/src/math/floor.rs index f6068c69..4a0409bf 100644 --- a/src/math/floor.rs +++ b/src/math/floor.rs @@ -1,4 +1,6 @@ use core::f64; +#[cfg(test)] +use libm_test::nearest; const TOINT: f64 = 1. / f64::EPSILON; @@ -7,6 +9,7 @@ const TOINT: f64 = 1. / f64::EPSILON; /// Finds the nearest integer less than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn floor(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.floor` native instruction, so we can leverage this for both code size diff --git a/src/math/floorf.rs b/src/math/floorf.rs index ae605e19..4c3f4ff9 100644 --- a/src/math/floorf.rs +++ b/src/math/floorf.rs @@ -1,10 +1,13 @@ use core::f32; +#[cfg(test)] +use libm_test::nearest; /// Floor (f64) /// /// Finds the nearest integer less than or equal to `x`. #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn floorf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.floor` native instruction, so we can leverage this for both code size diff --git a/src/math/fmaf.rs b/src/math/fmaf.rs index e77e0fa4..c73dca32 100644 --- a/src/math/fmaf.rs +++ b/src/math/fmaf.rs @@ -24,7 +24,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - use core::f32; use core::ptr::read_volatile; diff --git a/src/math/j0.rs b/src/math/j0.rs index c4258ccc..c072753b 100644 --- a/src/math/j0.rs +++ b/src/math/j0.rs @@ -53,7 +53,6 @@ * by the method mentioned above. * 3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0. */ - use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ const TPI: f64 = 6.36619772367581382433e-01; /* 0x3FE45F30, 0x6DC9C883 */ diff --git a/src/math/j0f.rs b/src/math/j0f.rs index 91c03dbb..8c2a4782 100644 --- a/src/math/j0f.rs +++ b/src/math/j0f.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::{cosf, fabsf, logf, sinf, sqrtf}; const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ diff --git a/src/math/j1.rs b/src/math/j1.rs index 02a65ca5..736f8dca 100644 --- a/src/math/j1.rs +++ b/src/math/j1.rs @@ -53,7 +53,6 @@ * where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1) * by method mentioned above. */ - use super::{cos, fabs, get_high_word, get_low_word, log, sin, sqrt}; const INVSQRTPI: f64 = 5.64189583547756279280e-01; /* 0x3FE20DD7, 0x50429B6D */ diff --git a/src/math/j1f.rs b/src/math/j1f.rs index 83ac1acf..c096e13c 100644 --- a/src/math/j1f.rs +++ b/src/math/j1f.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::{cosf, fabsf, logf, sinf, sqrtf}; const INVSQRTPI: f32 = 5.6418961287e-01; /* 0x3f106ebb */ diff --git a/src/math/log10.rs b/src/math/log10.rs index c9969604..86ea9280 100644 --- a/src/math/log10.rs +++ b/src/math/log10.rs @@ -16,7 +16,6 @@ * as in log.c, then combine and scale in extra precision: * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) */ - use core::f64; const IVLN10HI: f64 = 4.34294481878168880939e-01; /* 0x3fdbcb7b, 0x15200000 */ diff --git a/src/math/log10f.rs b/src/math/log10f.rs index 9845cda5..b7328827 100644 --- a/src/math/log10f.rs +++ b/src/math/log10f.rs @@ -12,7 +12,6 @@ /* * See comments in log10.c. */ - use core::f32; const IVLN10HI: f32 = 4.3432617188e-01; /* 0x3ede6000 */ diff --git a/src/math/log1p.rs b/src/math/log1p.rs index cd7045ac..06d44551 100644 --- a/src/math/log1p.rs +++ b/src/math/log1p.rs @@ -52,7 +52,6 @@ * * See HP-15C Advanced Functions Handbook, p.193. */ - use core::f64; const LN2_HI: f64 = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */ diff --git a/src/math/log1pf.rs b/src/math/log1pf.rs index 8e965135..78eeb840 100644 --- a/src/math/log1pf.rs +++ b/src/math/log1pf.rs @@ -9,7 +9,6 @@ * is preserved. * ==================================================== */ - use core::f32; const LN2_HI: f32 = 6.9313812256e-01; /* 0x3f317180 */ diff --git a/src/math/log2.rs b/src/math/log2.rs index a3d43e55..1e70d965 100644 --- a/src/math/log2.rs +++ b/src/math/log2.rs @@ -16,7 +16,6 @@ * as in log.c, then combine and scale in extra precision: * log2(x) = (f - f*f/2 + r)/log(2) + k */ - use core::f64; const IVLN2HI: f64 = 1.44269504072144627571e+00; /* 0x3ff71547, 0x65200000 */ diff --git a/src/math/log2f.rs b/src/math/log2f.rs index 53a37e50..dcf554af 100644 --- a/src/math/log2f.rs +++ b/src/math/log2f.rs @@ -12,7 +12,6 @@ /* * See comments in log2.c. */ - use core::f32; const IVLN2HI: f32 = 1.4428710938e+00; /* 0x3fb8b000 */ diff --git a/src/math/mod.rs b/src/math/mod.rs index 35ffe1a2..29fd5904 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -69,7 +69,7 @@ macro_rules! llvm_intrinsically_optimized { }; } -// Public modules +// public modules mod acos; mod acosf; mod acosh; diff --git a/src/math/powf.rs b/src/math/powf.rs index 015bade8..b73c5992 100644 --- a/src/math/powf.rs +++ b/src/math/powf.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - use super::{fabsf, scalbnf, sqrtf}; const BP: [f32; 2] = [1.0, 1.5]; diff --git a/src/math/round.rs b/src/math/round.rs index 9a9723cf..1b3e7a51 100644 --- a/src/math/round.rs +++ b/src/math/round.rs @@ -1,9 +1,12 @@ use core::f64; +#[cfg(test)] +use libm_test::nearest; const TOINT: f64 = 1.0 / f64::EPSILON; #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn round(mut x: f64) -> f64 { let (f, i) = (x, x.to_bits()); let e: u64 = i >> 52 & 0x7ff; diff --git a/src/math/roundf.rs b/src/math/roundf.rs index 839d9469..321eccba 100644 --- a/src/math/roundf.rs +++ b/src/math/roundf.rs @@ -1,9 +1,12 @@ use core::f32; +#[cfg(test)] +use libm_test::nearest; const TOINT: f32 = 1.0 / f32::EPSILON; #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn roundf(mut x: f32) -> f32 { let i = x.to_bits(); let e: u32 = i >> 23 & 0xff; diff --git a/src/math/sin.rs b/src/math/sin.rs index 51aed88a..88438c0a 100644 --- a/src/math/sin.rs +++ b/src/math/sin.rs @@ -8,7 +8,6 @@ // software is freely granted, provided that this notice // is preserved. // ==================================================== - use super::{k_cos, k_sin, rem_pio2}; // sin(x) diff --git a/src/math/sincosf.rs b/src/math/sincosf.rs index bb9a0039..6d23220b 100644 --- a/src/math/sincosf.rs +++ b/src/math/sincosf.rs @@ -13,7 +13,6 @@ * is preserved. * ==================================================== */ - use super::{k_cosf, k_sinf, rem_pio2f}; /* Small multiples of pi/2 rounded to double precision. */ diff --git a/src/math/sinf.rs b/src/math/sinf.rs index 0c31099e..0f50c7a8 100644 --- a/src/math/sinf.rs +++ b/src/math/sinf.rs @@ -13,7 +13,6 @@ * is preserved. * ==================================================== */ - use super::{k_cosf, k_sinf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/src/math/sqrt.rs b/src/math/sqrt.rs index 14404d4e..daaec535 100644 --- a/src/math/sqrt.rs +++ b/src/math/sqrt.rs @@ -75,7 +75,6 @@ * sqrt(-ve) = NaN ... with invalid signal * sqrt(NaN) = NaN ... with invalid signal for signaling NaN */ - use core::f64; use core::num::Wrapping; diff --git a/src/math/sqrtf.rs b/src/math/sqrtf.rs index b9365c61..4cdf1dd2 100644 --- a/src/math/sqrtf.rs +++ b/src/math/sqrtf.rs @@ -12,7 +12,6 @@ * is preserved. * ==================================================== */ - const TINY: f32 = 1.0e-30; #[inline] diff --git a/src/math/tan.rs b/src/math/tan.rs index e5c94cbb..9c8c731d 100644 --- a/src/math/tan.rs +++ b/src/math/tan.rs @@ -8,7 +8,6 @@ // software is freely granted, provided that this notice // is preserved. // ==================================================== - use super::{k_tan, rem_pio2}; // tan(x) diff --git a/src/math/tanf.rs b/src/math/tanf.rs index c286cdeb..143c1c70 100644 --- a/src/math/tanf.rs +++ b/src/math/tanf.rs @@ -13,7 +13,6 @@ * is preserved. * ==================================================== */ - use super::{k_tanf, rem_pio2f}; use core::f64::consts::FRAC_PI_2; diff --git a/src/math/trunc.rs b/src/math/trunc.rs index 1ee46fc7..fd59cb53 100644 --- a/src/math/trunc.rs +++ b/src/math/trunc.rs @@ -1,7 +1,10 @@ use core::f64; +#[cfg(test)] +use libm_test::nearest; #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn trunc(x: f64) -> f64 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f64.trunc` native instruction, so we can leverage this for both code size diff --git a/src/math/truncf.rs b/src/math/truncf.rs index f9338326..44f60e64 100644 --- a/src/math/truncf.rs +++ b/src/math/truncf.rs @@ -1,7 +1,10 @@ use core::f32; +#[cfg(test)] +use libm_test::nearest; #[inline] #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +#[cfg_attr(test, nearest)] pub fn truncf(x: f32) -> f32 { // On wasm32 we know that LLVM's intrinsic will compile to an optimized // `f32.trunc` native instruction, so we can leverage this for both code size