1use crate::common::{f_fmla, is_integerf};
30use crate::polyeval::f_polyeval5;
31use crate::sin_cosf::sincosf_eval::sincospif_eval;
32
33#[inline(always)]
34fn sincpif_gen_impl(x: f32) -> f32 {
35 let x_abs = x.to_bits() & 0x7fff_ffffu32;
36 let xd = x as f64;
37
38 if x_abs <= 0x3d80_0000u32 {
39 if x_abs < 0x3580_2126u32 {
41 if x_abs == 0u32 {
43 return 1.;
45 }
46
47 #[cfg(any(
50 all(
51 any(target_arch = "x86", target_arch = "x86_64"),
52 target_feature = "fma"
53 ),
54 target_arch = "aarch64"
55 ))]
56 {
57 use crate::common::f_fmlaf;
58 const M_SQR_PI_OVER_6: f32 = f32::from_bits(0xbfd28d33);
59 return f_fmlaf(x, M_SQR_PI_OVER_6 * x, 1.);
60 }
61 #[cfg(not(any(
62 all(
63 any(target_arch = "x86", target_arch = "x86_64"),
64 target_feature = "fma"
65 ),
66 target_arch = "aarch64"
67 )))]
68 {
69 const M_SQR_PI_OVER_6: f64 = f64::from_bits(0xbffa51a6625307d3);
70 let x2 = xd * xd;
71 let p = f_fmla(x2, M_SQR_PI_OVER_6, 1.);
72 return p as f32;
73 }
74 }
75
76 let xsqr = xd * xd;
77
78 let p = f_polyeval5(
84 xsqr,
85 f64::from_bits(0x3ff0000000000000),
86 f64::from_bits(0xbffa51a662530723),
87 f64::from_bits(0x3fe9f9cb401e8e85),
88 f64::from_bits(0xbfc86a8da89c9234),
89 f64::from_bits(0x3f9ac0a16798157e),
90 );
91 return p as f32;
92 }
93
94 if x_abs >= 0x4b00_0000u32 || is_integerf(x) {
97 if x_abs >= 0x7f80_0000u32 {
98 return x + f32::NAN;
99 }
100 return if x.is_sign_negative() { -0. } else { 0. };
101 }
102
103 const PI: f64 = f64::from_bits(0x400921fb54442d18);
104 let rs = sincospif_eval(xd);
105 let sf = f_fmla(rs.sin_y, rs.cos_k, f_fmla(rs.cosm1_y, rs.sin_k, rs.sin_k));
106 (sf / (PI * xd)) as f32
107}
108
109#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
110#[target_feature(enable = "avx", enable = "fma")]
111unsafe fn sincpif_fma_impl(x: f32) -> f32 {
112 let x_abs = x.to_bits() & 0x7fff_ffffu32;
113 let xd = x as f64;
114
115 if x_abs <= 0x3d80_0000u32 {
116 if x_abs < 0x3580_2126u32 {
118 if x_abs == 0u32 {
120 return 1.;
122 }
123
124 const M_SQR_PI_OVER_6: f32 = f32::from_bits(0xbfd28d33);
127 return f32::mul_add(x, M_SQR_PI_OVER_6 * x, 1.);
128 }
129
130 let xsqr = xd * xd;
131
132 use crate::polyeval::d_polyeval5;
138 let p = d_polyeval5(
139 xsqr,
140 f64::from_bits(0x3ff0000000000000),
141 f64::from_bits(0xbffa51a662530723),
142 f64::from_bits(0x3fe9f9cb401e8e85),
143 f64::from_bits(0xbfc86a8da89c9234),
144 f64::from_bits(0x3f9ac0a16798157e),
145 );
146 return p as f32;
147 }
148
149 if x_abs >= 0x4b00_0000u32 || x == x.round_ties_even() {
152 if x_abs >= 0x7f80_0000u32 {
153 return x + f32::NAN;
154 }
155 return if x.is_sign_negative() { -0. } else { 0. };
156 }
157
158 const PI: f64 = f64::from_bits(0x400921fb54442d18);
159 use crate::sin_cosf::sincosf_eval::sincospif_eval_fma;
160 let rs = sincospif_eval_fma(xd);
161 let sf = f64::mul_add(
162 rs.sin_y,
163 rs.cos_k,
164 f64::mul_add(rs.cosm1_y, rs.sin_k, rs.sin_k),
165 );
166 (sf / (PI * xd)) as f32
167}
168
169pub fn f_sincpif(x: f32) -> f32 {
175 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
176 {
177 sincpif_gen_impl(x)
178 }
179 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
180 {
181 use std::sync::OnceLock;
182 static EXECUTOR: OnceLock<unsafe fn(f32) -> f32> = OnceLock::new();
183 let q = EXECUTOR.get_or_init(|| {
184 if std::arch::is_x86_feature_detected!("avx")
185 && std::arch::is_x86_feature_detected!("fma")
186 {
187 sincpif_fma_impl
188 } else {
189 sincpif_gen_impl
190 }
191 });
192 unsafe { q(x) }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_sincpif_eval() {
202 assert_eq!(f_sincpif(1.0), 0.);
203 assert_eq!(f_sincpif(2.0), 0.);
204 assert_eq!(f_sincpif(3.0), 0.);
205 assert_eq!(f_sincpif(0.0543242), 0.99515265);
206 assert_eq!(f_sincpif(0.002134242), 0.9999925);
207 assert_eq!(f_sincpif(0.00000005421321), 1.0);
208 assert!(f_sincpif(f32::INFINITY).is_nan());
209 assert!(f_sincpif(f32::NEG_INFINITY).is_nan());
210 assert!(f_sincpif(f32::NAN).is_nan());
211 }
212}