1use crate::common::*;
30use crate::logs::logf::{GenLogfBackend, LogfBackend};
31
32static LOG10_R: [u64; 128] = [
33 0x0000000000000000,
34 0x3f6be76bd77b4fc3,
35 0x3f7c03a80ae5e054,
36 0x3f851824c7587eb0,
37 0x3f8c3d0837784c41,
38 0x3f91b85d6044e9ae,
39 0x3f9559bd2406c3ba,
40 0x3f9902c31d62a843,
41 0x3f9cb38fccd8bfdb,
42 0x3f9e8eeb09f2f6cb,
43 0x3fa125d0432ea20e,
44 0x3fa30838cdc2fbfd,
45 0x3fa3faf7c663060e,
46 0x3fa5e3966b7e9295,
47 0x3fa7d070145f4fd7,
48 0x3fa8c878eeb05074,
49 0x3faabbcebd84fca0,
50 0x3fabb7209d1e24e5,
51 0x3fadb11ed766abf4,
52 0x3faeafd05035bd3b,
53 0x3fb0585283764178,
54 0x3fb0d966cc6500fa,
55 0x3fb1dd5460c8b16f,
56 0x3fb2603072a25f82,
57 0x3fb367ba3aaa1883,
58 0x3fb3ec6ad5407868,
59 0x3fb4f7aad9bbcbaf,
60 0x3fb57e3d47c3af7b,
61 0x3fb605735ee985f1,
62 0x3fb715d0ce367afc,
63 0x3fb79efb57b0f803,
64 0x3fb828cfed29a215,
65 0x3fb93e7de0fc3e80,
66 0x3fb9ca5aa1729f45,
67 0x3fba56e8325f5c87,
68 0x3fbae4285509950b,
69 0x3fbb721cd17157e3,
70 0x3fbc902a19e65111,
71 0x3fbd204698cb42bd,
72 0x3fbdb11ed766abf4,
73 0x3fbe42b4c16caaf3,
74 0x3fbed50a4a26eafc,
75 0x3fbffbfc2bbc7803,
76 0x3fc0484e4942aa43,
77 0x3fc093025a19976c,
78 0x3fc0de1b56356b04,
79 0x3fc1299a4fb3e306,
80 0x3fc175805d1587c1,
81 0x3fc1c1ce9955c0c6,
82 0x3fc20e8624038fed,
83 0x3fc25ba8215af7fc,
84 0x3fc2a935ba5f1479,
85 0x3fc2f7301cf4e87b,
86 0x3fc345987bfeea91,
87 0x3fc394700f7953fd,
88 0x3fc3e3b8149739d4,
89 0x3fc43371cde076c2,
90 0x3fc4839e83506c87,
91 0x3fc4d43f8275a483,
92 0x3fc525561e9256ee,
93 0x3fc576e3b0bde0a7,
94 0x3fc5c8e998072fe2,
95 0x3fc61b6939983048,
96 0x3fc66e6400da3f77,
97 0x3fc6c1db5f9bb336,
98 0x3fc6c1db5f9bb336,
99 0x3fc715d0ce367afc,
100 0x3fc76a45cbb7e6ff,
101 0x3fc7bf3bde099f30,
102 0x3fc814b4921bd52b,
103 0x3fc86ab17c10bc7f,
104 0x3fc86ab17c10bc7f,
105 0x3fc8c13437695532,
106 0x3fc9183e673394fa,
107 0x3fc96fd1b639fc09,
108 0x3fc9c7efd734a2f9,
109 0x3fca209a84fbcff8,
110 0x3fca209a84fbcff8,
111 0x3fca79d382bc21d9,
112 0x3fcad39c9c2c6080,
113 0x3fcb2df7a5c50299,
114 0x3fcb2df7a5c50299,
115 0x3fcb88e67cf97980,
116 0x3fcbe46b087354bc,
117 0x3fcc4087384f4f80,
118 0x3fcc4087384f4f80,
119 0x3fcc9d3d065c5b42,
120 0x3fccfa8e765cbb72,
121 0x3fccfa8e765cbb72,
122 0x3fcd587d96494759,
123 0x3fcdb70c7e96e7f3,
124 0x3fcdb70c7e96e7f3,
125 0x3fce163d527e68cf,
126 0x3fce76124046b3f3,
127 0x3fce76124046b3f3,
128 0x3fced68d819191fc,
129 0x3fcf37b15bab08d1,
130 0x3fcf37b15bab08d1,
131 0x3fcf99801fdb749d,
132 0x3fcffbfc2bbc7803,
133 0x3fcffbfc2bbc7803,
134 0x3fd02f93f4c87101,
135 0x3fd06182e84fd4ac,
136 0x3fd06182e84fd4ac,
137 0x3fd093cc32c90f84,
138 0x3fd093cc32c90f84,
139 0x3fd0c6711d6abd7a,
140 0x3fd0f972f87ff3d6,
141 0x3fd0f972f87ff3d6,
142 0x3fd12cd31b9c99ff,
143 0x3fd12cd31b9c99ff,
144 0x3fd16092e5d3a9a6,
145 0x3fd194b3bdef6b9e,
146 0x3fd194b3bdef6b9e,
147 0x3fd1c93712abc7ff,
148 0x3fd1c93712abc7ff,
149 0x3fd1fe1e5af2c141,
150 0x3fd1fe1e5af2c141,
151 0x3fd2336b161b3337,
152 0x3fd2336b161b3337,
153 0x3fd2691ecc29f042,
154 0x3fd2691ecc29f042,
155 0x3fd29f3b0e15584b,
156 0x3fd29f3b0e15584b,
157 0x3fd2d5c1760b86bb,
158 0x3fd2d5c1760b86bb,
159 0x3fd30cb3a7bb3625,
160 0x3fd34413509f79ff,
161];
162
163#[inline(always)]
164fn log10f_gen<B: LogfBackend>(x: f32, backend: B) -> f32 {
165 let mut x_u = x.to_bits();
166
167 const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32;
168
169 let mut m = -(E_BIAS as i32);
170 if x_u < f32::MIN_POSITIVE.to_bits() || x_u > f32::MAX.to_bits() {
171 if x == 0.0 {
172 return f32::NEG_INFINITY;
173 }
174 if x_u == 0x80000000u32 {
175 return f32::NEG_INFINITY;
176 }
177 if x.is_sign_negative() && !x.is_nan() {
178 return f32::NAN + x;
179 }
180 if x.is_nan() || x.is_infinite() {
182 return x + x;
183 }
184 x_u = (x * f64::from_bits(0x4160000000000000) as f32).to_bits();
186 m -= 23;
187 }
188
189 m = m.wrapping_add(x_u.wrapping_shr(23) as i32);
190 let index = (x_u >> 16) & 0x7F;
191 x_u = set_exponent_f32(x_u, 0x7F);
192
193 let u = f32::from_bits(x_u);
194
195 let v = if B::HAS_FMA {
196 backend.fmaf(
197 u,
198 f32::from_bits(crate::logs::logf::LOG_REDUCTION_F32.0[index as usize]),
199 -1.0,
200 ) as f64 } else {
202 backend.fma(
203 u as f64,
204 f32::from_bits(crate::logs::logf::LOG_REDUCTION_F32.0[index as usize]) as f64,
205 -1.0,
206 ) };
208 const COEFFS: [u64; 5] = [
211 0x3fdbcb7b1526e2e5,
212 0xbfcbcb7b1528d43d,
213 0x3fc287a77eb4ca0d,
214 0xbfbbcb8110a181b5,
215 0x3fb60e7e3e747129,
216 ];
217 let v2 = v * v; let p2 = backend.fma(v, f64::from_bits(COEFFS[4]), f64::from_bits(COEFFS[3]));
219 let p1 = backend.fma(v, f64::from_bits(COEFFS[2]), f64::from_bits(COEFFS[1]));
220 let p0 = backend.fma(
221 v,
222 f64::from_bits(COEFFS[0]),
223 f64::from_bits(LOG10_R[index as usize]),
224 );
225 const LOG_10_2: f64 = f64::from_bits(0x3fd34413509f79ff);
226 let r = backend.fma(m as f64, LOG_10_2, backend.polyeval3(v2, p0, p1, p2));
227 r as f32
228}
229
230#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
231#[target_feature(enable = "avx", enable = "fma")]
232unsafe fn log10f_fma_impl(x: f32) -> f32 {
233 use crate::logs::logf::FmaLogfBackend;
234 log10f_gen(x, FmaLogfBackend {})
235}
236
237pub fn f_log10f(x: f32) -> f32 {
241 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
242 {
243 log10f_gen(x, GenLogfBackend {})
244 }
245 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
246 {
247 use std::sync::OnceLock;
248 static EXECUTOR: OnceLock<unsafe fn(f32) -> f32> = OnceLock::new();
249 let q = EXECUTOR.get_or_init(|| {
250 if std::arch::is_x86_feature_detected!("avx")
251 && std::arch::is_x86_feature_detected!("fma")
252 {
253 log10f_fma_impl
254 } else {
255 fn def_log10f(x: f32) -> f32 {
256 log10f_gen(x, GenLogfBackend {})
257 }
258 def_log10f
259 }
260 });
261 unsafe { q(x) }
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn test_log10f() {
271 assert_eq!(f_log10f(0.35), -0.45593196f32);
272 assert_eq!(f_log10f(0.9), -4.5757502e-2);
273 assert_eq!(f_log10f(10.), 1.);
274 assert_eq!(f_log10f(100.), 2.);
275 assert_eq!(f_log10f(0.), f32::NEG_INFINITY);
276 assert!(f_log10f(-1.).is_nan());
277 assert!(f_log10f(f32::NAN).is_nan());
278 assert!(f_log10f(f32::NEG_INFINITY).is_nan());
279 assert_eq!(f_log10f(f32::INFINITY), f32::INFINITY);
280 }
281}