1use super::consts::*;
2use super::unsigned::UnsignedNumeric;
3use super::signed::SignedNumeric;
4
5impl SignedNumeric {
73
74 pub fn exp(&self) -> Option<UnsignedNumeric> {
78 let hi: Self;
79 let lo: Self;
80 let k: Self;
81 let x: Self;
82
83 if self.value.greater_than(&HALFLN2) {
86 if self.value.greater_than_or_equal(&THREEHALFLN2) {
88 k = INVLN2
89 .signed()
90 .checked_mul(self)?
91 .checked_add(&Self {
92 value: HALF,
93 is_negative: self.is_negative,
94 })?
95 .floor()?;
96
97 } else {
102 k = Self {
103 value: UnsignedNumeric::one(),
104 is_negative: self.is_negative,
105 }
106 }
107 hi = self.checked_sub(
108 &k.checked_mul(&LN2HI.signed())?
109 .checked_div(&LN2HI_SCALE.signed())?,
110 )?;
111
112 lo = k
113 .checked_mul(&LN2LO.signed())?
114 .checked_div(&LN2LO_SCALE.signed())?;
115 x = hi.checked_sub(&lo)?
116 } else {
117 x = self.clone();
118 k = UnsignedNumeric::zero().signed();
119 hi = self.clone();
120 lo = UnsignedNumeric::zero().signed()
121 }
122
123 let xx = x.checked_mul(&x)?;
125 let p4p5 = P4.checked_add(&xx.checked_mul(&P5)?)?;
127 let p3p4p5 = P3.checked_add(&xx.checked_mul(&p4p5)?)?;
128 let p2p3p4p5 = P2.checked_add(&xx.checked_mul(&p3p4p5)?)?;
129 let p1p2p3p4p5 = P1.checked_add(&xx.checked_mul(&p2p3p4p5)?)?;
130 let c = x.checked_sub(&p1p2p3p4p5.checked_mul(&xx)?)?;
131
132 let y = ONE_PREC.signed().checked_add(
134 &x.checked_mul(&c)?
135 .checked_div(&TWO_PREC.signed().checked_sub(&c)?)?
136 .checked_sub(&lo)?
137 .checked_add(&hi)?,
138 )?;
139
140 if k.value.eq(&UnsignedNumeric::zero()) {
141 Some(y.value)
142 } else {
143 let bits = k.value.to_imprecise()?;
144
145 if k.is_negative {
146 Some(UnsignedNumeric {
147 value: y.value.value >> bits,
148 })
149 } else {
150 Some(UnsignedNumeric {
151 value: y.value.value << bits,
152 })
153 }
154 }
155 }
156
157 pub fn sqrt(&self) -> Option<Self> {
159 if self.is_negative {
160 return None;
161 }
162 self.value.sqrt().map(|v| Self { value: v, is_negative: false })
163 }
164}
165
166impl UnsignedNumeric {
167
168 pub fn frexp(&self) -> Option<(Self, i64)> {
176 if self.eq(&ZERO_PREC) {
177 Some((ZERO_PREC.clone(), 0))
178 } else if self.less_than(&ONE_PREC) {
179 let first_leading = self.value.0[0].leading_zeros();
180 let one_leading = ONE_PREC.value.0[0].leading_zeros();
181 let bits = i64::from(first_leading.checked_sub(one_leading).unwrap());
182 let frac = UnsignedNumeric {
183 value: self.value << bits,
184 };
185 if frac.less_than(&HALF) {
186 Some((frac.checked_mul(&TWO_PREC).unwrap(), -bits - 1))
187 } else {
188 Some((frac, -bits))
189 }
190 } else {
191 let bits = 128_i64.checked_sub(i64::from(self.to_imprecise()?.leading_zeros()))?;
192 let frac = UnsignedNumeric {
193 value: self.value >> bits,
194 };
195 if frac.less_than(&HALF) {
196 Some((frac.checked_mul(&TWO_PREC).unwrap(), bits - 1))
197 } else {
198 Some((frac, bits))
199 }
200 }
201 }
202
203 pub fn pow(&self, exp: &Self) -> Option<Self> {
211 if self.eq(&ZERO_PREC) {
212 return Some(ZERO_PREC.clone());
213 }
214
215 let lg = self.log()?;
216 let x = exp.signed().checked_mul(&lg)?;
217 x.exp()
218 }
219
220 pub fn sqrt(&self) -> Option<Self> {
222 self.pow(&HALF)
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229 use crate::InnerUint;
230
231 fn frexp_recombine(frac: UnsignedNumeric, exp: i64) -> UnsignedNumeric {
232 let shifted = if exp >= 0 {
233 UnsignedNumeric {
234 value: frac.value << (exp as usize),
235 }
236 } else {
237 UnsignedNumeric {
238 value: frac.value >> ((-exp) as usize),
239 }
240 };
241 shifted
242 }
243
244 #[test]
245 fn test_signed_exp() {
246 let precision = InnerUint::from(1_000_000_000_u128); let half = UnsignedNumeric { value: half() }.signed();
249 assert!(half.exp().unwrap().almost_eq(
250 &UnsignedNumeric::new(16487212707001282)
251 .checked_div(&UnsignedNumeric::new(10000000000000000))
252 .unwrap(),
253 precision
254 ));
255
256 let three_half = UnsignedNumeric::new(15)
257 .checked_div(&UnsignedNumeric::new(10))
258 .unwrap()
259 .signed();
260 assert!(three_half.exp().unwrap().almost_eq(
261 &UnsignedNumeric::new(44816890703380645)
262 .checked_div(&UnsignedNumeric::new(10000000000000000))
263 .unwrap(),
264 precision
265 ));
266
267 let point_one = UnsignedNumeric::new(1)
268 .checked_div(&UnsignedNumeric::new(10))
269 .unwrap()
270 .signed();
271 assert!(point_one.exp().unwrap().almost_eq(
272 &UnsignedNumeric::new(11051709180756477)
273 .checked_div(&UnsignedNumeric::new(10000000000000000))
274 .unwrap(),
275 precision
276 ));
277
278 let negative = UnsignedNumeric::new(55)
279 .checked_div(&UnsignedNumeric::new(100))
280 .unwrap()
281 .signed()
282 .negate();
283 assert!(negative.exp().unwrap().almost_eq(
284 &UnsignedNumeric::new(5769498103804866)
285 .checked_div(&UnsignedNumeric::new(10000000000000000))
286 .unwrap(),
287 precision
288 ));
289
290 let test = UnsignedNumeric::new(19).signed();
291 assert!(test.exp().unwrap().almost_eq(
292 &UnsignedNumeric::new(178482300963187260)
293 .checked_div(&UnsignedNumeric::new(1000000000))
294 .unwrap(),
295 precision
296 ));
297 }
298
299 #[test]
300 fn test_pow() {
301 let precision = InnerUint::from(5_000_000_000_000_u128); let test = UnsignedNumeric::new(8);
303 let sqrt = test.pow(&HALF).unwrap();
304 let expected = UnsignedNumeric::new(28284271247461903)
305 .checked_div(&UnsignedNumeric::new(10000000000000000))
306 .unwrap();
307 assert!(sqrt.almost_eq(&expected, precision));
308
309 let test2 = UnsignedNumeric::new(55)
310 .checked_div(&UnsignedNumeric::new(100))
311 .unwrap();
312 let squared = test2.pow(&TWO_PREC).unwrap();
313 let expected = UnsignedNumeric::new(3025)
314 .checked_div(&UnsignedNumeric::new(10000))
315 .unwrap();
316 assert!(squared.almost_eq(&expected, precision));
317 }
318
319 #[test]
320 fn test_sqrt() {
321 let precision = InnerUint::from(5_000_000_000_000_u128); let test = UnsignedNumeric::new(12);
323 let sqrt = test.sqrt().unwrap();
324 let expected = UnsignedNumeric::new(34641016151377544)
325 .checked_div(&UnsignedNumeric::new(10000000000000000))
326 .unwrap();
327 assert!(sqrt.almost_eq(&expected, precision));
328 }
329
330 #[test]
331 pub fn test_signed_sqrt() {
332 let precision = InnerUint::from(5_000_000_000_000_u128); let test = SignedNumeric {
334 value: UnsignedNumeric::new(8),
335 is_negative: false,
336 };
337 let sqrt = test.sqrt().unwrap();
338 let expected = UnsignedNumeric::new(28284271247461903)
339 .checked_div(&UnsignedNumeric::new(10000000000000000))
340 .unwrap();
341 assert!(sqrt.value.almost_eq(&expected, precision));
342
343 let neg_test = SignedNumeric {
344 value: UnsignedNumeric::new(8),
345 is_negative: true,
346 };
347 assert!(neg_test.sqrt().is_none());
348 }
349
350 #[test]
351 fn test_exp_zero() {
352 let zero = UnsignedNumeric::zero().signed();
353 let result = zero.exp().unwrap();
354 assert_eq!(result, UnsignedNumeric::one());
355 }
356
357 #[test]
358 fn test_exp_small_negative() {
359 let x = UnsignedNumeric::new(1)
360 .checked_div(&UnsignedNumeric::new(1000))
361 .unwrap()
362 .signed()
363 .negate();
364 let result = x.exp().unwrap();
365
366 let expected = UnsignedNumeric::from_scaled_u128(999_000_499_833_375_000);
368 assert!(
369 result.almost_eq(&expected, InnerUint::from(10_000_000)),
370 "got: {} expected: {}",
371 result.to_string(),
372 expected.to_string()
373 );
374 }
375
376 #[test]
377 fn test_exp_large_positive() {
378 let x = UnsignedNumeric::new(10).signed(); let result = x.exp().unwrap();
380
381 let expected = UnsignedNumeric::from_scaled_u128(22_026_465_794_806_700_000_000);
383 assert!(
384 result.almost_eq(&expected, InnerUint::from(1_000_000_000_000_u64)),
385 "got: {} expected: {}",
386 result.to_string(),
387 expected.to_string()
388 );
389 }
390
391 #[test]
392 fn test_exp_large_negative() {
393 let x = UnsignedNumeric::new(10).signed().negate(); let result = x.exp().unwrap();
395
396 let expected = UnsignedNumeric::from_scaled_u128(45_399_920_000_000); assert!(
398 result.almost_eq(&expected, InnerUint::from(1_000_000_000)),
399 "got: {} expected: {}",
400 result.to_string(),
401 expected.to_string()
402 );
403 }
404
405 #[test]
406 fn test_frexp_zero() {
407 let zero = UnsignedNumeric::zero();
408 let (frac, exp) = zero.frexp().unwrap();
409 assert_eq!(frac, zero);
410 assert_eq!(exp, 0);
411 }
412
413 #[test]
414 fn test_frexp_one() {
415 let one = UnsignedNumeric::one();
416 let (frac, exp) = one.frexp().unwrap();
417 let recombined = frexp_recombine(frac.clone(), exp);
419 assert!(
420 recombined.almost_eq(&one, InnerUint::from(1_000_000_000)),
421 "Expected: {}, Got: {} × 2^{} = {}",
422 one.to_string(),
423 frac.to_string(),
424 exp,
425 recombined.to_string()
426 );
427 assert!(frac.greater_than_or_equal(&HALF));
428 assert!(frac.less_than(&ONE_PREC));
429 }
430
431 #[test]
432 fn test_frexp_two() {
433 let two = UnsignedNumeric::new(2);
434 let (frac, exp) = two.frexp().unwrap();
435 let recombined = frexp_recombine(frac.clone(), exp);
436 assert!(
437 recombined.almost_eq(&two, InnerUint::from(1_000_000_000)),
438 "Expected: {}, Got: {} × 2^{} = {}",
439 two.to_string(),
440 frac.to_string(),
441 exp,
442 recombined.to_string()
443 );
444 assert!(frac.greater_than_or_equal(&HALF));
445 assert!(frac.less_than(&ONE_PREC));
446 }
447
448 #[test]
449 fn test_frexp_fractional() {
450 let val = UnsignedNumeric::new(3)
451 .checked_div(&UnsignedNumeric::new(4)) .unwrap();
453 let (frac, exp) = val.frexp().unwrap();
454 let recombined = frexp_recombine(frac.clone(), exp);
455
456 assert!(
457 recombined.almost_eq(&val, InnerUint::from(1_000_000_000)),
458 "Expected: {}, Got: {} × 2^{} = {}",
459 val.to_string(),
460 frac.to_string(),
461 exp,
462 recombined.to_string()
463 );
464 assert!(frac.greater_than_or_equal(&HALF));
465 assert!(frac.less_than(&ONE_PREC));
466 }
467
468 #[test]
469 fn test_frexp_large_value() {
470 let val = UnsignedNumeric {
471 value: InnerUint([0, 0, 1]), };
473 let (frac, exp) = val.frexp().unwrap();
474 let recombined = frexp_recombine(frac.clone(), exp);
475
476 assert!(
477 recombined.almost_eq(&val, InnerUint::from(10_000_000_000_u64)),
478 "Expected: {}, Got: {} × 2^{} = {}",
479 val.to_string(),
480 frac.to_string(),
481 exp,
482 recombined.to_string()
483 );
484 }
485}