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 let a_xe = x_e & 0x7fff_ffff_ffff_ffff;
220 if a_xe < 70 {
221 let x_sqr = DoubleDouble::from_exact_mult(x, x);
222 return if y_sign {
223 let recip = x_sqr.recip();
224 recip.to_f64()
225 } else {
226 x_sqr.to_f64()
227 };
228 }
229 }
230 _ => {}
231 }
232
233 if y_a > 0x43d7_4910_d52d_3052 {
235 if y_a >= 0x7ff0_0000_0000_0000 {
236 if y_mant != 0 {
238 return if x_u == 1f64.to_bits() { 1.0 } else { y };
242 }
243
244 if f64::from_bits(x_abs).is_nan() {
246 return x;
248 }
249
250 if x_a == 0x3ff0_0000_0000_0000 {
251 return 1.0;
253 }
254
255 if x == 0.0 && y_sign {
256 return f64::INFINITY;
258 }
259 return if (x_a < 1f64.to_bits()) == y_sign {
264 f64::INFINITY
265 } else {
266 0.0
267 };
268 }
269 y = if y_sign {
273 f64::from_bits(0xc630000000000000)
274 } else {
275 f64::from_bits(0x4630000000000000)
276 };
277 }
278
279 if x_u == 1f64.to_bits() {
282 return 1.0;
284 }
285
286 if x == 0.0 {
287 let out_is_neg = x_sign && is_odd_integer(y);
288 if y_sign {
289 return if out_is_neg {
291 f64::NEG_INFINITY
292 } else {
293 f64::INFINITY
294 };
295 }
296 return if out_is_neg { -0.0 } else { 0.0 };
298 } else if x == 2.0 {
299 return pow_exp2_fallback(y);
300 } else if x == 10.0 {
301 return pow_exp10_fallback(y);
302 }
303
304 if x_a == f64::INFINITY.to_bits() {
305 let out_is_neg = x_sign && is_odd_integer(y);
306 if y_sign {
307 return if out_is_neg { -0.0 } else { 0.0 };
308 }
309 return if out_is_neg {
310 f64::NEG_INFINITY
311 } else {
312 f64::INFINITY
313 };
314 }
315
316 if x_a > f64::INFINITY.to_bits() {
317 return x;
320 }
321
322 let is_y_integer = is_integer(y);
325 #[cfg(any(
330 all(
331 any(target_arch = "x86", target_arch = "x86_64"),
332 target_feature = "fma"
333 ),
334 target_arch = "aarch64"
335 ))]
336 if is_y_integer
337 && y_a <= 0x4059800000000000u64
338 && x_a <= 0x4090000000000000u64
339 && x_a > 0x3cc0_0000_0000_0000
340 {
341 return f_powi(x, y);
342 }
343 #[cfg(not(any(
344 all(
345 any(target_arch = "x86", target_arch = "x86_64"),
346 target_feature = "fma"
347 ),
348 target_arch = "aarch64"
349 )))]
350 if is_y_integer
351 && y_a <= 0x4059800000000000u64
352 && x_a <= 0x4090000000000000u64
353 && x_a > 0x3cc0_0000_0000_0000
354 && y.is_sign_positive()
355 {
356 return f_powi(x, y);
357 }
358
359 if x_sign {
360 if is_y_integer {
361 x = -x;
362 if is_odd_integer(y) {
363 static CS: [f64; 2] = [1.0, -1.0];
365
366 let y_parity = if (y.abs()) >= f64::from_bits(0x4340000000000000) {
368 0usize
369 } else {
370 (y as i64 & 0x1) as usize
371 };
372 s = CS[y_parity];
373 }
374 } else {
375 return f64::NAN;
377 }
378 }
379
380 if x_u == 1f64.to_bits() {
383 return 1.0;
385 }
386
387 if x == 0.0 {
388 let out_is_neg = x_sign && is_odd_integer(y);
389 if y_sign {
390 return if out_is_neg {
392 f64::NEG_INFINITY
393 } else {
394 f64::INFINITY
395 };
396 }
397 return if out_is_neg { -0.0 } else { 0.0 };
399 }
400
401 if x_a == f64::INFINITY.to_bits() {
402 let out_is_neg = x_sign && is_odd_integer(y);
403 if y_sign {
404 return if out_is_neg { -0.0 } else { 0.0 };
405 }
406 return if out_is_neg {
407 f64::NEG_INFINITY
408 } else {
409 f64::INFINITY
410 };
411 }
412
413 if x_a > f64::INFINITY.to_bits() {
414 return x;
417 }
418 }
419
420 let (mut l, cancel) = pow_log_1(x);
422
423 let ey = ((y.to_bits() >> 52) & 0x7ff) as i32;
431 if ey < 0x36 || ey >= 0x7f5 {
432 l.lo = f64::NAN;
433 l.hi = f64::NAN;
434 }
435
436 let r = DoubleDouble::quick_mult_f64(l, y);
437 let res = pow_exp_1(r, s);
438 static ERR: [u64; 2] = [0x3bf2700000000000, 0x3c55700000000000];
439 let res_min = res.hi + f_fmla(f64::from_bits(ERR[cancel as usize]), -res.hi, res.lo);
440 let res_max = res.hi + f_fmla(f64::from_bits(ERR[cancel as usize]), res.hi, res.lo);
441 if res_min == res_max {
442 return res_max;
443 }
444 pow_rational128(x, y, s)
445}
446
447#[cold]
448fn pow_rational128(x: f64, y: f64, s: f64) -> f64 {
449 let f_y = DyadicFloat128::new_from_f64(y);
450
451 let r = log_dyadic(x) * f_y;
452 let mut result = exp_dyadic(r);
453
454 result.sign = if s == -1.0 {
462 DyadicSign::Neg
463 } else {
464 DyadicSign::Pos
465 };
466
467 result.fast_as_f64()
468}
469
470pub const fn pow(d: f64, n: f64) -> f64 {
473 let value = d.abs();
474
475 let r = n * log(value);
476 let c = exp(r);
477 if n == 0. {
478 return 1.;
479 }
480 if d < 0.0 {
481 let y = n as i32;
482 if y % 2 == 0 { c } else { -c }
483 } else {
484 c
485 }
486}
487
488#[cfg(test)]
489mod tests {
490 use super::*;
491
492 #[test]
493 fn powf_test() {
494 assert!(
495 (pow(2f64, 3f64) - 8f64).abs() < 1e-9,
496 "Invalid result {}",
497 pow(2f64, 3f64)
498 );
499 assert!(
500 (pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9,
501 "Invalid result {}",
502 pow(0.5f64, 2f64)
503 );
504 }
505
506 #[test]
507 fn f_pow_test() {
508 assert_eq!(f_pow(
509 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371,
510 -0.5,
511 ), 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
512 assert_eq!(f_pow(
513 0.000000000000000000000000000000000000000000000000000021798599361155193,
514 -2.,
515 ),2104470396771397700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
516 assert_eq!(
517 f_pow(-25192281723900620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.,
518 -2.),
519 0.
520 );
521 assert_eq!(
522 f_pow(0.000000000000000000000000000000000000000000000000000021799650661798696,
523 -2.),
524 2104267423084451500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
525 );
526 assert_eq!(
527 f_pow(0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014916691520383755,
528 -2.),
529 44942267764413600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
530 );
531 assert_eq!(
532 f_pow(
533 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000135264499699371,
534 -0.5,
535 ),
536 27189929701044785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
537 );
538 assert_eq!(f_pow(1., f64::INFINITY), 1.);
539 assert_eq!(f_pow(2., f64::INFINITY), f64::INFINITY);
540 assert_eq!(f_pow(f64::INFINITY, -0.5), 0.);
541 assert!(
542 (f_pow(2f64, 3f64) - 8f64).abs() < 1e-9,
543 "Invalid result {}",
544 f_pow(2f64, 3f64)
545 );
546 assert!(
547 (f_pow(0.5f64, 2f64) - 0.25f64).abs() < 1e-9,
548 "Invalid result {}",
549 f_pow(0.5f64, 2f64)
550 );
551 assert_eq!(f_pow(2.1f64, 2.7f64), 7.412967494768546);
552 assert_eq!(f_pow(27., 1. / 3.), 3.);
553 }
554
555 #[test]
556 fn powi_test() {
557 assert_eq!(f_pow(f64::from_bits(0x3cc0_0000_0000_0000), 102.), 0.0);
558 assert_eq!(f_pow(3., 3.), 27.);
559 assert_eq!(f_pow(3., -3.), 1. / 27.);
560 assert_eq!(f_pow(3., 102.), 4.638397686588102e48);
561 assert_eq!(f_pow(0.000000000000011074474670636028, -22.), 10589880229528372000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
562 }
563}