1use crate::common::{f_fmla, is_integer, is_odd_integer};
30use crate::double_double::DoubleDouble;
31use crate::dyadic_float::{DyadicFloat128, DyadicSign};
32use crate::logs::{log1p_f64_dyadic, log1p_fast_dd};
33use crate::pow_exec::{exp_dyadic, pow_exp_dd};
34use crate::triple_double::TripleDouble;
35
36pub fn f_compound(x: f64, y: f64) -> f64 {
39 let x_sign = x.is_sign_negative();
52 let y_sign = y.is_sign_negative();
53
54 let x_abs = x.to_bits() & 0x7fff_ffff_ffff_ffff;
55 let y_abs = y.to_bits() & 0x7fff_ffff_ffff_ffff;
56
57 const MANTISSA_MASK: u64 = (1u64 << 52) - 1;
58
59 let y_mant = y.to_bits() & MANTISSA_MASK;
60 let x_u = x.to_bits();
61 let x_a = x_abs;
62 let y_a = y_abs;
63
64 if x.is_nan() || y.is_nan() {
66 return f64::NAN;
67 }
68
69 let mut s = 1.0;
70
71 let ax = x.to_bits() & 0x7fff_ffff_ffff_ffff;
72 let ay = y.to_bits() & 0x7fff_ffff_ffff_ffff;
73
74 if y_mant == 0
80 || y_a > 0x43d7_4910_d52d_3052
81 || x_u == 1f64.to_bits()
82 || x_u >= f64::INFINITY.to_bits()
83 || x_u < f64::MIN.to_bits()
84 {
85 if y == 0.0 {
87 return 1.0;
88 }
89
90 if x.is_nan() {
92 if y != 0. {
93 return x;
94 } return 1.0;
96 }
97
98 if x == 0.0 {
100 return 1.0;
101 }
102
103 if x.is_infinite() && x > 0.0 {
105 return if y > 0. { x } else { 0.0 };
106 }
107
108 if x < -1.0 {
110 return f64::NAN;
112 }
113
114 if x == -1.0 {
116 return if y < 0. { f64::INFINITY } else { 0.0 };
117 }
118
119 match y_a {
120 0x3fe0_0000_0000_0000 => {
121 if x == 0.0 {
123 return 1.0;
124 }
125 let z = DoubleDouble::from_full_exact_add(x, 1.0).sqrt();
126 return if y_sign {
127 z.recip().to_f64()
128 } else {
129 z.to_f64()
130 };
131 }
132 0x3ff0_0000_0000_0000 => {
133 return if y_sign {
134 const ONES: DyadicFloat128 = DyadicFloat128 {
135 sign: DyadicSign::Pos,
136 exponent: -127,
137 mantissa: 0x80000000_00000000_00000000_00000000_u128,
138 };
139 let z = DyadicFloat128::new_from_f64(x) + ONES;
140 z.reciprocal().fast_as_f64()
141 } else {
142 DoubleDouble::from_full_exact_add(x, 1.0).to_f64()
143 };
144 }
145 0x4000_0000_0000_0000 => {
146 let z0 = DoubleDouble::from_full_exact_add(x, 1.0);
147 let z = DoubleDouble::quick_mult(z0, z0);
148 return if y_sign {
149 z.recip().to_f64()
150 } else {
151 f64::copysign(z.to_f64(), x)
152 };
153 }
154 _ => {}
155 }
156
157 if y_a >= 0x7ff0_0000_0000_0000 {
159 if y_mant != 0 {
161 return if x_u == 1f64.to_bits() { 1.0 } else { y };
165 }
166
167 if f64::from_bits(x_abs).is_nan() {
169 return x;
171 }
172
173 if x == 0.0 && y_sign {
174 return f64::INFINITY;
176 }
177 return if (x_a < 1f64.to_bits()) == y_sign {
182 f64::INFINITY
183 } else {
184 0.0
185 };
186 }
187
188 if x == 0.0 {
191 let out_is_neg = x_sign && is_odd_integer(y);
192 if y_sign {
193 return if out_is_neg {
195 f64::NEG_INFINITY
196 } else {
197 f64::INFINITY
198 };
199 }
200 return if out_is_neg { -0.0 } else { 0.0 };
202 }
203
204 if x_a == f64::INFINITY.to_bits() {
205 let out_is_neg = x_sign && is_odd_integer(y);
206 if y_sign {
207 return if out_is_neg { -0.0 } else { 0.0 };
208 }
209 return if out_is_neg {
210 f64::NEG_INFINITY
211 } else {
212 f64::INFINITY
213 };
214 }
215
216 if x_a > f64::INFINITY.to_bits() {
217 return x;
220 }
221
222 if x_sign {
224 if is_integer(y) {
225 if is_odd_integer(y) {
226 static CS: [f64; 2] = [1.0, -1.0];
228
229 let y_parity = if (y.abs()) >= f64::from_bits(0x4340000000000000) {
231 0usize
232 } else {
233 (y as i64 & 0x1) as usize
234 };
235 s = CS[y_parity];
236 }
237 } else {
238 return f64::NAN;
240 }
241 }
242
243 if x_u == 1f64.to_bits() {
246 return 2.0;
248 }
249
250 if x == 0.0 {
251 let out_is_neg = x_sign && is_odd_integer(y);
252 if y_sign {
253 return if out_is_neg {
255 f64::NEG_INFINITY
256 } else {
257 f64::INFINITY
258 };
259 }
260 return if out_is_neg { -0.0 } else { 0.0 };
262 }
263
264 if x_a == f64::INFINITY.to_bits() {
265 let out_is_neg = x_sign && is_odd_integer(y);
266 if y_sign {
267 return if out_is_neg { -0.0 } else { 0.0 };
268 }
269 return if out_is_neg {
270 f64::NEG_INFINITY
271 } else {
272 f64::INFINITY
273 };
274 }
275
276 if x_a > f64::INFINITY.to_bits() {
277 return x;
280 }
281
282 let min_abs = f64::min(f64::from_bits(ax), f64::from_bits(ay)).to_bits();
283 let max_abs = f64::max(f64::from_bits(ax), f64::from_bits(ay)).to_bits();
284 let min_exp = min_abs.wrapping_shr(52);
285 let max_exp = max_abs.wrapping_shr(52);
286
287 if max_exp > 0x7ffu64 - 128u64 || min_exp < 128u64 {
288 let scale_up = min_exp < 128u64;
289 let scale_down = max_exp > 0x7ffu64 - 128u64;
290 if scale_up || scale_down {
293 return compound_accurate(x, y, s);
294 }
295 }
296 }
297
298 #[cfg(any(
299 all(
300 any(target_arch = "x86", target_arch = "x86_64"),
301 target_feature = "fma"
302 ),
303 all(target_arch = "aarch64", target_feature = "neon")
304 ))]
305 let straight_path_precondition: bool = true;
306 #[cfg(not(any(
307 all(
308 any(target_arch = "x86", target_arch = "x86_64"),
309 target_feature = "fma"
310 ),
311 all(target_arch = "aarch64", target_feature = "neon")
312 )))]
313 let straight_path_precondition: bool = y.is_sign_positive();
314 if is_integer(y)
318 && y_a <= 0x4059800000000000u64
319 && x_a <= 0x4090000000000000u64
320 && x_a > 0x3cc0_0000_0000_0000
321 && straight_path_precondition
322 {
323 let mut s = DoubleDouble::from_full_exact_add(1.0, x);
324 let mut iter_count = unsafe { y.abs().to_int_unchecked::<usize>() };
325
326 let mut acc = if iter_count % 2 != 0 {
328 s
329 } else {
330 DoubleDouble::new(0., 1.)
331 };
332
333 while {
334 iter_count >>= 1;
335 iter_count
336 } != 0
337 {
338 s = DoubleDouble::mult(s, s);
339 if iter_count % 2 != 0 {
340 acc = DoubleDouble::mult(acc, s);
341 }
342 }
343
344 let dz = if y.is_sign_negative() {
345 acc.recip()
346 } else {
347 acc
348 };
349 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 {
352 return dz.to_f64();
353 }
354 return mul_fixed_power_hard(x, y);
355 }
356
357 let l = log1p_fast_dd(x);
358 let ey = ((y.to_bits() >> 52) & 0x7ff) as i32;
359 if ey < 0x36 || ey >= 0x7f5 {
360 return compound_accurate(x, y, s);
361 }
362
363 let r = DoubleDouble::quick_mult_f64(l, y);
364 let res = pow_exp_dd(r, s);
365 let res_min = res.hi + f_fmla(f64::from_bits(0x3bf0000000000000), -res.hi, res.lo);
366 let res_max = res.hi + f_fmla(f64::from_bits(0x3bf0000000000000), res.hi, res.lo);
367 if res_min == res_max {
368 return res_max;
369 }
370
371 compound_accurate(x, y, s)
372}
373
374#[cold]
375fn compound_accurate(x: f64, y: f64, s: f64) -> f64 {
376 let f_y = DyadicFloat128::new_from_f64(y);
380
381 let r = log1p_f64_dyadic(x) * f_y;
382 let mut result = exp_dyadic(r);
383
384 if result.exponent < -1075 {
388 return 0.5 * (s * f64::from_bits(0x0000000000000001));
389 }
390 if result.exponent >= 1025 {
391 return 1.0;
392 }
393
394 result.sign = if s == -1.0 {
395 DyadicSign::Neg
396 } else {
397 DyadicSign::Pos
398 };
399
400 result.fast_as_f64()
401}
402
403#[cold]
404#[inline(never)]
405fn mul_fixed_power_hard(x: f64, y: f64) -> f64 {
406 let mut s = TripleDouble::from_full_exact_add(1.0, x);
407 let mut iter_count = unsafe { y.abs().to_int_unchecked::<usize>() };
408
409 let mut acc = if iter_count % 2 != 0 {
411 s
412 } else {
413 TripleDouble::new(0., 0., 1.)
414 };
415
416 while {
417 iter_count >>= 1;
418 iter_count
419 } != 0
420 {
421 s = TripleDouble::quick_mult(s, s);
422 if iter_count % 2 != 0 {
423 acc = TripleDouble::quick_mult(acc, s);
424 }
425 }
426
427 if y.is_sign_negative() {
428 acc.recip().to_f64()
429 } else {
430 acc.to_f64()
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437 #[test]
438 fn test_compound() {
439 assert_eq!(f_compound(4831835136., -13.),0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012780345669344118 );
440 assert_eq!(
441 f_compound(11468322278342656., 2.9995136260713475),
442 1481455956234813000000000000000000000000000000000.
443 );
444 assert_eq!(f_compound(0.9999999999999999, 3.), 7.999999999999999);
445 assert_eq!(
446 f_compound(1.0039215087890625, 10.000000000349134),
447 1044.2562119607103
448 );
449 assert_eq!(f_compound(10., 18.0), 5559917313492231000.0);
450 assert_eq!(
451 f_compound(131071.65137729312, 2.000001423060894),
452 17180328027.532265
453 );
454 assert_eq!(f_compound(2., 5.), 243.);
455 assert_eq!(f_compound(126.4324324, 126.4324324), 1.4985383310514043e266);
456 assert_eq!(f_compound(0.4324324, 126.4324324), 5.40545942023447e19);
457 assert!(f_compound(-0.4324324, 126.4324324).is_nan());
458 assert_eq!(f_compound(0.0, 0.0), 1.0);
459 assert_eq!(f_compound(0.0, -1. / 2.), 1.0);
460 assert_eq!(f_compound(-1., -1. / 2.), f64::INFINITY);
461 assert_eq!(f_compound(f64::INFINITY, -1. / 2.), 0.0);
462 assert_eq!(f_compound(f64::INFINITY, 1. / 2.), f64::INFINITY);
463 assert_eq!(f_compound(46.3828125, 46.3828125), 5.248159634773675e77);
464 }
465
466 #[test]
467 fn test_compound_exotic_cases() {
468 assert_eq!(f_compound(0.9999999850987819, -1.), 0.5000000037253046);
469 assert_eq!(
470 f_compound(22427285907987670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.,
471 -1.),
472 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004458854290718438
473 );
474 assert_eq!(f_compound(0.786438105629145, 607.999512419221),
475 1616461095392737200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
476 assert_eq!(f_compound( 1.0000002381857613, 960.8218657970428),
477 17228671476562465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.);
478 assert_eq!(f_compound(1., 1.0000000000000284), 2.);
479 assert_eq!(f_compound(1., f64::INFINITY), f64::INFINITY);
480 assert_eq!(
481 f_compound(10.000000000000007, -8.),
482 0.00000000466507380209731
483 );
484 }
485}