1use crate::common::{is_integer, is_odd_integer};
30use crate::double_double::DoubleDouble;
31use crate::exponents::{EXPM1_T0, EXPM1_T1, ldexp};
32use crate::pow_exec::pow_log_1;
33use crate::round_ties_even::RoundTiesEven;
34
35pub fn f_powm1(x: f64, y: f64) -> f64 {
37 let ax: u64 = x.to_bits().wrapping_shl(1);
38 let ay: u64 = y.to_bits().wrapping_shl(1);
39
40 if ax == 0 || ax >= 0x7ffu64 << 53 || ay == 0 || ay >= 0x7ff64 << 53 {
42 if x.is_nan() || y.is_nan() {
43 return f64::NAN;
44 }
45
46 if x.is_infinite() {
48 return if x.is_sign_positive() {
49 if y.is_infinite() {
50 return f64::INFINITY;
51 } else if y > 0.0 {
52 f64::INFINITY } else if y < 0.0 {
54 -1.0 } else {
56 f64::NAN }
58 } else {
59 if y.is_infinite() {
61 return -1.0;
62 }
63 if is_integer(y) {
64 let pow = if y as i32 % 2 == 0 {
66 f64::INFINITY
67 } else {
68 f64::NEG_INFINITY
69 };
70 pow - 1.0
71 } else {
72 f64::NAN }
74 };
75 }
76
77 if y.is_infinite() {
79 return if x.abs() > 1.0 {
80 if y.is_sign_positive() {
81 f64::INFINITY
82 } else {
83 -1.0
84 }
85 } else if x.abs() < 1.0 {
86 if y.is_sign_positive() {
87 -1.0
88 } else {
89 f64::INFINITY
90 }
91 } else {
92 f64::NAN };
95 }
96
97 if x == 0.0 {
99 return if y > 0.0 {
100 -1.0 } else if y < 0.0 {
102 f64::INFINITY } else {
104 0.0 };
106 }
107 }
108
109 let y_integer = is_integer(y);
110
111 let mut negative_parity: bool = false;
112
113 let mut x = x;
114
115 if x < 0.0 {
117 if !y_integer {
118 return f64::NAN; }
120 x = x.abs();
121 if is_odd_integer(y) {
122 negative_parity = true;
123 }
124 }
125
126 let (mut l, _) = pow_log_1(x);
127 l = DoubleDouble::from_exact_add(l.hi, l.lo);
128
129 let r = DoubleDouble::quick_mult_f64(l, y);
130 if r.hi < -37.42994775023705 {
131 return -1.;
133 }
134 let res = powm1_expm1_1(r);
135 if negative_parity {
139 DoubleDouble::full_add_f64(-res, -2.).to_f64()
140 } else {
141 res.to_f64()
142 }
143}
144
145#[inline]
146pub(crate) fn powm1_expm1_1(r: DoubleDouble) -> DoubleDouble {
147 let ax = r.hi.to_bits() & 0x7fffffffffffffffu64;
148
149 const LOG2H: f64 = f64::from_bits(0x3f262e42fefa39ef);
150 const LOG2L: f64 = f64::from_bits(0x3bbabc9e3b39803f);
151
152 if ax <= 0x3f80000000000000 {
153 if ax < 0x3970000000000000 {
155 return r;
157 }
158 let d = crate::pow_exec::expm1_poly_dd_tiny(r);
159 return d;
160 }
161
162 const INVLOG2: f64 = f64::from_bits(0x40b71547652b82fe);
163
164 let k = (r.hi * INVLOG2).round_ties_even_finite();
165
166 let z = DoubleDouble::mul_f64_add(DoubleDouble::new(LOG2L, LOG2H), -k, r);
167
168 let bk = unsafe { k.to_int_unchecked::<i64>() }; let mk = (bk >> 12) + 0x3ff;
170 let i2 = (bk >> 6) & 0x3f;
171 let i1 = bk & 0x3f;
172
173 let t0 = DoubleDouble::from_bit_pair(EXPM1_T0[i2 as usize]);
174 let t1 = DoubleDouble::from_bit_pair(EXPM1_T1[i1 as usize]);
175 let tbh = DoubleDouble::quick_mult(t1, t0);
176 let mut de = tbh;
177 let q = crate::pow_exec::expm1_poly_fast(z);
179 de = DoubleDouble::quick_mult(de, q);
180 de = DoubleDouble::add(tbh, de);
181
182 let ie = mk - 0x3ff;
183
184 let off: f64 = f64::from_bits((2048i64 + 1023i64).wrapping_sub(ie).wrapping_shl(52) as u64);
185
186 let e: f64;
187 if ie < 53 {
188 let fhz = DoubleDouble::from_exact_add(off, de.hi);
189 de.hi = fhz.hi;
190 e = fhz.lo;
191 } else if ie < 104 {
192 let fhz = DoubleDouble::from_exact_add(de.hi, off);
193 de.hi = fhz.hi;
194 e = fhz.lo;
195 } else {
196 e = 0.;
197 }
198 de.lo += e;
199 de.hi = ldexp(de.to_f64(), ie as i32);
200 de.lo = 0.;
201 de
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207 #[test]
208 fn test_powm1() {
209 assert_eq!(f_powm1(f64::INFINITY, f64::INFINITY), f64::INFINITY);
210 assert_eq!(f_powm1(50850368932909610000000000., 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023201985303960773), 1.3733470789307166e-303);
211 assert_eq!(f_powm1(-3.375, -9671689000000000000000000.), -1.);
212 assert_eq!(f_powm1(1.83329e-40, 2.4645883e-32), -2.255031542428047e-30);
213 assert_eq!(f_powm1(3., 2.), 8.);
214 assert_eq!(f_powm1(3., 3.), 26.);
215 assert_eq!(f_powm1(5., 2.), 24.);
216 assert_eq!(f_powm1(5., -2.), 1. / 25. - 1.);
217 assert_eq!(f_powm1(-5., 2.), 24.);
218 assert_eq!(f_powm1(-5., 3.), -126.);
219 assert_eq!(
220 f_powm1(196560., 0.000000000000000000000000000000000000001193773),
221 1.4550568430468268e-38
222 );
223 }
224}