substrate_fixed/
transcendental.rs

1//  Copyright (c) 2019 Alain Brenzikofer
2//
3//  Licensed under the Apache License, Version 2.0 (the "License");
4//  you may not use this file except in compliance with the License.
5//  You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14
15/*!
16This module contains transcendental functions.
17*/
18use crate::consts;
19use crate::traits::{Fixed, FixedSigned, LossyFrom, ToFixed};
20use crate::types::{I9F23, I9F55, U0F128};
21use core::ops::{AddAssign, BitOrAssign, ShlAssign};
22
23type ConstType = I9F23;
24
25/// zero
26pub const ZERO: I9F23 = I9F23::from_bits(0i32 << 23);
27/// one
28pub const ONE: I9F23 = I9F23::from_bits(1i32 << 23);
29/// two
30pub const TWO: I9F23 = I9F23::from_bits(2i32 << 23);
31/// three
32pub const THREE: I9F23 = I9F23::from_bits(3i32 << 23);
33/// 2*pi
34pub const TWO_PI: I9F23 = I9F23::from_bits((consts::PI.to_bits() >> 102) as i32);
35/// pi
36pub const PI: I9F23 = I9F23::from_bits((consts::PI.to_bits() >> 103) as i32);
37/// pi/2
38pub const FRAC_PI_2: I9F23 = I9F23::from_bits((consts::PI.to_bits() >> 104) as i32);
39/// pi/4
40pub const FRAC_PI_4: I9F23 = I9F23::from_bits((consts::PI.to_bits() >> 105) as i32);
41/// log2(e)
42pub const LOG2_E: I9F23 = I9F23::from_bits((consts::LOG2_E.to_bits() >> 104) as i32);
43/// e
44pub const E: I9F23 = I9F23::from_bits((consts::E.to_bits() >> 103) as i32);
45
46// generate with
47// ```matlab
48// for i = [0:63]
49//   disp(["0x", dec2hex(round(atan(2^(-i)) * 2^128),32)])
50// end
51// ```
52/// arctan(2^-i) lookup table for cordic
53const ARCTAN_ANGLES: [U0F128; 64] = [
54    U0F128::from_bits(0xC90FDAA22168C0000000000000000000),
55    U0F128::from_bits(0x76B19C1586ED3C000000000000000000),
56    U0F128::from_bits(0x3EB6EBF25901BA000000000000000000),
57    U0F128::from_bits(0x1FD5BA9AAC2F6E000000000000000000),
58    U0F128::from_bits(0x0FFAADDB967EF5000000000000000000),
59    U0F128::from_bits(0x07FF556EEA5D89400000000000000000),
60    U0F128::from_bits(0x03FFEAAB776E53600000000000000000),
61    U0F128::from_bits(0x01FFFD555BBBA9700000000000000000),
62    U0F128::from_bits(0x00FFFFAAAADDDDB80000000000000000),
63    U0F128::from_bits(0x007FFFF55556EEF00000000000000000),
64    U0F128::from_bits(0x003FFFFEAAAAB7780000000000000000),
65    U0F128::from_bits(0x001FFFFFD55555BC0000000000000000),
66    U0F128::from_bits(0x000FFFFFFAAAAAAE0000000000000000),
67    U0F128::from_bits(0x0007FFFFFF5555558000000000000000),
68    U0F128::from_bits(0x0003FFFFFFEAAAAAA000000000000000),
69    U0F128::from_bits(0x0001FFFFFFFD55555000000000000000),
70    U0F128::from_bits(0x0000FFFFFFFFAAAAA800000000000000),
71    U0F128::from_bits(0x00007FFFFFFFF5555400000000000000),
72    U0F128::from_bits(0x00003FFFFFFFFEAAAA00000000000000),
73    U0F128::from_bits(0x00001FFFFFFFFFD55500000000000000),
74    U0F128::from_bits(0x00000FFFFFFFFFFAAA80000000000000),
75    U0F128::from_bits(0x000007FFFFFFFFFF5540000000000000),
76    U0F128::from_bits(0x000003FFFFFFFFFFEAA0000000000000),
77    U0F128::from_bits(0x000001FFFFFFFFFFFD50000000000000),
78    U0F128::from_bits(0x000000FFFFFFFFFFFFA8000000000000),
79    U0F128::from_bits(0x0000007FFFFFFFFFFFF4000000000000),
80    U0F128::from_bits(0x0000003FFFFFFFFFFFFE000000000000),
81    U0F128::from_bits(0x00000020000000000000000000000000),
82    U0F128::from_bits(0x00000010000000000000000000000000),
83    U0F128::from_bits(0x00000008000000000000000000000000),
84    U0F128::from_bits(0x00000004000000000000000000000000),
85    U0F128::from_bits(0x00000002000000000000000000000000),
86    U0F128::from_bits(0x00000001000000000000000000000000),
87    U0F128::from_bits(0x00000000800000000000000000000000),
88    U0F128::from_bits(0x00000000400000000000000000000000),
89    U0F128::from_bits(0x00000000200000000000000000000000),
90    U0F128::from_bits(0x00000000100000000000000000000000),
91    U0F128::from_bits(0x00000000080000000000000000000000),
92    U0F128::from_bits(0x00000000040000000000000000000000),
93    U0F128::from_bits(0x00000000020000000000000000000000),
94    U0F128::from_bits(0x00000000010000000000000000000000),
95    U0F128::from_bits(0x00000000008000000000000000000000),
96    U0F128::from_bits(0x00000000004000000000000000000000),
97    U0F128::from_bits(0x00000000002000000000000000000000),
98    U0F128::from_bits(0x00000000001000000000000000000000),
99    U0F128::from_bits(0x00000000000800000000000000000000),
100    U0F128::from_bits(0x00000000000400000000000000000000),
101    U0F128::from_bits(0x00000000000200000000000000000000),
102    U0F128::from_bits(0x00000000000100000000000000000000),
103    U0F128::from_bits(0x00000000000080000000000000000000),
104    U0F128::from_bits(0x00000000000040000000000000000000),
105    U0F128::from_bits(0x00000000000020000000000000000000),
106    U0F128::from_bits(0x00000000000010000000000000000000),
107    U0F128::from_bits(0x00000000000008000000000000000000),
108    U0F128::from_bits(0x00000000000004000000000000000000),
109    U0F128::from_bits(0x00000000000002000000000000000000),
110    U0F128::from_bits(0x00000000000001000000000000000000),
111    U0F128::from_bits(0x00000000000000800000000000000000),
112    U0F128::from_bits(0x00000000000000400000000000000000),
113    U0F128::from_bits(0x00000000000000200000000000000000),
114    U0F128::from_bits(0x00000000000000100000000000000000),
115    U0F128::from_bits(0x00000000000000080000000000000000),
116    U0F128::from_bits(0x00000000000000040000000000000000),
117    U0F128::from_bits(0x00000000000000020000000000000000),
118];
119
120/// right-shift with rounding
121fn rs<T>(operand: T) -> T
122where
123    T: Fixed,
124{
125    let lsb = T::from_num(1) >> T::frac_nbits();
126    (operand >> 1) + (operand & lsb)
127    //let x = operand.to_bits();
128    //T::from_bits((x >> 1) + (x & 1))
129}
130
131/// square root
132pub fn sqrt<S, D>(operand: S) -> Result<D, &'static str>
133where
134    S: Fixed + PartialOrd<ConstType>,
135    D: Fixed + PartialOrd<ConstType> + From<S>,
136{
137    let mut invert = false;
138    if operand < ZERO {
139        return Err("Can't calculate sqrt from negative numbers.");
140    };
141
142    let mut operand = D::from(operand);
143    if operand == ZERO || operand == ONE {
144        return Ok(operand);
145    };
146    if operand < ONE {
147        invert = true;
148        operand = if let Some(r) = D::from_num(1).checked_div(operand) {
149            r
150        } else {
151            return Err("Overflow inverting operand.");
152        };
153    }
154    // Newton iterations
155    let mut l = (operand / D::from_num(2)) + D::from_num(1);
156    for _i in 0..D::frac_nbits() {
157        l = (l + operand / l) / D::from_num(2);
158    }
159    if invert {
160        l = if let Some(r) = D::from_num(1).checked_div(l) {
161            r
162        } else {
163            return Err("Overflow un-inverting operand.");
164        };
165    }
166    Ok(l)
167}
168
169/// base 2 logarithm assuming self >=1
170fn log2_inner<S, D>(operand: S) -> D
171where
172    S: FixedSigned + PartialOrd<ConstType>,
173    D: FixedSigned,
174    D::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
175{
176    let mut x = operand;
177    let mut result = D::from_num(0).to_bits();
178    let lsb = (D::from_num(1) >> D::frac_nbits()).to_bits();
179
180    while x >= TWO {
181        result += lsb;
182        x = rs(x);
183    }
184
185    if x == ONE {
186        return D::from_num(result);
187    };
188
189    for _i in (0..D::frac_nbits()).rev() {
190        x *= x;
191        result <<= lsb;
192        if x >= TWO {
193            result |= lsb;
194            x = rs(x);
195        }
196    }
197    D::from_bits(result)
198}
199
200/// base 2 logarithm
201pub fn log2<S, D>(operand: S) -> Result<D, ()>
202where
203    S: FixedSigned + PartialOrd<ConstType>,
204    D: FixedSigned + PartialOrd<ConstType> + From<S>,
205    D::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
206{
207    if operand <= S::from_num(0) {
208        return Err(());
209    };
210
211    let operand = D::from(operand);
212    if operand < D::from_num(1) {
213        let inverse = D::from_num(1).checked_div(operand).ok_or(())?;
214        return Ok(-log2_inner::<D, D>(inverse));
215    };
216    return Ok(log2_inner::<D, D>(operand));
217}
218
219/// natural logarithm
220pub fn ln<S, D>(operand: S) -> Result<D, ()>
221where
222    S: FixedSigned + PartialOrd<ConstType>,
223    D: FixedSigned + PartialOrd<ConstType> + From<S> + From<ConstType>,
224    D::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
225{
226    Ok(log2::<S, D>(operand)? / D::from(LOG2_E))
227}
228
229/// exponential function e^(operand)
230pub fn exp<S, D>(mut operand: S) -> Result<D, ()>
231where
232    S: FixedSigned + PartialOrd<ConstType>,
233    D: FixedSigned + PartialOrd<ConstType> + From<S> + From<ConstType>,
234{
235    if operand == ZERO {
236        return Ok(D::from_num(1));
237    };
238    if operand == ONE {
239        return Ok(D::from(E));
240    };
241    let neg = operand < ZERO;
242    if neg {
243        operand = operand.checked_neg().ok_or(())?;
244    };
245
246    let operand = D::from(operand);
247    let mut result = operand.checked_add(D::from_num(1)).ok_or(())?;
248    let mut term = operand;
249
250    for i in 2..D::frac_nbits() {
251        term = if let Some(r) = term.checked_mul(operand) {
252            r
253        } else {
254            return Err(());
255        };
256        //let bits = if let Some(r) = D::from_num(i)
257        //    { r } else { return Err(()) };
258        term = if let Some(r) = term.checked_div(D::from_num(i)) {
259            r
260        } else {
261            return Err(());
262        };
263
264        result = if let Some(r) = result.checked_add(term) {
265            r
266        } else {
267            return Err(());
268        };
269        //if term < 500 && (i > 15 || term < $ty(20i32).unwrap()) {
270        //    break;
271        //};
272    }
273    if neg {
274        result = if let Some(r) = D::from_num(1).checked_div(result) {
275            r
276        } else {
277            return Err(());
278        };
279    }
280    Ok(result)
281}
282
283/// power
284pub fn pow<S, D>(operand: S, exponent: S) -> Result<D, ()>
285where
286    S: FixedSigned + PartialOrd<ConstType>,
287    D: FixedSigned + PartialOrd<ConstType> + From<S> + From<ConstType>,
288    D::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
289{
290    // TODO: dynamic typing depending on input
291    //type I = FixedI128<U64>; // internal
292    if operand == S::from_num(0) {
293        return Ok(D::from_num(0));
294    };
295    if exponent == S::from_num(0) {
296        return Ok(D::from_num(1));
297    };
298    if exponent == S::from_num(1) {
299        return Ok(D::from(operand));
300    };
301
302    let r = if let Some(r) = ln::<S, D>(operand)?.checked_mul(exponent.into()) {
303        r
304    } else {
305        return Err(());
306    };
307    let result: D = if let Ok(r) = exp(r) {
308        r
309    } else {
310        return Err(());
311    };
312    let (result, oflw) = result.overflowing_to_num::<D>();
313    if oflw {
314        return Err(());
315    };
316    Ok(result)
317}
318
319/// power with integer exponend
320pub fn powi<S, D>(operand: S, exponent: i32) -> Result<D, ()>
321where
322    S: Fixed + PartialOrd<ConstType>,
323    D: Fixed + PartialOrd<ConstType> + From<S> + From<ConstType>,
324    D::Bits: Copy + ToFixed + AddAssign + BitOrAssign + ShlAssign,
325{
326    if operand == S::from_num(0) {
327        return Ok(D::from_num(0));
328    };
329    if exponent == 0 {
330        return Ok(D::from_num(1));
331    };
332    if exponent == 1 {
333        return Ok(D::from(operand));
334    };
335    let operand = D::from(operand);
336    let mut r = operand;
337
338    for _i in 1..exponent.abs() {
339        r = if let Some(r) = r.checked_mul(operand) {
340            r
341        } else {
342            return Err(());
343        };
344    }
345    if exponent < 0 {
346        r = if let Some(r) = D::from_num(1).checked_div(r) {
347            r
348        } else {
349            return Err(());
350        };
351    }
352    Ok(r)
353}
354
355/// CORDIC in rotation mode.
356fn cordic_rotation<T>(mut x: T, mut y: T, mut z: T) -> (T, T)
357where
358    T: FixedSigned + PartialOrd<ConstType> + LossyFrom<U0F128>,
359{
360    for (angle, i) in ARCTAN_ANGLES.iter().cloned().zip(0..) {
361        let angle = T::lossy_from(angle);
362        //if z == ZERO {
363        //    break;
364        //};
365        if i >= 24 {
366            break;
367        }
368        let prev_x = x;
369        if z < ZERO {
370            x += y >> i;
371            y -= prev_x >> i;
372            z += angle;
373        } else {
374            x -= y >> i;
375            y += prev_x >> i;
376            z -= angle;
377        }
378    }
379    (x, y)
380}
381
382/// sine function in radians
383pub fn sin<T>(mut angle: T) -> T
384where
385    T: FixedSigned
386        + PartialOrd<ConstType>
387        + LossyFrom<ConstType>
388        + LossyFrom<I9F23>
389        + LossyFrom<U0F128>,
390{
391    //wraparound
392    while angle > PI {
393        angle -= T::lossy_from(TWO_PI);
394    }
395    while angle < -PI {
396        angle += T::lossy_from(TWO_PI);
397    }
398    //mirror
399    if angle > FRAC_PI_2 {
400        angle = T::lossy_from(FRAC_PI_2) - (angle - T::lossy_from(FRAC_PI_2));
401    }
402    if angle < -FRAC_PI_2 {
403        angle = -T::lossy_from(FRAC_PI_2) - (angle + T::lossy_from(FRAC_PI_2));
404    }
405
406    //FIXME: find correction factor for constant iterations
407    // now this is optimized for I32F32 type
408    // x0= 1/K with K ~ 1.647 for infinite iterations
409    // dec2hex(round(1 / 1.6467602578923106 * 2^128),32)
410    let x = T::lossy_from(U0F128::from_bits(0x9B74EDA8A01E20000000000000000000));
411    //let x = T::from_num(1);
412    let (_x, y) = cordic_rotation(x, T::from_num(0), angle);
413    y
414}
415
416/// cosine function in radians
417pub fn cos<T>(angle: T) -> T
418where
419    T: FixedSigned
420        + PartialOrd<ConstType>
421        + LossyFrom<ConstType>
422        + LossyFrom<I9F55>
423        + LossyFrom<U0F128>,
424{
425    sin(angle + T::lossy_from(FRAC_PI_2))
426}
427
428/// tangent function in radians
429pub fn tan<T>(mut angle: T) -> T
430where
431    T: FixedSigned
432        + PartialOrd<ConstType>
433        + LossyFrom<ConstType>
434        + LossyFrom<I9F55>
435        + LossyFrom<U0F128>,
436{
437    angle *= T::from_num(2);
438    sin(angle) / (T::from_num(1) + cos(angle))
439}
440
441/// arcsine function in radians
442//FIXME: only valid for very small angles
443pub fn asin<T>(angle: T) -> T {
444    angle
445}
446
447#[cfg(test)]
448mod tests {
449    use super::*;
450    use crate::traits::LossyInto;
451    use crate::types::{I32F32, I64F64, U64F64};
452
453    #[test]
454    fn sqrt_works() {
455        {
456            type S = I9F23;
457            type D = I9F23;
458
459            assert_eq!(sqrt::<S, D>(S::from_num(4)).unwrap(), TWO);
460
461            let result: f64 = sqrt::<S, D>(S::from_num(1)).unwrap().lossy_into();
462            assert_relative_eq!(result, 1.0, epsilon = 1.0e-6);
463            let result: f64 = sqrt::<S, D>(S::from_num(0)).unwrap().lossy_into();
464            assert_relative_eq!(result, 0.0, epsilon = 1.0e-6);
465            let result: f64 = sqrt::<S, D>(S::from_num(0.1_f32)).unwrap().lossy_into();
466            assert_relative_eq!(result, 0.316228, epsilon = 1.0e-4);
467            let result: f64 = sqrt::<S, D>(S::from_num(10)).unwrap().lossy_into();
468            assert_relative_eq!(result, 3.16228, epsilon = 1.0e-4);
469        }
470        {
471            type S = U64F64;
472            type D = U64F64;
473            let result: f64 = sqrt::<S, D>(S::from_num(1)).unwrap().lossy_into();
474            assert_relative_eq!(result, 1.0, epsilon = 1.0e-6);
475        }
476    }
477
478    #[test]
479    fn sqrt_check_lower_bound_of_working_values() {
480        // Todo: This could be done for other types too.
481        type S = I32F32;
482        type D = I32F32;
483
484        // this works
485        let result: f64 = sqrt::<S, D>(S::from_num(5.8208e-10)).unwrap().lossy_into();
486        assert_relative_eq!(result, 0.0000261, epsilon = 1.0e-6);
487
488        // slightly below lower bound that produces an overflow
489        let res = sqrt::<S, D>(S::from_num(5.8205e-10));
490        assert_eq!(res.unwrap_err(), "Overflow inverting operand.")
491    }
492
493    #[test]
494    fn rs_works() {
495        let result: f64 = rs(I9F23::from_num(0)).lossy_into();
496        assert_eq!(result, 0.0);
497        let result: f64 = rs(I9F23::from_num(1)).lossy_into();
498        assert_eq!(result, 0.5);
499        let result: f64 = rs(I9F23::from_num(2)).lossy_into();
500        assert_eq!(result, 1.0);
501        let result: f64 = rs(I9F23::from_num(3)).lossy_into();
502        assert_eq!(result, 1.5);
503        let result: f64 = rs(I9F23::from_num(4)).lossy_into();
504        assert_eq!(result, 2.0);
505        let result: f64 = rs(I9F23::from_num(-1)).lossy_into();
506        assert_eq!(result, -0.5);
507        let result: f64 = rs(I9F23::from_num(-2)).lossy_into();
508        assert_eq!(result, -1.0);
509
510        assert_eq!(rs(I9F23::from_bits(1)).to_bits(), 1);
511        assert_eq!(rs(I9F23::from_bits(2)).to_bits(), 1);
512        assert_eq!(rs(I9F23::from_bits(3)).to_bits(), 2);
513        assert_eq!(rs(I9F23::from_bits(4)).to_bits(), 2);
514    }
515
516    #[test]
517    fn log2_works() {
518        type S = I9F23;
519        type D = I32F32;
520        assert!(log2::<S, D>(S::from_num(0)).is_err());
521
522        assert_eq!(log2::<S, D>(S::from_num(1)).unwrap(), ZERO);
523
524        let result: D = log2::<S, D>(S::from_num(2)).unwrap();
525        let result: f64 = result.lossy_into();
526        assert_relative_eq!(result, 1.0, epsilon = 1.0e-6);
527        let result: D = log2::<S, D>(S::from_num(4)).unwrap();
528        let result: f64 = result.lossy_into();
529        assert_relative_eq!(result, 2.0, epsilon = 1.0e-6);
530        let result: D = log2::<S, D>(S::from_num(3.33333_f64)).unwrap();
531        let result: f64 = result.lossy_into();
532        assert_relative_eq!(result, 1.73696, epsilon = 1.0e-5);
533        let result: D = log2::<S, D>(S::from_num(0.11111_f64)).unwrap();
534        let result: f64 = result.lossy_into();
535        assert_relative_eq!(result, -3.16994, epsilon = 1.0e-2);
536    }
537
538    #[test]
539    fn ln_works() {
540        type S = I9F23;
541        type D = I32F32;
542        assert!(ln::<S, D>(S::from_num(0)).is_err());
543        assert_eq!(ln::<S, D>(S::from_num(1)).unwrap(), ZERO);
544        let result: f64 = ln::<S, D>(E).unwrap().lossy_into();
545        assert_relative_eq!(result, 1.0, epsilon = 1.0e-4);
546        let result: f64 = ln::<S, D>(S::from_num(10)).unwrap().lossy_into();
547        assert_relative_eq!(result, 2.30259, epsilon = 1.0e-4);
548        let result: f64 = ln::<S, D>(S::from_num(0.00001)).unwrap().lossy_into();
549        assert_relative_eq!(result, -11.5129, epsilon = 1.0e-1);
550    }
551
552    #[test]
553    fn exp_works() {
554        type S = I9F23;
555        type D = I32F32;
556
557        let result: f64 = exp::<S, D>(ZERO).unwrap().lossy_into();
558        assert_eq!(result, 1.0);
559
560        let result: f64 = exp::<S, D>(ONE).unwrap().lossy_into();
561        assert_relative_eq!(result, 2.718281828459045235_f64, epsilon = 1.0e-4);
562
563        let result: f64 = exp::<S, D>(S::from_num(5.0)).unwrap().lossy_into();
564        assert_relative_eq!(result, 148.413159, epsilon = 1.0e-1);
565        // overflow if type too small
566        assert!(exp::<S, D>(S::from_num(-23)).is_err());
567        // same is fine with larger destination type
568        let result: f64 = exp::<S, I64F64>(S::from_num(-23)).unwrap().lossy_into();
569        assert_relative_eq!(result, 102.619e-12, epsilon = 1.0e-12);
570    }
571
572    #[test]
573    fn pow_works() {
574        type S = I9F23;
575        type D = I32F32;
576
577        let result: D = pow(ZERO, TWO).unwrap();
578        let result: f64 = result.lossy_into();
579        assert_eq!(result, 0.0);
580
581        let result: D = pow(ONE, TWO).unwrap();
582        let result: f64 = result.lossy_into();
583        assert_eq!(result, 1.0);
584
585        let result: D = pow(TWO, TWO).unwrap();
586        let result: f64 = result.lossy_into();
587        assert_relative_eq!(result, 4.0, epsilon = 1.0e-3);
588        let result: D = pow(TWO, THREE).unwrap();
589        let result: f64 = result.lossy_into();
590        assert_relative_eq!(result, 8.0, epsilon = 1.0e-3);
591        let result: D = pow(S::from_num(2.9), S::from_num(3.1)).unwrap();
592        let result: f64 = result.lossy_into();
593        assert_relative_eq!(result, 27.129, epsilon = 1.0e-2);
594        let result: D = pow(S::from_num(0.0001), S::from_num(2)).unwrap();
595        let result: f64 = result.lossy_into();
596        assert_relative_eq!(result, 0.00000001, epsilon = 1.0e-9);
597
598        // this would lead a complex result due to computation method
599        assert!(pow::<S, D>(S::from_num(-0.0001), S::from_num(2)).is_err());
600    }
601
602    #[test]
603    fn powi_works() {
604        type D = I32F32;
605
606        let result: D = powi(ZERO, 2).unwrap();
607        let result: f64 = result.lossy_into();
608        assert_eq!(result, 0.0);
609
610        let result: D = powi(ONE, 2).unwrap();
611        let result: f64 = result.lossy_into();
612        assert_eq!(result, 1.0);
613
614        let result: D = powi(TWO, 2).unwrap();
615        let result: f64 = result.lossy_into();
616        assert_relative_eq!(result, 4.0, epsilon = 1.0e-3);
617
618        let result: D = powi(TWO, -2).unwrap();
619        let result: f64 = result.lossy_into();
620        assert_relative_eq!(result, 1.0 / 4.0, epsilon = 1.0e-4);
621
622        let result: D = powi(TWO, 3).unwrap();
623        let result: f64 = result.lossy_into();
624        assert_relative_eq!(result, 8.0, epsilon = 1.0e-3);
625    }
626
627    #[test]
628    fn sin_works() {
629        // for correction factor reference
630        let result: f64 = sin(I32F32::lossy_from(FRAC_PI_2)).lossy_into();
631        assert_relative_eq!(result, 1.0, epsilon = 1.0e-5);
632
633        let result: f64 = sin(FRAC_PI_2).lossy_into();
634        assert_relative_eq!(result, 1.0, epsilon = 1.0e-5);
635
636        let result: f64 = sin(I32F32::from_num(0)).lossy_into();
637        assert_relative_eq!(result, 0.0, epsilon = 1.0e-5);
638        let result: f64 = sin(I9F23::from_num(0)).lossy_into();
639        assert_relative_eq!(result, 0.0, epsilon = 1.0e-5);
640        let result: f64 = sin(PI).lossy_into();
641        assert_relative_eq!(result, 0.0, epsilon = 1.0e-5);
642        let result: f64 = sin(PI + FRAC_PI_2).lossy_into();
643        assert_relative_eq!(result, -1.0, epsilon = 1.0e-5);
644        let result: f64 = sin(TWO_PI).lossy_into();
645        assert_relative_eq!(result, 0.0, epsilon = 1.0e-5);
646        let result: f64 = sin(FRAC_PI_4).lossy_into();
647        assert_relative_eq!(result, 0.707107, epsilon = 1.0e-1);
648        let result: f64 = sin(-FRAC_PI_2).lossy_into();
649        assert_relative_eq!(result, -1.0, epsilon = 1.0e-1);
650        let result: f64 = sin(-FRAC_PI_4).lossy_into();
651        assert_relative_eq!(result, -0.707107, epsilon = 1.0e-1);
652        let result: f64 = sin(PI + FRAC_PI_4).lossy_into();
653        assert_relative_eq!(result, -0.707107, epsilon = 1.0e-1);
654        let result: f64 = sin(TWO).lossy_into();
655        assert_relative_eq!(result, 0.909297, epsilon = 1.0e-5);
656        let result: f64 = sin(-TWO).lossy_into();
657        assert_relative_eq!(result, -0.909297, epsilon = 1.0e-5);
658    }
659
660    #[test]
661    fn cos_works() {
662        let result: f64 = cos(I9F23::from_num(0)).lossy_into();
663        assert_relative_eq!(result, 1.0, epsilon = 1.0e-5);
664    }
665
666    #[test]
667    fn tan_works() {
668        let result: f64 = tan(I9F23::from_num(0)).lossy_into();
669        assert_relative_eq!(result, 0.0, epsilon = 1.0e-5);
670
671        let result: f64 = tan(ONE).lossy_into();
672        assert_relative_eq!(result, 1.55741, epsilon = 1.0e-5);
673    }
674
675    #[test]
676    fn asin_works() {
677        let result: f64 = asin(I9F23::from_num(0)).lossy_into();
678        assert_relative_eq!(result, 0.0, epsilon = 1.0e-5);
679        let result: f64 = asin(I9F23::from_num(0.01)).lossy_into();
680        assert_relative_eq!(result, 0.01, epsilon = 1.0e-5);
681    }
682}