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)]
416fn powf_gen<B: PowfBackend>(x: f32, y: f32, backend: B) -> f32 {
417 let mut x_u = x.to_bits();
418 let x_abs = x_u & 0x7fff_ffff;
419 let mut y = y;
420 let y_u = y.to_bits();
421 let y_abs = y_u & 0x7fff_ffff;
422 let mut x = x;
423
424 if ((y_abs & 0x0007_ffff) == 0) || (y_abs > 0x4f170000) {
425 if x.is_nan() || y.is_nan() {
427 if y.abs() == 0. {
428 return 1.;
429 }
430 if x == 1. {
431 return 1.;
432 }
433 return f32::NAN;
434 }
435
436 if y == 0.0 {
438 return 1.0;
439 }
440
441 match y_abs {
442 0x7f80_0000 => {
443 if x_abs > 0x7f80_0000 {
444 return x;
446 }
447 if x_abs == 0x3f80_0000 {
448 return 1.0;
450 }
451 if x == 0.0 && y_u == 0xff80_0000 {
452 return f32::INFINITY;
454 }
455 return if (x_abs < 0x3f80_0000) == (y_u == 0xff80_0000) {
460 f32::INFINITY
461 } else {
462 0.
463 };
464 }
465 _ => {
466 match y_u {
467 0x3f00_0000 => {
468 if x == 0.0 || x_u == 0xff80_0000 {
470 return x * x;
474 }
475 let r = x.sqrt();
476 return if r.to_bits() != 0x8000_0000 { r } else { 0.0 };
477 }
478 0x3f80_0000 => {
479 return x;
480 } 0x4000_0000 => return x * x, _ => {
483 let is_int = backend.integerf(y);
484 if is_int && (y_u > 0x4000_0000) && (y_u <= 0x41c0_0000) {
485 let mut msb: i32 = if x_abs == 0 {
487 32 - 2
488 } else {
489 x_abs.leading_zeros() as i32
490 };
491 msb = if msb > 8 { msb } else { 8 };
492 let mut lsb: i32 = if x_abs == 0 {
493 0
494 } else {
495 x_abs.trailing_zeros() as i32
496 };
497 lsb = if lsb > 23 { 23 } else { lsb };
498 let extra_bits: i32 = 32 - 2 - lsb - msb;
499 let iter = y as i32;
500
501 if extra_bits * iter <= 23 + 2 {
502 let x_d = x as f64;
505 let mut result = x_d;
506 for _ in 1..iter {
507 result *= x_d;
508 }
509 return result as f32;
510 }
511 }
512
513 if y_abs > 0x4f17_0000 {
514 if y_abs > 0x7f80_0000 {
516 if x_u == 0x3f80_0000 {
517 return 1.0;
520 }
521 return y;
523 }
524 y = f32::from_bits((y_u & 0x8000_0000).wrapping_add(0x4f800000u32));
528 }
529 }
530 }
531 }
532 }
533 }
534
535 const E_BIAS: u32 = (1u32 << (8 - 1u32)) - 1u32;
536 let mut ex = -(E_BIAS as i32);
537 let mut sign: u64 = 0;
538
539 if ((x_u & 0x801f_ffffu32) == 0) || x_u >= 0x7f80_0000u32 || x_u < 0x0080_0000u32 {
540 if x.is_nan() {
541 return f32::NAN;
542 }
543
544 if x_u == 0x3f80_0000 {
545 return 1.;
546 }
547
548 let x_is_neg = x.to_bits() > 0x8000_0000;
549
550 if x == 0.0 {
551 let out_is_neg = x_is_neg && backend.odd_integerf(f32::from_bits(y_u));
552 if y_u > 0x8000_0000u32 {
553 return if x_is_neg {
555 f32::NEG_INFINITY
556 } else {
557 f32::INFINITY
558 };
559 }
560 return if out_is_neg { -0.0 } else { 0.0 };
562 }
563
564 if x_abs == 0x7f80_0000u32 {
565 let out_is_neg = x_is_neg && backend.odd_integerf(f32::from_bits(y_u));
567 if y_u >= 0x7fff_ffff {
568 return if out_is_neg { -0.0 } else { 0.0 };
569 }
570 return if out_is_neg {
571 f32::NEG_INFINITY
572 } else {
573 f32::INFINITY
574 };
575 }
576
577 if x_abs > 0x7f80_0000 {
578 return x;
581 }
582
583 if x_abs < 0x0080_0000u32 {
585 ex = ex.wrapping_sub(64);
586 x *= f32::from_bits(0x5f800000);
587 }
588
589 if x.is_sign_negative() {
591 if backend.integerf(y) {
592 x = -x;
593 if backend.odd_integerf(y) {
594 sign = 0x8000_0000_0000_0000u64;
595 }
596 } else {
597 return f32::NAN;
599 }
600 }
601 }
602
603 x_u = x.to_bits();
607
608 ex = ex.wrapping_add((x_u >> 23) as i32);
610 let e_x = ex as f64;
611 let x_mant = x_u & ((1u32 << 23) - 1);
613 let idx_x = (x_mant >> (23 - 7)) as i32;
614 let m_x = f32::from_bits(x_mant | 0x3f800000);
617
618 let dx = if B::HAS_FMA {
626 use crate::logs::LOG_REDUCTION_F32;
627 backend.fmaf(
628 m_x,
629 f32::from_bits(LOG_REDUCTION_F32.0[idx_x as usize]),
630 -1.0,
631 ) as f64 } else {
633 use crate::logs::LOG_RANGE_REDUCTION;
634 backend.fma(
635 m_x as f64,
636 f64::from_bits(LOG_RANGE_REDUCTION[idx_x as usize]),
637 -1.0,
638 ) };
640
641 const COEFFS: [u64; 6] = [
648 0x3ff71547652b82fe,
649 0xbfe71547652b7a07,
650 0x3fdec709dc458db1,
651 0xbfd715479c2266c9,
652 0x3fd2776ae1ddf8f0,
653 0xbfce7b2178870157,
654 ];
655
656 let dx2 = dx * dx; let c0 = backend.fma(dx, f64::from_bits(COEFFS[1]), f64::from_bits(COEFFS[0]));
658 let c1 = backend.fma(dx, f64::from_bits(COEFFS[3]), f64::from_bits(COEFFS[2]));
659 let c2 = backend.fma(dx, f64::from_bits(COEFFS[5]), f64::from_bits(COEFFS[4]));
660
661 let p = backend.polyeval3(dx2, c0, c1, c2);
662
663 let s = backend.fma(dx, p, f64::from_bits(LOG2_R[idx_x as usize]) + e_x);
670
671 let y6 = (y * f32::from_bits(0x42800000)) as f64; let hm = backend.round(s * y6);
693
694 let lo6_hi = backend.fma(y6, e_x + f64::from_bits(LOG2_R_TD[idx_x as usize].2), -hm); let lo6 = backend.fma(
709 y6,
710 backend.fma(dx, p, f64::from_bits(LOG2_R_TD[idx_x as usize].1)),
711 lo6_hi,
712 );
713
714 let mut hm_i = unsafe { hm.to_int_unchecked::<i64>() };
719 hm_i = if hm_i > (1i64 << 15) {
720 1 << 15
721 } else if hm_i < (-(1i64 << 15)) {
722 -(1 << 15)
723 } else {
724 hm_i
725 };
726
727 let idx_y = hm_i & 0x3f;
728
729 let exp_hi_i = (hm_i >> 6).wrapping_shl(52);
731 let exp_mid_i = EXP2_MID1[idx_y as usize].1;
733 let exp2_hi_mid_i = (exp_hi_i.wrapping_add(exp_mid_i as i64) as u64).wrapping_add(sign);
736 let exp2_hi_mid = f64::from_bits(exp2_hi_mid_i);
737
738 const EXP2_COEFFS: [u64; 6] = [
744 0x3ff0000000000000,
745 0x3f862e42fefa39ef,
746 0x3f0ebfbdff82a23a,
747 0x3e8c6b08d7076268,
748 0x3e03b2ad33f8b48b,
749 0x3d75d870c4d84445,
750 ];
751
752 let lo6_sqr = lo6 * lo6;
753 let d0 = backend.fma(
754 lo6,
755 f64::from_bits(EXP2_COEFFS[1]),
756 f64::from_bits(EXP2_COEFFS[0]),
757 );
758 let d1 = backend.fma(
759 lo6,
760 f64::from_bits(EXP2_COEFFS[3]),
761 f64::from_bits(EXP2_COEFFS[2]),
762 );
763 let d2 = backend.fma(
764 lo6,
765 f64::from_bits(EXP2_COEFFS[5]),
766 f64::from_bits(EXP2_COEFFS[4]),
767 );
768 let pp = backend.polyeval3(lo6_sqr, d0, d1, d2);
769
770 let r = pp * exp2_hi_mid;
771 let r_u = r.to_bits();
772
773 let r_upper = f64::from_bits(r_u + B::ERR) as f32;
774 let r_lower = f64::from_bits(r_u - B::ERR) as f32;
775 if r_upper == r_lower {
776 return r_upper;
777 }
778
779 let exp2_hi_mid_dd = DoubleDouble {
781 lo: if idx_y != 0 {
782 f64::from_bits((exp_hi_i as u64).wrapping_add(EXP2_MID1[idx_y as usize].0))
783 } else {
784 0.
785 },
786 hi: exp2_hi_mid,
787 };
788
789 let r_dd = powf_dd(idx_x, dx, y6, lo6_hi, exp2_hi_mid_dd, &backend);
790 r_dd as f32
791}
792
793#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
794#[target_feature(enable = "avx", enable = "fma")]
795unsafe fn powf_fma_impl(x: f32, y: f32) -> f32 {
796 powf_gen(x, y, FmaPowfBackend {})
797}
798
799pub fn f_powf(x: f32, y: f32) -> f32 {
803 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
804 {
805 powf_gen(x, y, GenPowfBackend {})
806 }
807 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
808 {
809 use std::sync::OnceLock;
810 static EXECUTOR: OnceLock<unsafe fn(f32, f32) -> f32> = OnceLock::new();
811 let q = EXECUTOR.get_or_init(|| {
812 if std::arch::is_x86_feature_detected!("avx")
813 && std::arch::is_x86_feature_detected!("fma")
814 {
815 powf_fma_impl
816 } else {
817 fn def_powf(x: f32, y: f32) -> f32 {
818 powf_gen(x, y, GenPowfBackend {})
819 }
820 def_powf
821 }
822 });
823 unsafe { q(x, y) }
824 }
825}
826
827#[inline]
829pub fn dirty_powf(d: f32, n: f32) -> f32 {
830 use crate::exponents::dirty_exp2f;
831 use crate::logs::dirty_log2f;
832 let value = d.abs();
833 let lg = dirty_log2f(value);
834 let c = dirty_exp2f(n * lg);
835 if d < 0.0 {
836 let y = n as i32;
837 if y % 2 == 0 { c } else { -c }
838 } else {
839 c
840 }
841}
842
843#[cfg(test)]
844mod tests {
845 use super::*;
846
847 #[test]
848 fn powf_test() {
849 assert!(
850 (powf(2f32, 3f32) - 8f32).abs() < 1e-6,
851 "Invalid result {}",
852 powf(2f32, 3f32)
853 );
854 assert!(
855 (powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6,
856 "Invalid result {}",
857 powf(0.5f32, 2f32)
858 );
859 }
860
861 #[test]
862 fn f_powf_test() {
863 assert!(
864 (f_powf(2f32, 3f32) - 8f32).abs() < 1e-6,
865 "Invalid result {}",
866 f_powf(2f32, 3f32)
867 );
868 assert!(
869 (f_powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6,
870 "Invalid result {}",
871 f_powf(0.5f32, 2f32)
872 );
873 assert_eq!(f_powf(0.5f32, 1.5432f32), 0.34312353);
874 assert_eq!(
875 f_powf(f32::INFINITY, 0.00000000000000000000000000000000038518824),
876 f32::INFINITY
877 );
878 assert_eq!(f_powf(f32::NAN, 0.0), 1.);
879 assert_eq!(f_powf(1., f32::NAN), 1.);
880 }
881
882 #[test]
883 fn dirty_powf_test() {
884 assert!(
885 (dirty_powf(2f32, 3f32) - 8f32).abs() < 1e-6,
886 "Invalid result {}",
887 dirty_powf(2f32, 3f32)
888 );
889 assert!(
890 (dirty_powf(0.5f32, 2f32) - 0.25f32).abs() < 1e-6,
891 "Invalid result {}",
892 dirty_powf(0.5f32, 2f32)
893 );
894 }
895}