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