1use core::num::FpCategory;
11
12use super::{
13 bkm::{bkm_e, bkm_l},
14 pow::approx_powf,
15 Float256, Float512,
16};
17use crate::math::log::approx_ln;
18use crate::{
19 abs_bits,
20 big_uint::{BigUInt, U256},
21 consts, f256, norm_signif_exp, SIGNIFICAND_BITS,
22};
23
24const LN_MAX: f256 = f256 {
27 bits: U256::new(
28 85075909386780507726367091749182177406,
29 126058098762831240896900834817458532725,
30 ),
31};
32
33const LOG2_MAX: f256 = f256 {
36 bits: U256::new(
37 0x40010fffffffffffffffffffffffffff,
38 0xffffffffffffffffffffffffffffffff,
39 ),
40};
41
42#[allow(clippy::cast_sign_loss)]
43pub(crate) fn approx_exp(x: &Float512) -> Float512 {
44 let mut m = x.abs();
46 let mut e = 0_i32;
47 if m > Float512::THREE_HALF {
51 let ms = m.signif();
52 if ms < Float512::THREE_HALF.signif() {
53 e = m.exp();
54 m = Float512::from(&ms);
55 } else {
56 e = m.exp() + 1;
57 m = Float512::from(&ms).mul_pow2(-1);
58 }
59 }
60 let mut res = match e {
61 0 => bkm_e(&m),
62 1.. => {
63 let n = 1_i32 << e as u32;
65 bkm_e(&m).powi(n)
66 }
67 -1 => {
68 bkm_e(&m).sqrt()
70 }
71 _ => {
72 let mut a = Float512::TWO.mul_pow2(e);
74 let mut t = bkm_e(&m);
75 let w = a * approx_ln(&t);
76 t * approx_exp(&w)
77 }
78 };
79 if x.signum() == -1 {
81 res = res.recip();
82 }
83 res
84}
85
86impl f256 {
87 #[must_use]
89 pub fn exp(&self) -> Self {
90 match self.classify() {
95 FpCategory::Zero | FpCategory::Subnormal => Self::ONE,
96 FpCategory::Infinite => {
97 [Self::INFINITY, Self::ZERO][self.sign() as usize]
98 }
99 FpCategory::Nan => Self::NAN,
100 _ => {
101 if self == &Self::ONE {
103 return consts::E;
105 }
106 let self_abs = self.abs();
107 if self_abs <= Self::EPSILON {
108 let x = Float512::from(self);
110 return Self::from(
111 &(Float512::ONE + x + x.square().mul_pow2(-1)),
112 );
113 }
114 if self_abs > LN_MAX {
115 return [Self::INFINITY, Self::ZERO]
116 [self.sign() as usize];
117 }
118 Self::from(&approx_exp(&Float512::from(self)))
119 }
120 }
121 }
122
123 #[must_use]
126 pub fn exp_m1(&self) -> Self {
127 match self.classify() {
132 FpCategory::Zero | FpCategory::Subnormal => Self::ZERO,
133 FpCategory::Infinite => {
134 [Self::INFINITY, Self::NEG_ONE][self.sign() as usize]
135 }
136 FpCategory::Nan => Self::NAN,
137 _ => {
138 if self == &Self::ONE {
140 return consts::E - Self::ONE;
142 }
143 let self_abs = self.abs();
144 if self_abs <= Self::EPSILON {
145 let x = Float512::from(self);
147 return Self::from(&(x + x.square().mul_pow2(-1)));
148 }
149 if self_abs > LN_MAX {
150 return [Self::INFINITY, Self::NEG_ONE]
151 [self.sign() as usize];
152 }
153 Self::from(
154 &(approx_exp(&Float512::from(self)) - Float512::ONE),
155 )
156 }
157 }
158 }
159
160 #[must_use]
162 pub fn exp2(&self) -> Self {
163 const LOG2_MIN: f256 = f256::power_of_two(-510);
164 match self.classify() {
169 FpCategory::Zero | FpCategory::Subnormal => Self::ONE,
170 FpCategory::Infinite => {
171 [Self::INFINITY, Self::ZERO][self.sign() as usize]
172 }
173 FpCategory::Nan => Self::NAN,
174 _ => {
175 if let Ok(e) = i32::try_from(self) {
177 return Self::power_of_two(e);
178 }
179 let self_abs = self.abs();
180 if self_abs < LOG2_MIN {
181 return Self::ONE;
182 }
183 if self.abs() > LOG2_MAX {
184 return [Self::INFINITY, Self::ZERO]
185 [self.sign() as usize];
186 }
187 Self::from(&approx_exp(
189 &(Float512::from(self) * Float512::LN_2),
190 ))
191 }
192 }
193 }
194}
195
196#[cfg(test)]
197mod exp_tests {
198 use super::*;
199 use crate::big_uint::HiLo;
200 use crate::consts::E;
201 use core::ops::Neg;
202
203 #[test]
204 fn calc_ln_max() {
205 let ln_max = f256::MAX.ln();
206 assert_eq!(ln_max, LN_MAX);
207 assert!(ln_max.exp().diff_within_n_bits(&f256::MAX, 17));
208 }
209
210 #[test]
211 fn test_specials() {
212 assert!(f256::NAN.exp().is_nan());
213 assert_eq!(f256::INFINITY.exp(), f256::INFINITY);
214 assert_eq!(f256::NEG_INFINITY.exp(), f256::ZERO);
215 assert_eq!(f256::ZERO.exp(), f256::ONE);
216 assert_eq!(f256::NEG_ZERO.exp(), f256::ONE);
217 }
218
219 #[test]
220 fn test_subnormal() {
221 assert_eq!(f256::MIN_GT_ZERO.exp(), f256::ONE);
222 let mut f = f256::MIN_POSITIVE;
223 f = f - f.ulp();
224 assert!(f.is_subnormal());
225 assert_eq!(f.exp(), f256::ONE);
226 }
227
228 #[test]
229 fn test_near_zero() {
230 assert_eq!(f256::MIN_POSITIVE.exp(), f256::ONE);
231 let mut f = f256::EPSILON.div_pow2(2);
232 assert_eq!(f.exp(), f256::ONE);
233 f += f.ulp();
234 assert_eq!(f.exp(), f256::ONE);
235 }
236
237 #[test]
238 fn test_near_one() {
239 assert_eq!(f256::ONE.exp(), E);
240 let mut f = f256::ONE + f256::EPSILON;
241 assert_eq!(f.exp(), E + E.ulp());
242 let mut f = f256::ONE - f256::EPSILON / f256::TWO;
243 assert_eq!(f.exp(), E - E.ulp());
244 }
245
246 #[test]
247 fn test_near_epsilon() {
248 let f = f256::EPSILON;
249 assert_eq!(f.exp(), f256::ONE + f);
250 let g = f - f.ulp().div2();
251 assert_eq!(g.exp(), f256::ONE + f);
252 let h = f.div2() - f.ulp().div2();
253 assert_eq!(h.exp(), f256::ONE);
254 }
255
256 #[test]
257 fn test_overflow() {
258 let f = LN_MAX + LN_MAX.ulp();
259 assert_eq!(f.exp(), f256::INFINITY);
260 assert_eq!(f.neg().exp(), f256::ZERO);
261 }
262}
263
264#[cfg(test)]
265mod exp_m1_tests {
266 use super::*;
267 use crate::consts::E;
269 use core::ops::Neg;
270
271 #[test]
272 fn test_specials() {
273 assert!(f256::NAN.exp_m1().is_nan());
274 assert_eq!(f256::INFINITY.exp_m1(), f256::INFINITY);
275 assert_eq!(f256::NEG_INFINITY.exp_m1(), f256::NEG_ONE);
276 assert_eq!(f256::ZERO.exp_m1(), f256::ZERO);
277 assert_eq!(f256::NEG_ZERO.exp_m1(), f256::ZERO);
278 }
279
280 #[test]
281 fn test_subnormal() {
282 assert_eq!(f256::MIN_GT_ZERO.exp_m1(), f256::ZERO);
283 let mut f = f256::MIN_POSITIVE;
284 f = f - f.ulp();
285 assert!(f.is_subnormal());
286 assert_eq!(f.exp_m1(), f256::ZERO);
287 }
288
289 #[test]
290 fn test_near_zero() {
291 assert_eq!(f256::MIN_POSITIVE.exp_m1(), f256::MIN_POSITIVE);
292 let mut f = f256::EPSILON.div_pow2(2);
293 assert_eq!(f.exp_m1(), f);
294 f += f.ulp();
295 assert_eq!(f.exp_m1(), f);
296 }
297
298 #[test]
299 fn test_near_one() {
300 assert_eq!(f256::ONE.exp_m1(), E - f256::ONE);
301 let mut f = f256::ONE + f256::EPSILON;
302 assert_eq!(f.exp_m1(), E + E.ulp() - f256::ONE);
303 let mut f = f256::ONE - f256::EPSILON.div2();
304 assert_eq!(f.exp_m1(), E - E.ulp() - f256::ONE);
305 }
306
307 #[test]
308 fn test_near_epsilon() {
309 let f = f256::EPSILON;
310 assert_eq!(f.exp_m1(), f);
311 let g = f - f.ulp().div2();
312 assert_eq!(g.exp_m1(), f);
313 let h = f.div2() - f.ulp().div2();
314 assert_eq!(h.exp_m1(), h);
315 }
316
317 #[test]
318 fn test_overflow() {
319 let f = LN_MAX + LN_MAX.ulp();
320 assert_eq!(f.exp_m1(), f256::INFINITY);
321 assert_eq!(f.neg().exp_m1(), f256::NEG_ONE);
322 }
323}
324
325#[cfg(test)]
326mod exp2_tests {
327 use super::*;
328 use crate::big_uint::HiLo;
329 use crate::consts::E;
330 use core::ops::Neg;
331
332 #[test]
333 fn calc_log2_max() {
334 let mut log2_max = f256::MAX.log2();
335 log2_max -= log2_max.ulp().div2();
336 assert_eq!(log2_max, LOG2_MAX);
337 assert!(log2_max.exp2().diff_within_n_bits(&f256::MAX, 18));
338 }
339
340 #[test]
341 fn test_specials() {
342 assert!(f256::NAN.exp2().is_nan());
343 assert_eq!(f256::INFINITY.exp2(), f256::INFINITY);
344 assert_eq!(f256::NEG_INFINITY.exp2(), f256::ZERO);
345 assert_eq!(f256::ZERO.exp2(), f256::ONE);
346 assert_eq!(f256::NEG_ZERO.exp2(), f256::ONE);
347 }
348
349 #[test]
350 fn test_subnormal() {
351 assert_eq!(f256::MIN_GT_ZERO.exp2(), f256::ONE);
352 let mut f = f256::MIN_POSITIVE;
353 f = f - f.ulp();
354 assert!(f.is_subnormal());
355 assert_eq!(f.exp2(), f256::ONE);
356 }
357
358 #[test]
359 fn test_near_zero() {
360 assert_eq!(f256::MIN_POSITIVE.exp2(), f256::ONE);
361 let mut f = f256::EPSILON.div_pow2(2);
362 assert_eq!(f.exp2(), f256::ONE);
363 f += f.ulp();
364 assert_eq!(f.exp2(), f256::ONE);
365 }
366
367 #[test]
368 fn test_near_one() {
369 assert_eq!(f256::ONE.exp2(), f256::TWO);
370 let mut f = f256::ONE + f256::EPSILON;
371 assert_eq!(f.exp2(), f256::TWO + f256::TWO.ulp());
372 let mut f = f256::ONE - f256::EPSILON.div2();
373 assert_eq!(f.exp2(), f256::TWO - f256::TWO.ulp().div2());
374 }
375
376 #[test]
377 fn test_near_epsilon() {
378 let f = f256::EPSILON;
379 assert_eq!(f.exp2(), f256::ONE + f);
380 let g = f - f.ulp().div2();
381 assert_eq!(g.exp2(), f256::ONE + f);
382 let h = f.div2() - f.ulp().div2();
383 assert_eq!(h.exp2(), f256::ONE);
384 }
385
386 #[test]
387 fn test_min() {
388 let f = -(LOG2_MAX + LOG2_MAX.ulp());
389 assert_eq!(f.exp2(), f256::MIN_POSITIVE.div_pow2(2));
390 }
391
392 #[test]
393 fn test_overflow() {
394 let f = LOG2_MAX + LOG2_MAX.ulp();
395 assert_eq!(f.exp2(), f256::INFINITY);
396 }
397}