1#![allow(clippy::too_many_arguments)]
30use crate::bits::biased_exponent_f64;
31use crate::common::*;
32use crate::double_double::DoubleDouble;
33use crate::exponents::expf;
34use crate::logf;
35use crate::logs::LOG2_R;
36use crate::pow_tables::EXP2_MID1;
37use crate::powf_tables::{LOG2_R_TD, LOG2_R2_DD, POWF_R2};
38use crate::rounding::CpuRound;
39
40pub const fn powf(d: f32, n: f32) -> f32 {
43 let value = d.abs();
44 let c = expf(n * logf(value));
45 if n == 1. {
46 return d;
47 }
48 if d < 0.0 {
49 let y = n as i32;
50 if y % 2 == 0 { c } else { -c }
51 } else {
52 c
53 }
54}
55
56pub(crate) trait PowfBackend {
57 fn fmaf(&self, x: f32, y: f32, z: f32) -> f32;
58 fn fma(&self, x: f64, y: f64, z: f64) -> f64;
59 fn polyeval3(&self, x: f64, a0: f64, a1: f64, a2: f64) -> f64;
60 fn integerf(&self, x: f32) -> bool;
61 fn odd_integerf(&self, x: f32) -> bool;
62 fn round(&self, x: f64) -> f64;
63 fn quick_mult(&self, x: DoubleDouble, y: DoubleDouble) -> DoubleDouble;
64 fn quick_mult_f64(&self, x: DoubleDouble, y: f64) -> DoubleDouble;
65 fn dd_polyeval6(
66 &self,
67 x: DoubleDouble,
68 a0: DoubleDouble,
69 a1: DoubleDouble,
70 a2: DoubleDouble,
71 a3: DoubleDouble,
72 a4: DoubleDouble,
73 a5: DoubleDouble,
74 ) -> DoubleDouble;
75 fn dd_polyeval10(
76 &self,
77 x: DoubleDouble,
78 a0: DoubleDouble,
79 a1: DoubleDouble,
80 a2: DoubleDouble,
81 a3: DoubleDouble,
82 a4: DoubleDouble,
83 a5: DoubleDouble,
84 a6: DoubleDouble,
85 a7: DoubleDouble,
86 a8: DoubleDouble,
87 a9: DoubleDouble,
88 ) -> DoubleDouble;
89 const HAS_FMA: bool;
90 const ERR: u64;
91}
92
93pub(crate) struct GenPowfBackend {}
94
95impl PowfBackend for GenPowfBackend {
96 #[inline(always)]
97 fn fmaf(&self, x: f32, y: f32, z: f32) -> f32 {
98 f_fmlaf(x, y, z)
99 }
100
101 #[inline(always)]
102 fn fma(&self, x: f64, y: f64, z: f64) -> f64 {
103 f_fmla(x, y, z)
104 }
105
106 #[inline(always)]
107 fn polyeval3(&self, x: f64, a0: f64, a1: f64, a2: f64) -> f64 {
108 use crate::polyeval::f_polyeval3;
109 f_polyeval3(x, a0, a1, a2)
110 }
111
112 #[inline(always)]
113 fn integerf(&self, x: f32) -> bool {
114 is_integerf(x)
115 }
116
117 #[inline(always)]
118 fn odd_integerf(&self, x: f32) -> bool {
119 is_odd_integerf(x)
120 }
121
122 #[inline(always)]
123 fn round(&self, x: f64) -> f64 {
124 x.cpu_round()
125 }
126
127 #[inline(always)]
128 fn quick_mult(&self, x: DoubleDouble, y: DoubleDouble) -> DoubleDouble {
129 DoubleDouble::quick_mult(x, y)
130 }
131
132 #[inline(always)]
133 fn quick_mult_f64(&self, x: DoubleDouble, y: f64) -> DoubleDouble {
134 DoubleDouble::quick_mult_f64(x, y)
135 }
136
137 #[inline(always)]
138 fn dd_polyeval6(
139 &self,
140 x: DoubleDouble,
141 a0: DoubleDouble,
142 a1: DoubleDouble,
143 a2: DoubleDouble,
144 a3: DoubleDouble,
145 a4: DoubleDouble,
146 a5: DoubleDouble,
147 ) -> DoubleDouble {
148 use crate::polyeval::dd_quick_polyeval6;
149 dd_quick_polyeval6(x, a0, a1, a2, a3, a4, a5)
150 }
151
152 #[inline(always)]
153 fn dd_polyeval10(
154 &self,
155 x: DoubleDouble,
156 a0: DoubleDouble,
157 a1: DoubleDouble,
158 a2: DoubleDouble,
159 a3: DoubleDouble,
160 a4: DoubleDouble,
161 a5: DoubleDouble,
162 a6: DoubleDouble,
163 a7: DoubleDouble,
164 a8: DoubleDouble,
165 a9: DoubleDouble,
166 ) -> DoubleDouble {
167 use crate::polyeval::dd_quick_polyeval10;
168 dd_quick_polyeval10(x, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
169 }
170
171 #[cfg(any(
172 all(
173 any(target_arch = "x86", target_arch = "x86_64"),
174 target_feature = "fma"
175 ),
176 target_arch = "aarch64"
177 ))]
178 const HAS_FMA: bool = true;
179 #[cfg(not(any(
180 all(
181 any(target_arch = "x86", target_arch = "x86_64"),
182 target_feature = "fma"
183 ),
184 target_arch = "aarch64"
185 )))]
186 const HAS_FMA: bool = false;
187 #[cfg(any(
188 all(
189 any(target_arch = "x86", target_arch = "x86_64"),
190 target_feature = "fma"
191 ),
192 target_arch = "aarch64"
193 ))]
194 const ERR: u64 = 64;
195 #[cfg(not(any(
196 all(
197 any(target_arch = "x86", target_arch = "x86_64"),
198 target_feature = "fma"
199 ),
200 target_arch = "aarch64"
201 )))]
202 const ERR: u64 = 128;
203}
204
205#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
206pub(crate) struct FmaPowfBackend {}
207
208#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
209impl PowfBackend for FmaPowfBackend {
210 #[inline(always)]
211 fn fmaf(&self, x: f32, y: f32, z: f32) -> f32 {
212 f32::mul_add(x, y, z)
213 }
214
215 #[inline(always)]
216 fn fma(&self, x: f64, y: f64, z: f64) -> f64 {
217 f64::mul_add(x, y, z)
218 }
219
220 #[inline(always)]
221 fn polyeval3(&self, x: f64, a0: f64, a1: f64, a2: f64) -> f64 {
222 use crate::polyeval::d_polyeval3;
223 d_polyeval3(x, a0, a1, a2)
224 }
225
226 #[inline(always)]
227 fn integerf(&self, x: f32) -> bool {
228 x.round_ties_even() == x
229 }
230
231 #[inline(always)]
232 fn odd_integerf(&self, x: f32) -> bool {
233 use crate::common::is_odd_integerf_fast;
234 is_odd_integerf_fast(x)
235 }
236
237 #[inline(always)]
238 fn round(&self, x: f64) -> f64 {
239 x.round()
240 }
241
242 #[inline(always)]
243 fn quick_mult(&self, x: DoubleDouble, y: DoubleDouble) -> DoubleDouble {
244 DoubleDouble::quick_mult_fma(x, y)
245 }
246
247 #[inline(always)]
248 fn quick_mult_f64(&self, x: DoubleDouble, y: f64) -> DoubleDouble {
249 DoubleDouble::quick_mult_f64_fma(x, y)
250 }
251
252 #[inline(always)]
253 fn dd_polyeval6(
254 &self,
255 x: DoubleDouble,
256 a0: DoubleDouble,
257 a1: DoubleDouble,
258 a2: DoubleDouble,
259 a3: DoubleDouble,
260 a4: DoubleDouble,
261 a5: DoubleDouble,
262 ) -> DoubleDouble {
263 use crate::polyeval::dd_quick_polyeval6_fma;
264 dd_quick_polyeval6_fma(x, a0, a1, a2, a3, a4, a5)
265 }
266
267 #[inline(always)]
268 fn dd_polyeval10(
269 &self,
270 x: DoubleDouble,
271 a0: DoubleDouble,
272 a1: DoubleDouble,
273 a2: DoubleDouble,
274 a3: DoubleDouble,
275 a4: DoubleDouble,
276 a5: DoubleDouble,
277 a6: DoubleDouble,
278 a7: DoubleDouble,
279 a8: DoubleDouble,
280 a9: DoubleDouble,
281 ) -> DoubleDouble {
282 use crate::polyeval::dd_quick_polyeval10_fma;
283 dd_quick_polyeval10_fma(x, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9)
284 }
285
286 const HAS_FMA: bool = true;
287
288 const ERR: u64 = 64;
289}
290
291#[inline]
292const fn larger_exponent(a: f64, b: f64) -> bool {
293 biased_exponent_f64(a) >= biased_exponent_f64(b)
294}
295
296#[cold]
304#[inline(always)]
305fn powf_dd<B: PowfBackend>(
306 idx_x: i32,
307 dx: f64,
308 y6: f64,
309 lo6_hi: f64,
310 exp2_hi_mid: DoubleDouble,
311 backend: &B,
312) -> f64 {
313 let idx2 = backend.round(backend.fma(
319 dx,
320 f64::from_bits(0x40d0000000000000),
321 f64::from_bits(0x4050000000000000),
322 )) as usize;
323 let dx2 = backend.fma(1.0 + dx, f64::from_bits(POWF_R2[idx2]), -1.0); const COEFFS: [(u64, u64); 6] = [
326 (0x3c7777d0ffda25e0, 0x3ff71547652b82fe),
327 (0xbc6777d101cf0a84, 0xbfe71547652b82fe),
328 (0x3c7ce04b5140d867, 0x3fdec709dc3a03fd),
329 (0x3c7137b47e635be5, 0xbfd71547652b82fb),
330 (0xbc5b5a30b3bdb318, 0x3fd2776c516a92a2),
331 (0x3c62d2fbd081e657, 0xbfcec70af1929ca6),
332 ];
333 let dx_dd = DoubleDouble::new(0.0, dx2);
334 let p = backend.dd_polyeval6(
335 dx_dd,
336 DoubleDouble::from_bit_pair(COEFFS[0]),
337 DoubleDouble::from_bit_pair(COEFFS[1]),
338 DoubleDouble::from_bit_pair(COEFFS[2]),
339 DoubleDouble::from_bit_pair(COEFFS[3]),
340 DoubleDouble::from_bit_pair(COEFFS[4]),
341 DoubleDouble::from_bit_pair(COEFFS[5]),
342 );
343 let log2_x_lo = backend.quick_mult_f64(p, dx2);
345 let log2_r_td = LOG2_R_TD[idx_x as usize];
347 let log2_x_mid = DoubleDouble::new(f64::from_bits(log2_r_td.0), f64::from_bits(log2_r_td.1));
348 let log2_x_m = DoubleDouble::add(DoubleDouble::from_bit_pair(LOG2_R2_DD[idx2]), log2_x_mid);
350 let log2_x = if larger_exponent(log2_x_m.hi, log2_x_lo.hi) {
354 DoubleDouble::add(log2_x_m, log2_x_lo)
355 } else {
356 DoubleDouble::add(log2_x_lo, log2_x_m)
357 };
358 let lo6_hi_dd = DoubleDouble::new(0.0, lo6_hi);
359 let prod = backend.quick_mult_f64(log2_x, y6);
361 let lo6 = if larger_exponent(prod.hi, lo6_hi) {
363 DoubleDouble::add(prod, lo6_hi_dd)
364 } else {
365 DoubleDouble::add(lo6_hi_dd, prod)
366 };
367
368 const EXP2_COEFFS: [(u64, u64); 10] = [
369 (0x0000000000000000, 0x3ff0000000000000),
370 (0x3c1abc9e3b398024, 0x3f862e42fefa39ef),
371 (0xbba5e43a5429bddb, 0x3f0ebfbdff82c58f),
372 (0xbb2d33162491268f, 0x3e8c6b08d704a0c0),
373 (0x3a94fb32d240a14e, 0x3e03b2ab6fba4e77),
374 (0x39ee84e916be83e0, 0x3d75d87fe78a6731),
375 (0xb989a447bfddc5e6, 0x3ce430912f86bfb8),
376 (0xb8e31a55719de47f, 0x3c4ffcbfc588ded9),
377 (0xb850ba57164eb36b, 0x3bb62c034beb8339),
378 (0xb7b8483eabd9642d, 0x3b1b5251ff97bee1),
379 ];
380
381 let pp = backend.dd_polyeval10(
382 lo6,
383 DoubleDouble::from_bit_pair(EXP2_COEFFS[0]),
384 DoubleDouble::from_bit_pair(EXP2_COEFFS[1]),
385 DoubleDouble::from_bit_pair(EXP2_COEFFS[2]),
386 DoubleDouble::from_bit_pair(EXP2_COEFFS[3]),
387 DoubleDouble::from_bit_pair(EXP2_COEFFS[4]),
388 DoubleDouble::from_bit_pair(EXP2_COEFFS[5]),
389 DoubleDouble::from_bit_pair(EXP2_COEFFS[6]),
390 DoubleDouble::from_bit_pair(EXP2_COEFFS[7]),
391 DoubleDouble::from_bit_pair(EXP2_COEFFS[8]),
392 DoubleDouble::from_bit_pair(EXP2_COEFFS[9]),
393 );
394 let rr = backend.quick_mult(exp2_hi_mid, pp);
395
396 let r = DoubleDouble::from_exact_add(rr.hi, rr.lo);
398
399 const FRACTION_MASK: u64 = (1u64 << 52) - 1;
400
401 let mut r_bits = r.hi.to_bits();
402 if ((r_bits & 0xfff_ffff) == 0) && (r.lo != 0.0) {
403 let hi_sign = r.hi.to_bits() >> 63;
404 let lo_sign = r.lo.to_bits() >> 63;
405 if hi_sign == lo_sign {
406 r_bits = r_bits.wrapping_add(1);
407 } else if (r_bits & FRACTION_MASK) > 0 {
408 r_bits = r_bits.wrapping_sub(1);
409 }
410 }
411
412 f64::from_bits(r_bits)
413}
414
415#[inline(always)]
416#[allow(clippy::manual_clamp)]
417fn powf_gen<B: PowfBackend>(x: f32, y: f32, backend: B) -> f32 {
418 let mut x_u = x.to_bits();
419 let x_abs = x_u & 0x7fff_ffff;
420 let mut y = y;
421 let y_u = y.to_bits();
422 let y_abs = y_u & 0x7fff_ffff;
423 let mut x = x;
424
425 if ((y_abs & 0x0007_ffff) == 0) || (y_abs > 0x4f170000) {
426 if x.is_nan() || y.is_nan() {
428 if y.abs() == 0. {
429 return 1.;
430 }
431 if x == 1. {
432 return 1.;
433 }
434 return f32::NAN;
435 }
436
437 if y == 0.0 {
439 return 1.0;
440 }
441
442 match y_abs {
443 0x7f80_0000 => {
444 if x_abs > 0x7f80_0000 {
445 return x;
447 }
448 if x_abs == 0x3f80_0000 {
449 return 1.0;
451 }
452 if x == 0.0 && y_u == 0xff80_0000 {
453 return f32::INFINITY;
455 }
456 return if (x_abs < 0x3f80_0000) == (y_u == 0xff80_0000) {
461 f32::INFINITY
462 } else {
463 0.
464 };
465 }
466 _ => {
467 match y_u {
468 0x3f00_0000 => {
469 if x == 0.0 || x_u == 0xff80_0000 {
471 return x * x;
475 }
476 let r = x.sqrt();
477 return if r.to_bits() != 0x8000_0000 { r } else { 0.0 };
478 }
479 0x3f80_0000 => {
480 return x;
481 } 0x4000_0000 => return x * x, _ => {
484 let is_int = backend.integerf(y);
485 if is_int && (y_u > 0x4000_0000) && (y_u <= 0x41c0_0000) {
486 let mut msb: i32 = if x_abs == 0 {
488 32 - 2
489 } else {
490 x_abs.leading_zeros() as i32
491 };
492 msb = if msb > 8 { msb } else { 8 };
493 let mut lsb: i32 = if x_abs == 0 {
494 0
495 } else {
496 x_abs.trailing_zeros() as i32
497 };
498 lsb = if lsb > 23 { 23 } else { lsb };
499 let extra_bits: i32 = 32 - 2 - lsb - msb;
500 let iter = y as i32;
501
502 if extra_bits * iter <= 23 + 2 {
503 let x_d = x as f64;
506 let mut result = x_d;
507 for _ in 1..iter {
508 result *= x_d;
509 }
510 return result as f32;
511 }
512 }
513
514 if y_abs > 0x4f17_0000 {
515 if y_abs > 0x7f80_0000 {
517 if x_u == 0x3f80_0000 {
518 return 1.0;
521 }
522 return y;
524 }
525 y = f32::from_bits((y_u & 0x8000_0000).wrapping_add(0x4f800000u32));
529 }
530 }
531 }
532 }
533 }
534 }
535
536 const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32;
537 let mut ex = -(E_BIAS as i32);
538 let mut sign: u64 = 0;
539
540 if ((x_u & 0x801f_ffffu32) == 0) || x_u >= 0x7f80_0000u32 || x_u < 0x0080_0000u32 {
541 if x.is_nan() {
542 return f32::NAN;
543 }
544
545 if x_u == 0x3f80_0000 {
546 return 1.;
547 }
548
549 let x_is_neg = x.to_bits() > 0x8000_0000;
550
551 if x == 0.0 {
552 let out_is_neg = x_is_neg && backend.odd_integerf(f32::from_bits(y_u));
553 if y_u > 0x8000_0000u32 {
554 return if x_is_neg {
556 f32::NEG_INFINITY
557 } else {
558 f32::INFINITY
559 };
560 }
561 return if out_is_neg { -0.0 } else { 0.0 };
563 }
564
565 if x_abs == 0x7f80_0000u32 {
566 let out_is_neg = x_is_neg && backend.odd_integerf(f32::from_bits(y_u));
568 if y_u >= 0x7fff_ffff {
569 return if out_is_neg { -0.0 } else { 0.0 };
570 }
571 return if out_is_neg {
572 f32::NEG_INFINITY
573 } else {
574 f32::INFINITY
575 };
576 }
577
578 if x_abs > 0x7f80_0000 {
579 return x;
582 }
583
584 if x_abs < 0x0080_0000u32 {
586 ex = ex.wrapping_sub(64);
587 x *= f32::from_bits(0x5f800000);
588 }
589
590 if x.is_sign_negative() {
592 if backend.integerf(y) {
593 x = -x;
594 if backend.odd_integerf(y) {
595 sign = 0x8000_0000_0000_0000u64;
596 }
597 } else {
598 return f32::NAN;
600 }
601 }
602 }
603
604 x_u = x.to_bits();
608
609 ex = ex.wrapping_add((x_u >> 23) as i32);
611 let e_x = ex as f64;
612 let x_mant = x_u & ((1u32 << 23) - 1);
614 let idx_x = (x_mant >> (23 - 7)) as i32;
615 let m_x = f32::from_bits(x_mant | 0x3f800000);
618
619 let dx = if B::HAS_FMA {
627 use crate::logs::LOG_REDUCTION_F32;
628 backend.fmaf(
629 m_x,
630 f32::from_bits(LOG_REDUCTION_F32.0[idx_x as usize]),
631 -1.0,
632 ) as f64 } else {
634 use crate::logs::LOG_RANGE_REDUCTION;
635 backend.fma(
636 m_x as f64,
637 f64::from_bits(LOG_RANGE_REDUCTION[idx_x as usize]),
638 -1.0,
639 ) };
641
642 const COEFFS: [u64; 6] = [
649 0x3ff71547652b82fe,
650 0xbfe71547652b7a07,
651 0x3fdec709dc458db1,
652 0xbfd715479c2266c9,
653 0x3fd2776ae1ddf8f0,
654 0xbfce7b2178870157,
655 ];
656
657 let dx2 = dx * dx; let c0 = backend.fma(dx, f64::from_bits(COEFFS[1]), f64::from_bits(COEFFS[0]));
659 let c1 = backend.fma(dx, f64::from_bits(COEFFS[3]), f64::from_bits(COEFFS[2]));
660 let c2 = backend.fma(dx, f64::from_bits(COEFFS[5]), f64::from_bits(COEFFS[4]));
661
662 let p = backend.polyeval3(dx2, c0, c1, c2);
663
664 let s = backend.fma(dx, p, f64::from_bits(LOG2_R[idx_x as usize]) + e_x);
671
672 let y6 = (y * f32::from_bits(0x42800000)) as f64; let hm = backend.round(s * y6);
694
695 let lo6_hi = backend.fma(y6, e_x + f64::from_bits(LOG2_R_TD[idx_x as usize].2), -hm); let lo6 = backend.fma(
710 y6,
711 backend.fma(dx, p, f64::from_bits(LOG2_R_TD[idx_x as usize].1)),
712 lo6_hi,
713 );
714
715 let mut hm_i = unsafe { hm.to_int_unchecked::<i64>() };
720 hm_i = if hm_i > (1i64 << 15) {
721 1 << 15
722 } else if hm_i < (-(1i64 << 15)) {
723 -(1 << 15)
724 } else {
725 hm_i
726 };
727
728 let idx_y = hm_i & 0x3f;
729
730 let exp_hi_i = (hm_i >> 6).wrapping_shl(52);
732 let exp_mid_i = EXP2_MID1[idx_y as usize].1;
734 let exp2_hi_mid_i = (exp_hi_i.wrapping_add(exp_mid_i as i64) as u64).wrapping_add(sign);
737 let exp2_hi_mid = f64::from_bits(exp2_hi_mid_i);
738
739 const EXP2_COEFFS: [u64; 6] = [
745 0x3ff0000000000000,
746 0x3f862e42fefa39ef,
747 0x3f0ebfbdff82a23a,
748 0x3e8c6b08d7076268,
749 0x3e03b2ad33f8b48b,
750 0x3d75d870c4d84445,
751 ];
752
753 let lo6_sqr = lo6 * lo6;
754 let d0 = backend.fma(
755 lo6,
756 f64::from_bits(EXP2_COEFFS[1]),
757 f64::from_bits(EXP2_COEFFS[0]),
758 );
759 let d1 = backend.fma(
760 lo6,
761 f64::from_bits(EXP2_COEFFS[3]),
762 f64::from_bits(EXP2_COEFFS[2]),
763 );
764 let d2 = backend.fma(
765 lo6,
766 f64::from_bits(EXP2_COEFFS[5]),
767 f64::from_bits(EXP2_COEFFS[4]),
768 );
769 let pp = backend.polyeval3(lo6_sqr, d0, d1, d2);
770
771 let r = pp * exp2_hi_mid;
772 let r_u = r.to_bits();
773
774 let r_upper = f64::from_bits(r_u + B::ERR) as f32;
775 let r_lower = f64::from_bits(r_u - B::ERR) as f32;
776 if r_upper == r_lower {
777 return r_upper;
778 }
779
780 let exp2_hi_mid_dd = DoubleDouble {
782 lo: if idx_y != 0 {
783 f64::from_bits((exp_hi_i as u64).wrapping_add(EXP2_MID1[idx_y as usize].0))
784 } else {
785 0.
786 },
787 hi: exp2_hi_mid,
788 };
789
790 let r_dd = powf_dd(idx_x, dx, y6, lo6_hi, exp2_hi_mid_dd, &backend);
791 r_dd as f32
792}
793
794#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
795#[target_feature(enable = "avx", enable = "fma")]
796unsafe fn powf_fma_impl(x: f32, y: f32) -> f32 {
797 powf_gen(x, y, FmaPowfBackend {})
798}
799
800pub fn f_powf(x: f32, y: f32) -> f32 {
804 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
805 {
806 powf_gen(x, y, GenPowfBackend {})
807 }
808 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
809 {
810 use std::sync::OnceLock;
811 static EXECUTOR: OnceLock<unsafe fn(f32, f32) -> f32> = OnceLock::new();
812 let q = EXECUTOR.get_or_init(|| {
813 if std::arch::is_x86_feature_detected!("avx")
814 && std::arch::is_x86_feature_detected!("fma")
815 {
816 powf_fma_impl
817 } else {
818 fn def_powf(x: f32, y: f32) -> f32 {
819 powf_gen(x, y, GenPowfBackend {})
820 }
821 def_powf
822 }
823 });
824 unsafe { q(x, y) }
825 }
826}
827
828#[inline]
830pub fn dirty_powf(d: f32, n: f32) -> f32 {
831 use crate::exponents::dirty_exp2f;
832 use crate::logs::dirty_log2f;
833 let value = d.abs();
834 let lg = dirty_log2f(value);
835 let c = dirty_exp2f(n * lg);
836 if d < 0.0 {
837 let y = n as i32;
838 if y % 2 == 0 { c } else { -c }
839 } else {
840 c
841 }
842}
843
844#[cfg(test)]
845mod tests {
846 use super::*;
847
848 #[test]
849 fn powf_test() {
850 assert!(
851 (powf(2f32, 3f32) - 8f32).abs() < 1e-6,
852 "Invalid result {}",
853 powf(2f32, 3f32)
854 );
855 assert!(
856 (powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6,
857 "Invalid result {}",
858 powf(0.5f32, 2f32)
859 );
860 }
861
862 #[test]
863 fn f_powf_test() {
864 assert!(
865 (f_powf(2f32, 3f32) - 8f32).abs() < 1e-6,
866 "Invalid result {}",
867 f_powf(2f32, 3f32)
868 );
869 assert!(
870 (f_powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6,
871 "Invalid result {}",
872 f_powf(0.5f32, 2f32)
873 );
874 assert_eq!(f_powf(0.5f32, 1.5432f32), 0.34312353);
875 assert_eq!(
876 f_powf(f32::INFINITY, 0.00000000000000000000000000000000038518824),
877 f32::INFINITY
878 );
879 assert_eq!(f_powf(f32::NAN, 0.0), 1.);
880 assert_eq!(f_powf(1., f32::NAN), 1.);
881 }
882
883 #[test]
884 fn dirty_powf_test() {
885 assert!(
886 (dirty_powf(2f32, 3f32) - 8f32).abs() < 1e-6,
887 "Invalid result {}",
888 dirty_powf(2f32, 3f32)
889 );
890 assert!(
891 (dirty_powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6,
892 "Invalid result {}",
893 dirty_powf(0.5f32, 2f32)
894 );
895 }
896}