1use crate::common::{f_fmla, f_fmlaf};
30use crate::round_ties_even::RoundTiesEven;
31
32static 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]
68fn 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 let h = f_fmla(ILN2L, z, f_fmla(ILN2H, z, -ia));
81 let h2 = h * h;
82
83 let q0 = f_fmla(h2, f64::from_bits(CH[6]), f64::from_bits(CH[4]));
84 let q1 = f_fmla(h2, f64::from_bits(CH[2]), f64::from_bits(CH[0]));
85
86 let te = f_fmla(h2 * h2, q0, q1);
87
88 let q2 = f_fmla(h2, f64::from_bits(CH[5]), f64::from_bits(CH[3]));
89
90 let to = f_fmla(h2, q2, f64::from_bits(CH[1]));
91
92 let b0 = f_fmla(h, to, te);
93 let b1 = f_fmla(-h, to, te);
94
95 f_fmla(f64::from_bits(sp), b0, -f64::from_bits(sm) * b1) as f32
96}
97
98#[inline]
102pub 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 let t = x.to_bits();
113 let z: f64 = x as f64;
114 let ux = t.wrapping_shl(1);
115 if ux > 0x8565a9f8u32 {
116 let sgn = f32::copysign(2.0, x);
118 if ux >= 0xff000000u32 {
119 if ux.wrapping_shl(8) != 0 {
120 return x + x;
121 } return sgn * f32::INFINITY; }
124 let r = sgn * f64::from_bits(0x47efffffe0000000) as f32;
125
126 return r;
127 }
128 if ux < 0x7c000000u32 {
129 if ux <= 0x74250bfeu32 {
131 if ux < 0x66000000u32 {
133 return f_fmlaf(x, x.abs(), x);
135 }
136 if ST[0].0 == ux {
137 let sgn = f32::copysign(1.0, x);
138 return f_fmlaf(sgn, f32::from_bits(ST[0].1), sgn * f32::from_bits(ST[0].2));
139 }
140 return f_fmlaf(x * f64::from_bits(0x3fc5555560000000) as f32, x * x, x);
141 }
142 const CP: [u64; 4] = [
143 0x3fc5555555555555,
144 0x3f811111111146e1,
145 0x3f2a01a00930dda6,
146 0x3ec71f92198aa6e9,
147 ];
148 let z2 = z * z;
149 let z4 = z2 * z2;
150
151 let w0 = f_fmla(z2, f64::from_bits(CP[3]), f64::from_bits(CP[2]));
152 let w1 = f_fmla(z2, f64::from_bits(CP[1]), f64::from_bits(CP[0]));
153 let w2 = f_fmla(z4, w0, w1);
154
155 return f_fmla(z2 * z, w2, z) as f32;
156 }
157 let a = ILN2 * z;
158 let ia = a.round_ties_even_finite();
159 let h = a - ia;
160 let h2 = h * h;
161 let ja = (ia + f64::from_bits(0x4338000000000000)).to_bits();
162 let jp: i64 = ja as i64;
163 let jm = -jp;
164 let sp = TB[(jp & 31) as usize].wrapping_add(jp.wrapping_shr(5).wrapping_shl(52) as u64);
165 let sm = TB[(jm & 31) as usize].wrapping_add(jm.wrapping_shr(5).wrapping_shl(52) as u64);
166 let te = f_fmla(h2, f64::from_bits(C[2]), f64::from_bits(C[0]));
167 let to = f_fmla(h2, f64::from_bits(C[3]), f64::from_bits(C[1]));
168 let rp = f64::from_bits(sp) * f_fmla(h, to, te);
169 let rm = f64::from_bits(sm) * f_fmla(-h, to, te);
170 let r = rp - rm;
171 let ub = r;
172 let lb = r - f64::from_bits(0x3de4e406496685f4) * r;
173 if ub != lb {
175 return sinhf_accurate(z, ia, sp, sm);
176 }
177 ub as f32
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_sinhf() {
186 assert_eq!(f_sinhf(-0.5), -0.5210953);
187 assert_eq!(f_sinhf(0.5), 0.5210953);
188 assert_eq!(f_sinhf(7.), 548.3161);
189 }
190}