Coverage Report

Created: 2025-12-14 07:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/pxfm-0.1.27/src/hyperbolic/sinhf.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, f_fmlaf};
30
use crate::rounding::CpuRoundTiesEven;
31
32
static TB: [u64; 32] = [
33
    0x3fe0000000000000,
34
    0x3fe059b0d3158574,
35
    0x3fe0b5586cf9890f,
36
    0x3fe11301d0125b51,
37
    0x3fe172b83c7d517b,
38
    0x3fe1d4873168b9aa,
39
    0x3fe2387a6e756238,
40
    0x3fe29e9df51fdee1,
41
    0x3fe306fe0a31b715,
42
    0x3fe371a7373aa9cb,
43
    0x3fe3dea64c123422,
44
    0x3fe44e086061892d,
45
    0x3fe4bfdad5362a27,
46
    0x3fe5342b569d4f82,
47
    0x3fe5ab07dd485429,
48
    0x3fe6247eb03a5585,
49
    0x3fe6a09e667f3bcd,
50
    0x3fe71f75e8ec5f74,
51
    0x3fe7a11473eb0187,
52
    0x3fe82589994cce13,
53
    0x3fe8ace5422aa0db,
54
    0x3fe93737b0cdc5e5,
55
    0x3fe9c49182a3f090,
56
    0x3fea5503b23e255d,
57
    0x3feae89f995ad3ad,
58
    0x3feb7f76f2fb5e47,
59
    0x3fec199bdd85529c,
60
    0x3fecb720dcef9069,
61
    0x3fed5818dcfba487,
62
    0x3fedfc97337b9b5f,
63
    0x3feea4afa2a490da,
64
    0x3fef50765b6e4540,
65
];
66
67
#[cold]
68
0
fn sinhf_accurate(z: f64, ia: f64, sp: u64, sm: u64) -> f32 {
69
    const CH: [u64; 7] = [
70
        0x3ff0000000000000,
71
        0x3f962e42fefa39ef,
72
        0x3f2ebfbdff82c58f,
73
        0x3ebc6b08d702e0ed,
74
        0x3e43b2ab6fb92e5e,
75
        0x3dc5d886e6d54203,
76
        0x3d4430976b8ce6ef,
77
    ];
78
    const ILN2H: f64 = f64::from_bits(0x4047154765000000);
79
    const ILN2L: f64 = f64::from_bits(0x3e55c17f0bbbe880);
80
0
    let h = f_fmla(ILN2L, z, f_fmla(ILN2H, z, -ia));
81
0
    let h2 = h * h;
82
83
0
    let q0 = f_fmla(h2, f64::from_bits(CH[6]), f64::from_bits(CH[4]));
84
0
    let q1 = f_fmla(h2, f64::from_bits(CH[2]), f64::from_bits(CH[0]));
85
86
0
    let te = f_fmla(h2 * h2, q0, q1);
87
88
0
    let q2 = f_fmla(h2, f64::from_bits(CH[5]), f64::from_bits(CH[3]));
89
90
0
    let to = f_fmla(h2, q2, f64::from_bits(CH[1]));
91
92
0
    let b0 = f_fmla(h, to, te);
93
0
    let b1 = f_fmla(-h, to, te);
94
95
0
    f_fmla(f64::from_bits(sp), b0, -f64::from_bits(sm) * b1) as f32
96
0
}
97
98
/// Huperbolic sine function
99
///
100
/// Max found ULP 0.4954563
101
#[inline]
102
0
pub fn f_sinhf(x: f32) -> f32 {
103
    const C: [u64; 4] = [
104
        0x3ff0000000000000,
105
        0x3f962e42fef4c4e7,
106
        0x3f2ebfd1b232f475,
107
        0x3ebc6b19384ecd93,
108
    ];
109
110
    const ST: [(u32, u32, u32); 1] = [(0x74250bfeu32, 0x3a1285ff, 0x2d800000)];
111
    const ILN2: f64 = f64::from_bits(0x40471547652b82fe);
112
0
    let t = x.to_bits();
113
0
    let z: f64 = x as f64;
114
0
    let ux = t.wrapping_shl(1);
115
0
    if ux > 0x8565a9f8u32 {
116
        // |x| > 89.416
117
0
        let sgn = f32::copysign(2.0, x);
118
0
        if ux >= 0xff000000u32 {
119
0
            if ux.wrapping_shl(8) != 0 {
120
0
                return x + x;
121
0
            } // nan
122
0
            return sgn * f32::INFINITY; // +-inf
123
0
        }
124
0
        let r = sgn * f64::from_bits(0x47efffffe0000000) as f32;
125
126
0
        return r;
127
0
    }
128
0
    if ux < 0x7c000000u32 {
129
        // |x| < 0.125
130
0
        if ux <= 0x74250bfeu32 {
131
            // |x| <= 0.000558942
132
0
            if ux < 0x66000000u32 {
133
                // |x| < 5.96046e-08
134
                #[cfg(any(
135
                    all(
136
                        any(target_arch = "x86", target_arch = "x86_64"),
137
                        target_feature = "fma"
138
                    ),
139
                    target_arch = "aarch64"
140
                ))]
141
                {
142
                    use crate::common::f_fmlaf;
143
                    return f_fmlaf(x, x.abs(), x);
144
                }
145
                #[cfg(not(any(
146
                    all(
147
                        any(target_arch = "x86", target_arch = "x86_64"),
148
                        target_feature = "fma"
149
                    ),
150
                    target_arch = "aarch64"
151
                )))]
152
                {
153
0
                    let dx = x as f64;
154
0
                    return f_fmla(dx, dx.abs(), dx) as f32;
155
                }
156
0
            }
157
0
            if ST[0].0 == ux {
158
0
                let sgn = f32::copysign(1.0, x);
159
0
                return f_fmlaf(sgn, f32::from_bits(ST[0].1), sgn * f32::from_bits(ST[0].2));
160
0
            }
161
            #[cfg(any(
162
                all(
163
                    any(target_arch = "x86", target_arch = "x86_64"),
164
                    target_feature = "fma"
165
                ),
166
                target_arch = "aarch64"
167
            ))]
168
            {
169
                use crate::common::f_fmlaf;
170
                return f_fmlaf(x * f64::from_bits(0x3fc5555560000000) as f32, x * x, x);
171
            }
172
            #[cfg(not(any(
173
                all(
174
                    any(target_arch = "x86", target_arch = "x86_64"),
175
                    target_feature = "fma"
176
                ),
177
                target_arch = "aarch64"
178
            )))]
179
            {
180
0
                let dx = x as f64;
181
0
                return f_fmla(dx * f64::from_bits(0x3fc5555560000000), dx * dx, dx) as f32;
182
            }
183
0
        }
184
        const CP: [u64; 4] = [
185
            0x3fc5555555555555,
186
            0x3f811111111146e1,
187
            0x3f2a01a00930dda6,
188
            0x3ec71f92198aa6e9,
189
        ];
190
0
        let z2 = z * z;
191
0
        let z4 = z2 * z2;
192
193
0
        let w0 = f_fmla(z2, f64::from_bits(CP[3]), f64::from_bits(CP[2]));
194
0
        let w1 = f_fmla(z2, f64::from_bits(CP[1]), f64::from_bits(CP[0]));
195
0
        let w2 = f_fmla(z4, w0, w1);
196
197
0
        return f_fmla(z2 * z, w2, z) as f32;
198
0
    }
199
0
    let a = ILN2 * z;
200
0
    let ia = a.cpu_round_ties_even();
201
0
    let h = a - ia;
202
0
    let h2 = h * h;
203
0
    let ja = (ia + f64::from_bits(0x4338000000000000)).to_bits();
204
0
    let jp: i64 = ja as i64;
205
0
    let jm = -jp;
206
0
    let sp = TB[(jp & 31) as usize].wrapping_add(jp.wrapping_shr(5).wrapping_shl(52) as u64);
207
0
    let sm = TB[(jm & 31) as usize].wrapping_add(jm.wrapping_shr(5).wrapping_shl(52) as u64);
208
0
    let te = f_fmla(h2, f64::from_bits(C[2]), f64::from_bits(C[0]));
209
0
    let to = f_fmla(h2, f64::from_bits(C[3]), f64::from_bits(C[1]));
210
0
    let rp = f64::from_bits(sp) * f_fmla(h, to, te);
211
0
    let rm = f64::from_bits(sm) * f_fmla(-h, to, te);
212
0
    let r = rp - rm;
213
0
    let ub = r;
214
0
    let lb = r - f64::from_bits(0x3de4e406496685f4) * r;
215
    // Ziv's accuracy test
216
0
    if ub != lb {
217
0
        return sinhf_accurate(z, ia, sp, sm);
218
0
    }
219
0
    ub as f32
220
0
}
221
222
#[cfg(test)]
223
mod tests {
224
    use super::*;
225
226
    #[test]
227
    fn test_sinhf() {
228
        assert_eq!(f_sinhf(-0.5), -0.5210953);
229
        assert_eq!(f_sinhf(0.5), 0.5210953);
230
        assert_eq!(f_sinhf(7.), 548.3161);
231
    }
232
}