Coverage Report

Created: 2025-10-14 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.25/src/tangent/tanf.rs
Line
Count
Source
1
/*
2
 * // Copyright (c) Radzivon Bartoshyk 6/2025. All rights reserved.
3
 * //
4
 * // Redistribution and use in source and binary forms, with or without modification,
5
 * // are permitted provided that the following conditions are met:
6
 * //
7
 * // 1.  Redistributions of source code must retain the above copyright notice, this
8
 * // list of conditions and the following disclaimer.
9
 * //
10
 * // 2.  Redistributions in binary form must reproduce the above copyright notice,
11
 * // this list of conditions and the following disclaimer in the documentation
12
 * // and/or other materials provided with the distribution.
13
 * //
14
 * // 3.  Neither the name of the copyright holder nor the names of its
15
 * // contributors may be used to endorse or promote products derived from
16
 * // this software without specific prior written permission.
17
 * //
18
 * // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
 * // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
 * // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
 * // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
 * // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
 * // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
 * // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
use crate::common::f_fmla;
30
use crate::polyeval::f_polyeval5;
31
use crate::tangent::evalf::tanf_eval;
32
33
/// Computes tan
34
///
35
/// Max found ULP 0.4999999
36
#[inline]
37
0
pub fn f_tanf(x: f32) -> f32 {
38
0
    let x_abs = x.to_bits() & 0x7fff_ffffu32;
39
0
    let xd = x as f64;
40
41
    // |x| < pi/32
42
0
    if x_abs <= 0x3dc9_0fdbu32 {
43
        // |x| < 0.000244141
44
0
        if x_abs < 0x3980_0000u32 {
45
0
            if x_abs == 0 {
46
0
                return x;
47
0
            }
48
49
            // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x
50
            // is:
51
            //   |tan(x) - x| / |tan(x)| < |x^3| / (3|x|)
52
            //                           = x^2 / 3
53
            //                           < 2^-25
54
            //                           < epsilon(1)/2.
55
            #[cfg(any(
56
                all(
57
                    any(target_arch = "x86", target_arch = "x86_64"),
58
                    target_feature = "fma"
59
                ),
60
                target_arch = "aarch64"
61
            ))]
62
            {
63
                use crate::common::f_fmlaf;
64
                return f_fmlaf(x, f32::from_bits(0xb3000000), x);
65
            }
66
            #[cfg(not(any(
67
                all(
68
                    any(target_arch = "x86", target_arch = "x86_64"),
69
                    target_feature = "fma"
70
                ),
71
                target_arch = "aarch64"
72
            )))]
73
            {
74
0
                return f_fmla(xd, f64::from_bits(0xbe60000000000000), xd) as f32;
75
            }
76
0
        }
77
78
0
        let xsqr = xd * xd;
79
80
        /*
81
           Generated by Sollya:
82
           f_tan = tan(x)/x;
83
           Q = fpminimax(f_tan, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]);
84
85
           See ./notes/tanf_at_zero.sollya
86
        */
87
0
        let p = f_polyeval5(
88
0
            xsqr,
89
0
            f64::from_bits(0x3ff0000000000000),
90
0
            f64::from_bits(0x3fd555555553d022),
91
0
            f64::from_bits(0x3fc111111ce442c1),
92
0
            f64::from_bits(0x3faba180a6bbdecd),
93
0
            f64::from_bits(0x3f969c0a88a0b71f),
94
        );
95
0
        return (xd * p) as f32;
96
0
    }
97
98
0
    if x_abs >= 0x7f80_0000u32 {
99
0
        return x + f32::NAN;
100
0
    }
101
102
    // For |x| >= pi/32, we use the definition of tan(x) function:
103
    // tan(a+b) = (tan(a) + tan(b)) / (1 - tan(a)tan(b))
104
    // tanf_eval returns:
105
    // - rs.tan_y = tan(pi/32 * y)          -> tangent of the remainder
106
    // - rs.tan_k = tan(pi/32 * k)          -> tan of the main angle multiple
107
0
    let rs = tanf_eval(xd, x_abs);
108
109
    // Then computing tan through identities
110
    // num = tan(k*pi/32) + tan(y*pi/32)
111
0
    let num = rs.tan_y + rs.tan_k;
112
    // den = 1 - tan(k*pi/32) * tan(y*pi/32)
113
0
    let den = f_fmla(rs.tan_y, -rs.tan_k, 1.);
114
0
    (num / den) as f32
115
0
}
116
117
#[cfg(test)]
118
mod tests {
119
    use super::*;
120
121
    #[test]
122
    fn f_tanf_test() {
123
        assert_eq!(f_tanf(0.0), 0.0);
124
        assert_eq!(f_tanf(1.0), 1.5574077);
125
        assert_eq!(f_tanf(-1.0), -1.5574077);
126
        assert_eq!(f_tanf(10.0), 0.64836085);
127
        assert_eq!(f_tanf(-10.0), -0.64836085);
128
    }
129
}