1cbd624adSopenharmony_ci#![cfg(all(not(feature = "std"), feature = "compact"))] 2cbd624adSopenharmony_ci 3cbd624adSopenharmony_ci// These are adapted from libm, a port of musl libc's libm to Rust. 4cbd624adSopenharmony_ci// libm can be found online [here](https://github.com/rust-lang/libm), 5cbd624adSopenharmony_ci// and is similarly licensed under an Apache2.0/MIT license 6cbd624adSopenharmony_ci 7cbd624adSopenharmony_ciuse core::f64; 8cbd624adSopenharmony_ciuse minimal_lexical::libm; 9cbd624adSopenharmony_ci 10cbd624adSopenharmony_ci#[test] 11cbd624adSopenharmony_cifn fabsf_sanity_test() { 12cbd624adSopenharmony_ci assert_eq!(libm::fabsf(-1.0), 1.0); 13cbd624adSopenharmony_ci assert_eq!(libm::fabsf(2.8), 2.8); 14cbd624adSopenharmony_ci} 15cbd624adSopenharmony_ci 16cbd624adSopenharmony_ci/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs 17cbd624adSopenharmony_ci#[test] 18cbd624adSopenharmony_cifn fabsf_spec_test() { 19cbd624adSopenharmony_ci assert!(libm::fabsf(f32::NAN).is_nan()); 20cbd624adSopenharmony_ci for f in [0.0, -0.0].iter().copied() { 21cbd624adSopenharmony_ci assert_eq!(libm::fabsf(f), 0.0); 22cbd624adSopenharmony_ci } 23cbd624adSopenharmony_ci for f in [f32::INFINITY, f32::NEG_INFINITY].iter().copied() { 24cbd624adSopenharmony_ci assert_eq!(libm::fabsf(f), f32::INFINITY); 25cbd624adSopenharmony_ci } 26cbd624adSopenharmony_ci} 27cbd624adSopenharmony_ci 28cbd624adSopenharmony_ci#[test] 29cbd624adSopenharmony_cifn sqrtf_sanity_test() { 30cbd624adSopenharmony_ci assert_eq!(libm::sqrtf(100.0), 10.0); 31cbd624adSopenharmony_ci assert_eq!(libm::sqrtf(4.0), 2.0); 32cbd624adSopenharmony_ci} 33cbd624adSopenharmony_ci 34cbd624adSopenharmony_ci/// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt 35cbd624adSopenharmony_ci#[test] 36cbd624adSopenharmony_cifn sqrtf_spec_test() { 37cbd624adSopenharmony_ci // Not Asserted: FE_INVALID exception is raised if argument is negative. 38cbd624adSopenharmony_ci assert!(libm::sqrtf(-1.0).is_nan()); 39cbd624adSopenharmony_ci assert!(libm::sqrtf(f32::NAN).is_nan()); 40cbd624adSopenharmony_ci for f in [0.0, -0.0, f32::INFINITY].iter().copied() { 41cbd624adSopenharmony_ci assert_eq!(libm::sqrtf(f), f); 42cbd624adSopenharmony_ci } 43cbd624adSopenharmony_ci} 44cbd624adSopenharmony_ci 45cbd624adSopenharmony_ciconst POS_ZERO: &[f64] = &[0.0]; 46cbd624adSopenharmony_ciconst NEG_ZERO: &[f64] = &[-0.0]; 47cbd624adSopenharmony_ciconst POS_ONE: &[f64] = &[1.0]; 48cbd624adSopenharmony_ciconst NEG_ONE: &[f64] = &[-1.0]; 49cbd624adSopenharmony_ciconst POS_FLOATS: &[f64] = &[99.0 / 70.0, f64::consts::E, f64::consts::PI]; 50cbd624adSopenharmony_ciconst NEG_FLOATS: &[f64] = &[-99.0 / 70.0, -f64::consts::E, -f64::consts::PI]; 51cbd624adSopenharmony_ciconst POS_SMALL_FLOATS: &[f64] = &[(1.0 / 2.0), f64::MIN_POSITIVE, f64::EPSILON]; 52cbd624adSopenharmony_ciconst NEG_SMALL_FLOATS: &[f64] = &[-(1.0 / 2.0), -f64::MIN_POSITIVE, -f64::EPSILON]; 53cbd624adSopenharmony_ciconst POS_EVENS: &[f64] = &[2.0, 6.0, 8.0, 10.0, 22.0, 100.0, f64::MAX]; 54cbd624adSopenharmony_ciconst NEG_EVENS: &[f64] = &[f64::MIN, -100.0, -22.0, -10.0, -8.0, -6.0, -2.0]; 55cbd624adSopenharmony_ciconst POS_ODDS: &[f64] = &[3.0, 7.0]; 56cbd624adSopenharmony_ciconst NEG_ODDS: &[f64] = &[-7.0, -3.0]; 57cbd624adSopenharmony_ciconst NANS: &[f64] = &[f64::NAN]; 58cbd624adSopenharmony_ciconst POS_INF: &[f64] = &[f64::INFINITY]; 59cbd624adSopenharmony_ciconst NEG_INF: &[f64] = &[f64::NEG_INFINITY]; 60cbd624adSopenharmony_ci 61cbd624adSopenharmony_ciconst ALL: &[&[f64]] = &[ 62cbd624adSopenharmony_ci POS_ZERO, 63cbd624adSopenharmony_ci NEG_ZERO, 64cbd624adSopenharmony_ci NANS, 65cbd624adSopenharmony_ci NEG_SMALL_FLOATS, 66cbd624adSopenharmony_ci POS_SMALL_FLOATS, 67cbd624adSopenharmony_ci NEG_FLOATS, 68cbd624adSopenharmony_ci POS_FLOATS, 69cbd624adSopenharmony_ci NEG_EVENS, 70cbd624adSopenharmony_ci POS_EVENS, 71cbd624adSopenharmony_ci NEG_ODDS, 72cbd624adSopenharmony_ci POS_ODDS, 73cbd624adSopenharmony_ci NEG_INF, 74cbd624adSopenharmony_ci POS_INF, 75cbd624adSopenharmony_ci NEG_ONE, 76cbd624adSopenharmony_ci POS_ONE, 77cbd624adSopenharmony_ci]; 78cbd624adSopenharmony_ciconst POS: &[&[f64]] = &[POS_ZERO, POS_ODDS, POS_ONE, POS_FLOATS, POS_EVENS, POS_INF]; 79cbd624adSopenharmony_ciconst NEG: &[&[f64]] = &[NEG_ZERO, NEG_ODDS, NEG_ONE, NEG_FLOATS, NEG_EVENS, NEG_INF]; 80cbd624adSopenharmony_ci 81cbd624adSopenharmony_cifn powd(base: f64, exponent: f64, expected: f64) { 82cbd624adSopenharmony_ci let res = libm::powd(base, exponent); 83cbd624adSopenharmony_ci assert!( 84cbd624adSopenharmony_ci if expected.is_nan() { 85cbd624adSopenharmony_ci res.is_nan() 86cbd624adSopenharmony_ci } else { 87cbd624adSopenharmony_ci libm::powd(base, exponent) == expected 88cbd624adSopenharmony_ci }, 89cbd624adSopenharmony_ci "{} ** {} was {} instead of {}", 90cbd624adSopenharmony_ci base, 91cbd624adSopenharmony_ci exponent, 92cbd624adSopenharmony_ci res, 93cbd624adSopenharmony_ci expected 94cbd624adSopenharmony_ci ); 95cbd624adSopenharmony_ci} 96cbd624adSopenharmony_ci 97cbd624adSopenharmony_cifn powd_test_sets_as_base(sets: &[&[f64]], exponent: f64, expected: f64) { 98cbd624adSopenharmony_ci sets.iter().for_each(|s| s.iter().for_each(|val| powd(*val, exponent, expected))); 99cbd624adSopenharmony_ci} 100cbd624adSopenharmony_ci 101cbd624adSopenharmony_cifn powd_test_sets_as_exponent(base: f64, sets: &[&[f64]], expected: f64) { 102cbd624adSopenharmony_ci sets.iter().for_each(|s| s.iter().for_each(|val| powd(base, *val, expected))); 103cbd624adSopenharmony_ci} 104cbd624adSopenharmony_ci 105cbd624adSopenharmony_cifn powd_test_sets(sets: &[&[f64]], computed: &dyn Fn(f64) -> f64, expected: &dyn Fn(f64) -> f64) { 106cbd624adSopenharmony_ci sets.iter().for_each(|s| { 107cbd624adSopenharmony_ci s.iter().for_each(|val| { 108cbd624adSopenharmony_ci let exp = expected(*val); 109cbd624adSopenharmony_ci let res = computed(*val); 110cbd624adSopenharmony_ci 111cbd624adSopenharmony_ci assert!( 112cbd624adSopenharmony_ci if exp.is_nan() { 113cbd624adSopenharmony_ci res.is_nan() 114cbd624adSopenharmony_ci } else { 115cbd624adSopenharmony_ci exp == res 116cbd624adSopenharmony_ci }, 117cbd624adSopenharmony_ci "test for {} was {} instead of {}", 118cbd624adSopenharmony_ci val, 119cbd624adSopenharmony_ci res, 120cbd624adSopenharmony_ci exp 121cbd624adSopenharmony_ci ); 122cbd624adSopenharmony_ci }) 123cbd624adSopenharmony_ci }); 124cbd624adSopenharmony_ci} 125cbd624adSopenharmony_ci 126cbd624adSopenharmony_ci#[test] 127cbd624adSopenharmony_cifn powd_zero_as_exponent() { 128cbd624adSopenharmony_ci powd_test_sets_as_base(ALL, 0.0, 1.0); 129cbd624adSopenharmony_ci powd_test_sets_as_base(ALL, -0.0, 1.0); 130cbd624adSopenharmony_ci} 131cbd624adSopenharmony_ci 132cbd624adSopenharmony_ci#[test] 133cbd624adSopenharmony_cifn powd_one_as_base() { 134cbd624adSopenharmony_ci powd_test_sets_as_exponent(1.0, ALL, 1.0); 135cbd624adSopenharmony_ci} 136cbd624adSopenharmony_ci 137cbd624adSopenharmony_ci#[test] 138cbd624adSopenharmony_cifn powd_nan_inputs() { 139cbd624adSopenharmony_ci // NAN as the base: 140cbd624adSopenharmony_ci // (NAN ^ anything *but 0* should be NAN) 141cbd624adSopenharmony_ci powd_test_sets_as_exponent(f64::NAN, &ALL[2..], f64::NAN); 142cbd624adSopenharmony_ci 143cbd624adSopenharmony_ci // NAN as the exponent: 144cbd624adSopenharmony_ci // (anything *but 1* ^ NAN should be NAN) 145cbd624adSopenharmony_ci powd_test_sets_as_base(&ALL[..(ALL.len() - 2)], f64::NAN, f64::NAN); 146cbd624adSopenharmony_ci} 147cbd624adSopenharmony_ci 148cbd624adSopenharmony_ci#[test] 149cbd624adSopenharmony_cifn powd_infinity_as_base() { 150cbd624adSopenharmony_ci // Positive Infinity as the base: 151cbd624adSopenharmony_ci // (+Infinity ^ positive anything but 0 and NAN should be +Infinity) 152cbd624adSopenharmony_ci powd_test_sets_as_exponent(f64::INFINITY, &POS[1..], f64::INFINITY); 153cbd624adSopenharmony_ci 154cbd624adSopenharmony_ci // (+Infinity ^ negative anything except 0 and NAN should be 0.0) 155cbd624adSopenharmony_ci powd_test_sets_as_exponent(f64::INFINITY, &NEG[1..], 0.0); 156cbd624adSopenharmony_ci 157cbd624adSopenharmony_ci // Negative Infinity as the base: 158cbd624adSopenharmony_ci // (-Infinity ^ positive odd ints should be -Infinity) 159cbd624adSopenharmony_ci powd_test_sets_as_exponent(f64::NEG_INFINITY, &[POS_ODDS], f64::NEG_INFINITY); 160cbd624adSopenharmony_ci 161cbd624adSopenharmony_ci // (-Infinity ^ anything but odd ints should be == -0 ^ (-anything)) 162cbd624adSopenharmony_ci // We can lump in pos/neg odd ints here because they don't seem to 163cbd624adSopenharmony_ci // cause panics (div by zero) in release mode (I think). 164cbd624adSopenharmony_ci powd_test_sets(ALL, &|v: f64| libm::powd(f64::NEG_INFINITY, v), &|v: f64| libm::powd(-0.0, -v)); 165cbd624adSopenharmony_ci} 166cbd624adSopenharmony_ci 167cbd624adSopenharmony_ci#[test] 168cbd624adSopenharmony_cifn infinity_as_exponent() { 169cbd624adSopenharmony_ci // Positive/Negative base greater than 1: 170cbd624adSopenharmony_ci // (pos/neg > 1 ^ Infinity should be Infinity - note this excludes NAN as the base) 171cbd624adSopenharmony_ci powd_test_sets_as_base(&ALL[5..(ALL.len() - 2)], f64::INFINITY, f64::INFINITY); 172cbd624adSopenharmony_ci 173cbd624adSopenharmony_ci // (pos/neg > 1 ^ -Infinity should be 0.0) 174cbd624adSopenharmony_ci powd_test_sets_as_base(&ALL[5..ALL.len() - 2], f64::NEG_INFINITY, 0.0); 175cbd624adSopenharmony_ci 176cbd624adSopenharmony_ci // Positive/Negative base less than 1: 177cbd624adSopenharmony_ci let base_below_one = &[POS_ZERO, NEG_ZERO, NEG_SMALL_FLOATS, POS_SMALL_FLOATS]; 178cbd624adSopenharmony_ci 179cbd624adSopenharmony_ci // (pos/neg < 1 ^ Infinity should be 0.0 - this also excludes NAN as the base) 180cbd624adSopenharmony_ci powd_test_sets_as_base(base_below_one, f64::INFINITY, 0.0); 181cbd624adSopenharmony_ci 182cbd624adSopenharmony_ci // (pos/neg < 1 ^ -Infinity should be Infinity) 183cbd624adSopenharmony_ci powd_test_sets_as_base(base_below_one, f64::NEG_INFINITY, f64::INFINITY); 184cbd624adSopenharmony_ci 185cbd624adSopenharmony_ci // Positive/Negative 1 as the base: 186cbd624adSopenharmony_ci // (pos/neg 1 ^ Infinity should be 1) 187cbd624adSopenharmony_ci powd_test_sets_as_base(&[NEG_ONE, POS_ONE], f64::INFINITY, 1.0); 188cbd624adSopenharmony_ci 189cbd624adSopenharmony_ci // (pos/neg 1 ^ -Infinity should be 1) 190cbd624adSopenharmony_ci powd_test_sets_as_base(&[NEG_ONE, POS_ONE], f64::NEG_INFINITY, 1.0); 191cbd624adSopenharmony_ci} 192cbd624adSopenharmony_ci 193cbd624adSopenharmony_ci#[test] 194cbd624adSopenharmony_cifn powd_zero_as_base() { 195cbd624adSopenharmony_ci // Positive Zero as the base: 196cbd624adSopenharmony_ci // (+0 ^ anything positive but 0 and NAN should be +0) 197cbd624adSopenharmony_ci powd_test_sets_as_exponent(0.0, &POS[1..], 0.0); 198cbd624adSopenharmony_ci 199cbd624adSopenharmony_ci // (+0 ^ anything negative but 0 and NAN should be Infinity) 200cbd624adSopenharmony_ci // (this should panic because we're dividing by zero) 201cbd624adSopenharmony_ci powd_test_sets_as_exponent(0.0, &NEG[1..], f64::INFINITY); 202cbd624adSopenharmony_ci 203cbd624adSopenharmony_ci // Negative Zero as the base: 204cbd624adSopenharmony_ci // (-0 ^ anything positive but 0, NAN, and odd ints should be +0) 205cbd624adSopenharmony_ci powd_test_sets_as_exponent(-0.0, &POS[3..], 0.0); 206cbd624adSopenharmony_ci 207cbd624adSopenharmony_ci // (-0 ^ anything negative but 0, NAN, and odd ints should be Infinity) 208cbd624adSopenharmony_ci // (should panic because of divide by zero) 209cbd624adSopenharmony_ci powd_test_sets_as_exponent(-0.0, &NEG[3..], f64::INFINITY); 210cbd624adSopenharmony_ci 211cbd624adSopenharmony_ci // (-0 ^ positive odd ints should be -0) 212cbd624adSopenharmony_ci powd_test_sets_as_exponent(-0.0, &[POS_ODDS], -0.0); 213cbd624adSopenharmony_ci 214cbd624adSopenharmony_ci // (-0 ^ negative odd ints should be -Infinity) 215cbd624adSopenharmony_ci // (should panic because of divide by zero) 216cbd624adSopenharmony_ci powd_test_sets_as_exponent(-0.0, &[NEG_ODDS], f64::NEG_INFINITY); 217cbd624adSopenharmony_ci} 218cbd624adSopenharmony_ci 219cbd624adSopenharmony_ci#[test] 220cbd624adSopenharmony_cifn special_cases() { 221cbd624adSopenharmony_ci // One as the exponent: 222cbd624adSopenharmony_ci // (anything ^ 1 should be anything - i.e. the base) 223cbd624adSopenharmony_ci powd_test_sets(ALL, &|v: f64| libm::powd(v, 1.0), &|v: f64| v); 224cbd624adSopenharmony_ci 225cbd624adSopenharmony_ci // Negative One as the exponent: 226cbd624adSopenharmony_ci // (anything ^ -1 should be 1/anything) 227cbd624adSopenharmony_ci powd_test_sets(ALL, &|v: f64| libm::powd(v, -1.0), &|v: f64| 1.0 / v); 228cbd624adSopenharmony_ci 229cbd624adSopenharmony_ci // Factoring -1 out: 230cbd624adSopenharmony_ci // (negative anything ^ integer should be (-1 ^ integer) * (positive anything ^ integer)) 231cbd624adSopenharmony_ci [POS_ZERO, NEG_ZERO, POS_ONE, NEG_ONE, POS_EVENS, NEG_EVENS].iter().for_each(|int_set| { 232cbd624adSopenharmony_ci int_set.iter().for_each(|int| { 233cbd624adSopenharmony_ci powd_test_sets(ALL, &|v: f64| libm::powd(-v, *int), &|v: f64| { 234cbd624adSopenharmony_ci libm::powd(-1.0, *int) * libm::powd(v, *int) 235cbd624adSopenharmony_ci }); 236cbd624adSopenharmony_ci }) 237cbd624adSopenharmony_ci }); 238cbd624adSopenharmony_ci 239cbd624adSopenharmony_ci // Negative base (imaginary results): 240cbd624adSopenharmony_ci // (-anything except 0 and Infinity ^ non-integer should be NAN) 241cbd624adSopenharmony_ci NEG[1..(NEG.len() - 1)].iter().for_each(|set| { 242cbd624adSopenharmony_ci set.iter().for_each(|val| { 243cbd624adSopenharmony_ci powd_test_sets(&ALL[3..7], &|v: f64| libm::powd(*val, v), &|_| f64::NAN); 244cbd624adSopenharmony_ci }) 245cbd624adSopenharmony_ci }); 246cbd624adSopenharmony_ci} 247cbd624adSopenharmony_ci 248cbd624adSopenharmony_ci#[test] 249cbd624adSopenharmony_cifn normal_cases() { 250cbd624adSopenharmony_ci assert_eq!(libm::powd(2.0, 20.0), (1 << 20) as f64); 251cbd624adSopenharmony_ci assert_eq!(libm::powd(-1.0, 9.0), -1.0); 252cbd624adSopenharmony_ci assert!(libm::powd(-1.0, 2.2).is_nan()); 253cbd624adSopenharmony_ci assert!(libm::powd(-1.0, -1.14).is_nan()); 254cbd624adSopenharmony_ci} 255cbd624adSopenharmony_ci 256cbd624adSopenharmony_ci#[test] 257cbd624adSopenharmony_cifn fabsd_sanity_test() { 258cbd624adSopenharmony_ci assert_eq!(libm::fabsd(-1.0), 1.0); 259cbd624adSopenharmony_ci assert_eq!(libm::fabsd(2.8), 2.8); 260cbd624adSopenharmony_ci} 261cbd624adSopenharmony_ci 262cbd624adSopenharmony_ci/// The spec: https://en.cppreference.com/w/cpp/numeric/math/fabs 263cbd624adSopenharmony_ci#[test] 264cbd624adSopenharmony_cifn fabsd_spec_test() { 265cbd624adSopenharmony_ci assert!(libm::fabsd(f64::NAN).is_nan()); 266cbd624adSopenharmony_ci for f in [0.0, -0.0].iter().copied() { 267cbd624adSopenharmony_ci assert_eq!(libm::fabsd(f), 0.0); 268cbd624adSopenharmony_ci } 269cbd624adSopenharmony_ci for f in [f64::INFINITY, f64::NEG_INFINITY].iter().copied() { 270cbd624adSopenharmony_ci assert_eq!(libm::fabsd(f), f64::INFINITY); 271cbd624adSopenharmony_ci } 272cbd624adSopenharmony_ci} 273cbd624adSopenharmony_ci 274cbd624adSopenharmony_ci#[test] 275cbd624adSopenharmony_cifn sqrtd_sanity_test() { 276cbd624adSopenharmony_ci assert_eq!(libm::sqrtd(100.0), 10.0); 277cbd624adSopenharmony_ci assert_eq!(libm::sqrtd(4.0), 2.0); 278cbd624adSopenharmony_ci} 279cbd624adSopenharmony_ci 280cbd624adSopenharmony_ci/// The spec: https://en.cppreference.com/w/cpp/numeric/math/sqrt 281cbd624adSopenharmony_ci#[test] 282cbd624adSopenharmony_cifn sqrtd_spec_test() { 283cbd624adSopenharmony_ci // Not Asserted: FE_INVALID exception is raised if argument is negative. 284cbd624adSopenharmony_ci assert!(libm::sqrtd(-1.0).is_nan()); 285cbd624adSopenharmony_ci assert!(libm::sqrtd(f64::NAN).is_nan()); 286cbd624adSopenharmony_ci for f in [0.0, -0.0, f64::INFINITY].iter().copied() { 287cbd624adSopenharmony_ci assert_eq!(libm::sqrtd(f), f); 288cbd624adSopenharmony_ci } 289cbd624adSopenharmony_ci} 290