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 = unsafe { y.abs().to_int_unchecked::<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 target_arch = "aarch64"
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 target_arch = "aarch64"
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 target_arch = "aarch64"
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 target_arch = "aarch64"
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);
449
450 let r = log_dyadic(x) * f_y;
451 let mut result = exp_dyadic(r);
452
453 result.sign = if s == -1.0 {
461 DyadicSign::Neg
462 } else {
463 DyadicSign::Pos
464 };
465
466 result.fast_as_f64()
467}
468
469pub const fn pow(d: f64, n: f64) -> f64 {
472 let value = d.abs();
473
474 let r = n * log(value);
475 let c = exp(r);
476 if n == 0. {
477 return 1.;
478 }
479 if d < 0.0 {
480 let y = n as i32;
481 if y % 2 == 0 { c } else { -c }
482 } else {
483 c
484 }
485}
486
487#[cfg(test)]
488mod tests {
489 use super::*;
490
491 #[test]
492 fn powf_test() {
493 assert!(
494 (pow(2f64, 3f64) - 8f64).abs() < 1e-9,
495 "Invalid result {}",
496 pow(2f64, 3f64)
497 );
498 assert!(
499 (pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9,
500 "Invalid result {}",
501 pow(0.5f64, 2f64)
502 );
503 }
504
505 #[test]
506 fn f_pow_test() {
507 assert_eq!(f_pow(
508 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371,
509 -0.5,
510 ), 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
511 assert_eq!(f_pow(
512 0.000000000000000000000000000000000000000000000000000021798599361155193,
513 -2.,
514 ),2104470396771397700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
515 assert_eq!(
516 f_pow(-25192281723900620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.,
517 -2.),
518 0.
519 );
520 assert_eq!(
521 f_pow(0.000000000000000000000000000000000000000000000000000021799650661798696,
522 -2.),
523 2104267423084451500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
524 );
525 assert_eq!(
526 f_pow(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014916691520383755,
527 -2.),
528 44942267764413600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
529 );
530 assert_eq!(
531 f_pow(
532 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371,
533 -0.5,
534 ),
535 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
536 );
537 assert_eq!(f_pow(1., f64::INFINITY), 1.);
538 assert_eq!(f_pow(2., f64::INFINITY), f64::INFINITY);
539 assert_eq!(f_pow(f64::INFINITY, -0.5), 0.);
540 assert!(
541 (f_pow(2f64, 3f64) - 8f64).abs() < 1e-9,
542 "Invalid result {}",
543 f_pow(2f64, 3f64)
544 );
545 assert!(
546 (f_pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9,
547 "Invalid result {}",
548 f_pow(0.5f64, 2f64)
549 );
550 assert_eq!(f_pow(2.1f64, 2.7f64), 7.412967494768546);
551 assert_eq!(f_pow(27., 1. / 3.), 3.);
552 }
553
554 #[test]
555 fn powi_test() {
556 assert_eq!(f_pow(f64::from_bits(0x3cc0_0000_0000_0000), 102.), 0.0);
557 assert_eq!(f_pow(3., 3.), 27.);
558 assert_eq!(f_pow(3., -3.), 1. / 27.);
559 assert_eq!(f_pow(3., 102.), 4.638397686588102e48);
560 assert_eq!(f_pow(0.000000000000011074474670636028, -22.), 10589880229528372000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
561 }
562}