1use crate::bits::get_exponent_f64;
30use crate::common::{f_fmla, is_integer, is_odd_integer};
31use crate::double_double::DoubleDouble;
32use crate::dyadic_float::{DyadicFloat128, DyadicSign};
33use crate::exponents::exp;
34use crate::logs::log_dyadic;
35use crate::pow_exec::{exp_dyadic, pow_exp_1, pow_log_1};
36use crate::triple_double::TripleDouble;
37use crate::{f_exp2, f_exp10, log};
38
39#[cold]
40fn pow_exp10_fallback(x: f64) -> f64 {
41 f_exp10(x)
42}
43
44#[cold]
45fn pow_exp2_fallback(x: f64) -> f64 {
46 f_exp2(x)
47}
48
49#[cold]
50#[inline(never)]
51fn f_powi(x: f64, y: f64) -> f64 {
52 let mut iter_count = unsafe { y.abs().to_int_unchecked::<usize>() };
53
54 let mut s = DoubleDouble::new(0., x);
55
56 let mut acc = if iter_count % 2 != 0 {
58 s
59 } else {
60 DoubleDouble::new(0., 1.)
61 };
62
63 while {
64 iter_count >>= 1;
65 iter_count
66 } != 0
67 {
68 s = DoubleDouble::mult(s, s);
69 if iter_count % 2 != 0 {
70 acc = DoubleDouble::mult(acc, s);
71 }
72 }
73
74 let dz = if y.is_sign_negative() {
75 acc.recip()
76 } else {
77 acc
78 };
79 let ub = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), -dz.hi, dz.lo); let lb = dz.hi + f_fmla(f64::from_bits(0x3c40000000000000), dz.hi, dz.lo); if ub == lb {
82 return dz.to_f64();
83 }
84 f_powi_hard(x, y)
85}
86
87#[cold]
88#[inline(never)]
89fn f_powi_hard(x: f64, y: f64) -> f64 {
90 let mut iter_count = y.abs() as usize;
91
92 let mut s = TripleDouble::new(0., 0., x);
93
94 let mut acc = if iter_count % 2 != 0 {
96 s
97 } else {
98 TripleDouble::new(0., 0., 1.)
99 };
100
101 while {
102 iter_count >>= 1;
103 iter_count
104 } != 0
105 {
106 s = TripleDouble::quick_mult(s, s);
107 if iter_count % 2 != 0 {
108 acc = TripleDouble::quick_mult(acc, s);
109 }
110 }
111
112 let dz = if y.is_sign_negative() {
113 acc.recip()
114 } else {
115 acc
116 };
117 dz.to_f64()
118}
119
120pub fn f_pow(x: f64, y: f64) -> f64 {
124 let mut y = y;
125 let x_sign = x.is_sign_negative();
126 let y_sign = y.is_sign_negative();
127
128 let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff;
129 let y_abs = y.to_bits() & 0x7fff_ffff_ffff_ffff;
130
131 const MANTISSA_MASK: u64 = (1u64 << 52) - 1;
132
133 let y_mant = y.to_bits() & MANTISSA_MASK;
134 let x_u = x.to_bits();
135 let x_a = x_abs;
136 let y_a = y_abs;
137
138 let mut x = x;
139
140 if x.is_nan() || y.is_nan() {
142 return f64::NAN;
143 }
144
145 let mut s = 1.0;
146
147 if y_mant == 0
153 || y_a > 0x43d7_4910_d52d_3052
154 || x_u == 1f64.to_bits()
155 || x_u >= f64::INFINITY.to_bits()
156 || x_u < f64::MIN.to_bits()
157 {
158 if y == 0.0 {
160 return 1.0;
161 }
162
163 match y_a {
164 0x3fe0_0000_0000_0000 => {
165 if x == 0.0 || x_u == f64::NEG_INFINITY.to_bits() {
166 return if y_sign { 1.0 / (x * x) } else { x * x };
169 }
170 return if y_sign {
171 if x.is_infinite() {
172 return if x.is_sign_positive() { 0. } else { f64::NAN };
173 }
174 #[cfg(any(
175 all(
176 any(target_arch = "x86", target_arch = "x86_64"),
177 target_feature = "fma"
178 ),
179 all(target_arch = "aarch64", target_feature = "neon")
180 ))]
181 {
182 let r = x.sqrt() / x;
183 let rx = r * x;
184 let drx = f_fmla(r, x, -rx);
185 let h = f_fmla(r, rx, -1.0) + r * drx;
186 let dr = (r * 0.5) * h;
187 r - dr
188 }
189 #[cfg(not(any(
190 all(
191 any(target_arch = "x86", target_arch = "x86_64"),
192 target_feature = "fma"
193 ),
194 all(target_arch = "aarch64", target_feature = "neon")
195 )))]
196 {
197 let r = x.sqrt() / x;
198 let d2x = DoubleDouble::from_exact_mult(r, x);
199 let DoubleDouble { hi: h, lo: pr } = DoubleDouble::quick_mult_f64(d2x, r);
200 let DoubleDouble { hi: p, lo: q } =
201 DoubleDouble::from_full_exact_add(-1.0, h);
202 let h = DoubleDouble::from_exact_add(p, pr + q);
203 let dr = DoubleDouble::quick_mult_f64(h, r * 0.5);
204 r - dr.hi - dr.lo
205 }
206 } else {
207 x.sqrt()
208 };
209 }
210 0x3ff0_0000_0000_0000 => {
211 return if y_sign { 1.0 / x } else { x };
212 }
213 0x4000_0000_0000_0000 => {
214 let x_e = get_exponent_f64(x);
215 if x_e > 511 {
216 return if y_sign { 0. } else { f64::INFINITY };
217 }
218 if x_e.abs() < 70 {
220 let x_sqr = DoubleDouble::from_exact_mult(x, x);
221 return if y_sign {
222 let recip = x_sqr.recip();
223 recip.to_f64()
224 } else {
225 x_sqr.to_f64()
226 };
227 }
228 }
229 _ => {}
230 }
231
232 if y_a > 0x43d7_4910_d52d_3052 {
234 if y_a >= 0x7ff0_0000_0000_0000 {
235 if y_mant != 0 {
237 return if x_u == 1f64.to_bits() { 1.0 } else { y };
241 }
242
243 if f64::from_bits(x_abs).is_nan() {
245 return x;
247 }
248
249 if x_a == 0x3ff0_0000_0000_0000 {
250 return 1.0;
252 }
253
254 if x == 0.0 && y_sign {
255 return f64::INFINITY;
257 }
258 return if (x_a < 1f64.to_bits()) == y_sign {
263 f64::INFINITY
264 } else {
265 0.0
266 };
267 }
268 y = if y_sign {
272 f64::from_bits(0xc630000000000000)
273 } else {
274 f64::from_bits(0x4630000000000000)
275 };
276 }
277
278 if x_u == 1f64.to_bits() {
281 return 1.0;
283 }
284
285 if x == 0.0 {
286 let out_is_neg = x_sign && is_odd_integer(y);
287 if y_sign {
288 return if out_is_neg {
290 f64::NEG_INFINITY
291 } else {
292 f64::INFINITY
293 };
294 }
295 return if out_is_neg { -0.0 } else { 0.0 };
297 } else if x == 2.0 {
298 return pow_exp2_fallback(y);
299 } else if x == 10.0 {
300 return pow_exp10_fallback(y);
301 }
302
303 if x_a == f64::INFINITY.to_bits() {
304 let out_is_neg = x_sign && is_odd_integer(y);
305 if y_sign {
306 return if out_is_neg { -0.0 } else { 0.0 };
307 }
308 return if out_is_neg {
309 f64::NEG_INFINITY
310 } else {
311 f64::INFINITY
312 };
313 }
314
315 if x_a > f64::INFINITY.to_bits() {
316 return x;
319 }
320
321 let is_y_integer = is_integer(y);
324 #[cfg(any(
329 all(
330 any(target_arch = "x86", target_arch = "x86_64"),
331 target_feature = "fma"
332 ),
333 all(target_arch = "aarch64", target_feature = "neon")
334 ))]
335 if is_y_integer
336 && y_a <= 0x4059800000000000u64
337 && x_a <= 0x4090000000000000u64
338 && x_a > 0x3cc0_0000_0000_0000
339 {
340 return f_powi(x, y);
341 }
342 #[cfg(not(any(
343 all(
344 any(target_arch = "x86", target_arch = "x86_64"),
345 target_feature = "fma"
346 ),
347 all(target_arch = "aarch64", target_feature = "neon")
348 )))]
349 if is_y_integer
350 && y_a <= 0x4059800000000000u64
351 && x_a <= 0x4090000000000000u64
352 && x_a > 0x3cc0_0000_0000_0000
353 && y.is_sign_positive()
354 {
355 return f_powi(x, y);
356 }
357
358 if x_sign {
359 if is_y_integer {
360 x = -x;
361 if is_odd_integer(y) {
362 static CS: [f64; 2] = [1.0, -1.0];
364
365 let y_parity = if (y.abs()) >= f64::from_bits(0x4340000000000000) {
367 0usize
368 } else {
369 (y as i64 & 0x1) as usize
370 };
371 s = CS[y_parity];
372 }
373 } else {
374 return f64::NAN;
376 }
377 }
378
379 if x_u == 1f64.to_bits() {
382 return 1.0;
384 }
385
386 if x == 0.0 {
387 let out_is_neg = x_sign && is_odd_integer(y);
388 if y_sign {
389 return if out_is_neg {
391 f64::NEG_INFINITY
392 } else {
393 f64::INFINITY
394 };
395 }
396 return if out_is_neg { -0.0 } else { 0.0 };
398 }
399
400 if x_a == f64::INFINITY.to_bits() {
401 let out_is_neg = x_sign && is_odd_integer(y);
402 if y_sign {
403 return if out_is_neg { -0.0 } else { 0.0 };
404 }
405 return if out_is_neg {
406 f64::NEG_INFINITY
407 } else {
408 f64::INFINITY
409 };
410 }
411
412 if x_a > f64::INFINITY.to_bits() {
413 return x;
416 }
417 }
418
419 let (mut l, cancel) = pow_log_1(x);
421
422 let ey = ((y.to_bits() >> 52) & 0x7ff) as i32;
430 if ey < 0x36 || ey >= 0x7f5 {
431 l.lo = f64::NAN;
432 l.hi = f64::NAN;
433 }
434
435 let r = DoubleDouble::quick_mult_f64(l, y);
436 let res = pow_exp_1(r, s);
437 static ERR: [u64; 2] = [0x3bf2700000000000, 0x3c55700000000000];
438 let res_min = res.hi + f_fmla(f64::from_bits(ERR[cancel as usize]), -res.hi, res.lo);
439 let res_max = res.hi + f_fmla(f64::from_bits(ERR[cancel as usize]), res.hi, res.lo);
440 if res_min == res_max {
441 return res_max;
442 }
443 pow_rational128(x, y, s)
444}
445
446#[cold]
447fn pow_rational128(x: f64, y: f64, s: f64) -> f64 {
448 let f_y = DyadicFloat128::new_from_f64(y);
452
453 let r = log_dyadic(x) * f_y;
454 let mut result = exp_dyadic(r);
455
456 result.sign = if s == -1.0 {
464 DyadicSign::Neg
465 } else {
466 DyadicSign::Pos
467 };
468
469 result.fast_as_f64()
470}
471
472#[inline]
475pub const fn pow(d: f64, n: f64) -> f64 {
476 let value = d.abs();
477
478 let r = n * log(value);
479 let c = exp(r);
480 if n == 0. {
481 return 1.;
482 }
483 if d < 0.0 {
484 let y = n as i32;
485 if y % 2 == 0 { c } else { -c }
486 } else {
487 c
488 }
489}
490
491#[cfg(test)]
492mod tests {
493 use super::*;
494
495 #[test]
496 fn powf_test() {
497 assert!(
498 (pow(2f64, 3f64) - 8f64).abs() < 1e-9,
499 "Invalid result {}",
500 pow(2f64, 3f64)
501 );
502 assert!(
503 (pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9,
504 "Invalid result {}",
505 pow(0.5f64, 2f64)
506 );
507 }
508
509 #[test]
510 fn f_pow_test() {
511 assert_eq!(f_pow(
512 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371,
513 -0.5,
514 ), 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
515 assert_eq!(f_pow(
516 0.000000000000000000000000000000000000000000000000000021798599361155193,
517 -2.,
518 ),2104470396771397700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
519 assert_eq!(
520 f_pow(-25192281723900620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.,
521 -2.),
522 0.
523 );
524 assert_eq!(
525 f_pow(0.000000000000000000000000000000000000000000000000000021799650661798696,
526 -2.),
527 2104267423084451500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
528 );
529 assert_eq!(
530 f_pow(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014916691520383755,
531 -2.),
532 44942267764413600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
533 );
534 assert_eq!(
535 f_pow(
536 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371,
537 -0.5,
538 ),
539 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
540 );
541 assert_eq!(f_pow(1., f64::INFINITY), 1.);
542 assert_eq!(f_pow(2., f64::INFINITY), f64::INFINITY);
543 assert_eq!(f_pow(f64::INFINITY, -0.5), 0.);
544 assert!(
545 (f_pow(2f64, 3f64) - 8f64).abs() < 1e-9,
546 "Invalid result {}",
547 f_pow(2f64, 3f64)
548 );
549 assert!(
550 (f_pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9,
551 "Invalid result {}",
552 f_pow(0.5f64, 2f64)
553 );
554 assert_eq!(f_pow(2.1f64, 2.7f64), 7.412967494768546);
555 assert_eq!(f_pow(27., 1. / 3.), 3.);
556 }
557
558 #[test]
559 fn powi_test() {
560 assert_eq!(f_pow(f64::from_bits(0x3cc0_0000_0000_0000), 102.), 0.0);
561 assert_eq!(f_pow(3., 3.), 27.);
562 assert_eq!(f_pow(3., -3.), 1. / 27.);
563 assert_eq!(f_pow(3., 102.), 4.638397686588102e48);
564 assert_eq!(f_pow(0.000000000000011074474670636028, -22.), 10589880229528372000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
565 }
566}