1extern crate alloc;
2
3use core::{cmp::Ordering, fmt::Display, ops::*, str::FromStr};
4use num_bigint::{BigInt, BigUint, Sign};
5use num_integer::Integer;
6use num_traits::{One, Signed, ToPrimitive, Zero};
7use quoth::Parsable;
8
9#[cfg(test)]
10use alloc::format;
11
12use crate::parsing::ParsedSafeInt;
13
14#[derive(Clone, Debug, Eq, Ord, Hash, Default, PartialEq, PartialOrd)]
28#[repr(transparent)]
29pub struct SafeInt(BigInt);
30
31pub const DEFAULT_MAX_ITERS: usize = 4_096;
34const MAX_EXACT_EXPONENT: u32 = 1_024;
35
36impl FromStr for SafeInt {
37 type Err = quoth::Error;
38
39 fn from_str(s: &str) -> Result<Self, Self::Err> {
40 let mut stream = quoth::ParseStream::from(s);
41 let parsed = ParsedSafeInt::parse(&mut stream)?;
42 Ok(parsed.value)
43 }
44}
45
46impl Display for SafeInt {
47 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48 write!(f, "{}", self.0)
49 }
50}
51
52impl SafeInt {
53 pub fn zero() -> SafeInt {
55 SafeInt(BigInt::zero())
56 }
57 pub fn one() -> SafeInt {
59 SafeInt(BigInt::one())
60 }
61 pub fn neg_one() -> SafeInt {
63 -SafeInt::one()
64 }
65 pub const ONE: ConstSafeInt<2> = ConstSafeInt::from_bytes([0, 1]);
67 pub const NEG_ONE: ConstSafeInt<2> = ConstSafeInt::from_bytes([1, 1]);
69
70 #[inline(always)]
72 pub const fn raw(&self) -> &BigInt {
73 &self.0
74 }
75
76 #[inline(always)]
78 pub const fn from_raw(value: BigInt) -> SafeInt {
79 SafeInt(value)
80 }
81
82 #[inline(always)]
84 pub fn is_negative(&self) -> bool {
85 self.0.sign() == Sign::Minus
86 }
87
88 #[inline(always)]
90 pub fn is_even(&self) -> bool {
91 self.0.is_even()
92 }
93
94 #[inline(always)]
96 pub fn is_odd(&self) -> bool {
97 self.0.is_odd()
98 }
99
100 #[inline(always)]
102 pub fn is_zero(&self) -> bool {
103 self.0.is_zero()
104 }
105
106 #[inline(always)]
108 pub fn abs(self) -> SafeInt {
109 SafeInt(self.0.abs())
110 }
111
112 #[inline(always)]
114 pub fn pow(self, exp: u32) -> SafeInt {
115 SafeInt(self.0.pow(exp))
116 }
117
118 #[inline(always)]
121 pub fn div_rem(self, other: SafeInt) -> Option<(SafeInt, SafeInt)> {
122 if other.0.is_zero() {
123 None
124 } else {
125 let (div, rem) = self.0.div_rem(&other.0);
126 Some((SafeInt(div), SafeInt(rem)))
127 }
128 }
129
130 #[inline(always)]
132 pub fn to_u8(&self) -> Option<u8> {
133 self.0.to_u8()
134 }
135
136 #[inline(always)]
138 pub fn to_u16(&self) -> Option<u16> {
139 self.0.to_u16()
140 }
141
142 #[inline(always)]
144 pub fn to_u32(&self) -> Option<u32> {
145 self.0.to_u32()
146 }
147
148 #[inline(always)]
150 pub fn to_u64(&self) -> Option<u64> {
151 self.0.to_u64()
152 }
153
154 #[inline(always)]
156 pub fn to_u128(&self) -> Option<u128> {
157 self.0.to_u128()
158 }
159
160 #[inline(always)]
162 pub fn to_i8(&self) -> Option<i8> {
163 self.0.to_i8()
164 }
165
166 #[inline(always)]
168 pub fn to_i16(&self) -> Option<i16> {
169 self.0.to_i16()
170 }
171
172 #[inline(always)]
174 pub fn to_i32(&self) -> Option<i32> {
175 self.0.to_i32()
176 }
177
178 #[inline(always)]
180 pub fn to_i64(&self) -> Option<i64> {
181 self.0.to_i64()
182 }
183
184 #[inline(always)]
186 pub fn to_i128(&self) -> Option<i128> {
187 self.0.to_i128()
188 }
189
190 #[inline(always)]
192 pub fn to_usize(&self) -> Option<usize> {
193 self.0.to_usize()
194 }
195
196 #[inline(always)]
198 pub fn to_isize(&self) -> Option<isize> {
199 self.0.to_isize()
200 }
201
202 #[inline(always)]
204 pub fn ceil_div(&self, b: SafeInt) -> Option<SafeInt> {
205 let one = SafeInt::from(1);
206 Some(((self - one.clone()) / b)? + one)
207 }
208
209 pub fn pow_ratio_scaled(
234 base_numerator: &SafeInt,
235 base_denominator: &SafeInt,
236 exponent_numerator: &SafeInt,
237 exponent_denominator: &SafeInt,
238 precision: u32,
239 scale: &SafeInt,
240 ) -> Option<SafeInt> {
241 Self::pow_ratio_scaled_with_max_iters(
242 base_numerator,
243 base_denominator,
244 exponent_numerator,
245 exponent_denominator,
246 precision,
247 scale,
248 None,
249 )
250 }
251
252 pub fn pow_ratio_scaled_with_max_iters(
256 base_numerator: &SafeInt,
257 base_denominator: &SafeInt,
258 exponent_numerator: &SafeInt,
259 exponent_denominator: &SafeInt,
260 precision: u32,
261 scale: &SafeInt,
262 max_iters: Option<usize>,
263 ) -> Option<SafeInt> {
264 if base_denominator.is_zero() || exponent_denominator.is_zero() {
265 return None;
266 }
267 if base_numerator.is_zero() {
268 return Some(SafeInt::zero());
269 }
270 if scale.is_negative() {
271 return None;
272 }
273 if base_numerator.is_negative() || base_denominator.is_negative() {
275 return None;
276 }
277
278 let base_num = base_numerator.0.to_biguint()?;
279 let base_den = base_denominator.0.to_biguint()?;
280 let mut exp_num = exponent_numerator.0.to_biguint()?;
281 let mut exp_den = exponent_denominator.0.to_biguint()?;
282
283 if exp_num.is_zero() {
284 return Some(scale.clone());
285 }
286
287 let g = gcd_biguint(exp_num.clone(), exp_den.clone());
288 if g > BigUint::one() {
289 exp_num /= g.clone();
290 exp_den /= g;
291 }
292
293 let scale_abs = scale.0.to_biguint()?;
294 let scale_bits = u32::try_from(scale_abs.bits()).unwrap_or(u32::MAX);
295
296 let exp_num_bits = exp_num.bits();
297 let exp_den_bits = exp_den.bits();
298 if exp_num_bits <= 32 && exp_den_bits <= 32 {
299 let exp_num_u32 = exp_num.to_u32()?;
300 let exp_den_u32 = exp_den.to_u32()?;
301 if exp_den_u32 == 0 {
302 return None;
303 }
304
305 if exp_num_u32 <= MAX_EXACT_EXPONENT {
306 let base_num_pow = base_num.pow(exp_num_u32);
307 let base_den_pow = base_den.pow(exp_num_u32);
308 let scale_pow = scale_abs.pow(exp_den_u32);
309
310 let target_num = base_num_pow * scale_pow;
311 let target_den = base_den_pow;
312
313 let root = nth_root_ratio_floor(&target_num, &target_den, exp_den_u32);
314 return Some(SafeInt(BigInt::from_biguint(Sign::Plus, root)));
315 }
316 }
317
318 let requested_precision = precision.max(32).max(scale_bits.saturating_add(8));
325 let guard_bits: u32 = 24;
326 let internal_precision = requested_precision.saturating_add(guard_bits);
327 let default_max_iters = DEFAULT_MAX_ITERS.min(internal_precision as usize + 128);
328 let max_iters = max_iters.unwrap_or(default_max_iters).max(1);
329
330 let target_scale_uint = BigUint::one() << requested_precision;
331 let guard_factor_uint = BigUint::one() << guard_bits;
332 let internal_scale_uint = &target_scale_uint << guard_bits;
333
334 let target_scale = BigInt::from_biguint(Sign::Plus, target_scale_uint.clone());
335 let guard_factor = BigInt::from_biguint(Sign::Plus, guard_factor_uint.clone());
336 let internal_scale = BigInt::from_biguint(Sign::Plus, internal_scale_uint.clone());
337
338 let ln_half = ln1p_fixed(
339 &(-(&internal_scale >> 1usize)),
340 &internal_scale,
341 &guard_factor,
342 max_iters,
343 );
344 let ln_two = -ln_half;
345
346 let ln_num = ln_biguint(
349 &base_num,
350 internal_precision,
351 &internal_scale_uint,
352 &internal_scale,
353 &guard_factor,
354 &ln_two,
355 max_iters,
356 );
357 let ln_den = ln_biguint(
358 &base_den,
359 internal_precision,
360 &internal_scale_uint,
361 &internal_scale,
362 &guard_factor,
363 &ln_two,
364 max_iters,
365 );
366 let ln_base = ln_num - ln_den;
367
368 let ln_scaled = (ln_base * BigInt::from_biguint(Sign::Plus, exp_num))
369 .div_floor(&BigInt::from_biguint(Sign::Plus, exp_den));
370 let exp_fp = exp_fixed(&ln_scaled, &internal_scale, &guard_factor, max_iters);
371 let exp_requested = round_to_precision(&exp_fp, &guard_factor);
372 let result =
373 (exp_requested * BigInt::from_biguint(Sign::Plus, scale_abs)).div_floor(&target_scale);
374
375 Some(SafeInt(result))
376 }
377
378 pub fn pow_bigint_base(
381 base: &SafeInt,
382 exponent_numerator: &SafeInt,
383 exponent_denominator: &SafeInt,
384 precision: u32,
385 scale: &SafeInt,
386 ) -> Option<SafeInt> {
387 Self::pow_bigint_base_scaled_with_max_iters(
388 base,
389 exponent_numerator,
390 exponent_denominator,
391 precision,
392 scale,
393 None,
394 )
395 }
396
397 fn pow_bigint_base_scaled_with_max_iters(
398 base: &SafeInt,
399 exponent_numerator: &SafeInt,
400 exponent_denominator: &SafeInt,
401 precision: u32,
402 scale: &SafeInt,
403 max_iters: Option<usize>,
404 ) -> Option<SafeInt> {
405 use num_bigint::{BigInt, BigUint, Sign};
406 use num_integer::Integer;
407 use num_traits::{One, ToPrimitive, Zero};
408
409 if exponent_denominator.is_zero() {
411 return None;
412 }
413 if base.is_zero() {
414 return Some(SafeInt::zero());
417 }
418 if scale.is_negative() {
419 return None;
420 }
421 if base.is_negative() {
423 return None;
424 }
425
426 let base_uint = base.0.to_biguint()?;
428
429 let mut exp_num = exponent_numerator.0.to_biguint()?;
430 let mut exp_den = exponent_denominator.0.to_biguint()?;
431
432 if exp_num.is_zero() {
433 return Some(scale.clone());
435 }
436
437 let g = gcd_biguint(exp_num.clone(), exp_den.clone());
439 if g > BigUint::one() {
440 exp_num /= g.clone();
441 exp_den /= g;
442 }
443
444 let scale_abs = scale.0.to_biguint()?;
445 let scale_bits = u32::try_from(scale_abs.bits()).unwrap_or(u32::MAX);
446
447 let exp_num_bits = exp_num.bits();
449 let exp_den_bits = exp_den.bits();
450 if exp_num_bits <= 32 && exp_den_bits <= 32 {
451 let exp_num_u32 = exp_num.to_u32()?;
452 let exp_den_u32 = exp_den.to_u32()?;
453 if exp_den_u32 == 0 {
454 return None;
455 }
456
457 if exp_num_u32 <= MAX_EXACT_EXPONENT {
458 let base_pow = base_uint.pow(exp_num_u32);
465 let scale_pow = scale_abs.pow(exp_den_u32);
466
467 let target_num = base_pow * scale_pow;
468 let target_den = BigUint::one();
469
470 let root = nth_root_ratio_floor(&target_num, &target_den, exp_den_u32);
471 return Some(SafeInt(BigInt::from_biguint(Sign::Plus, root)));
472 }
473 }
474
475 let requested_precision = precision.max(32).max(scale_bits.saturating_add(8));
479 let guard_bits: u32 = 24;
480 let internal_precision = requested_precision.saturating_add(guard_bits);
481 let default_max_iters = DEFAULT_MAX_ITERS.min(internal_precision as usize + 128);
482 let max_iters = max_iters.unwrap_or(default_max_iters).max(1);
483
484 let target_scale_uint = BigUint::one() << requested_precision;
485 let guard_factor_uint = BigUint::one() << guard_bits;
486 let internal_scale_uint = &target_scale_uint << guard_bits;
487
488 let target_scale = BigInt::from_biguint(Sign::Plus, target_scale_uint.clone());
489 let guard_factor = BigInt::from_biguint(Sign::Plus, guard_factor_uint.clone());
490 let internal_scale = BigInt::from_biguint(Sign::Plus, internal_scale_uint.clone());
491
492 let ln_half = ln1p_fixed(
494 &(-(&internal_scale >> 1usize)),
495 &internal_scale,
496 &guard_factor,
497 max_iters,
498 );
499 let ln_two = -ln_half;
500
501 let ln_base = ln_biguint(
503 &base_uint,
504 internal_precision,
505 &internal_scale_uint,
506 &internal_scale,
507 &guard_factor,
508 &ln_two,
509 max_iters,
510 );
511
512 let ln_scaled = (ln_base * BigInt::from_biguint(Sign::Plus, exp_num))
514 .div_floor(&BigInt::from_biguint(Sign::Plus, exp_den));
515
516 let exp_fp = exp_fixed(&ln_scaled, &internal_scale, &guard_factor, max_iters);
518
519 let exp_requested = round_to_precision(&exp_fp, &guard_factor);
521
522 let result =
524 (exp_requested * BigInt::from_biguint(Sign::Plus, scale_abs)).div_floor(&target_scale);
525
526 Some(SafeInt(result))
527 }
528}
529
530fn gcd_biguint(mut a: BigUint, mut b: BigUint) -> BigUint {
531 while !b.is_zero() {
532 let r = &a % &b;
533 a = b;
534 b = r;
535 }
536 a
537}
538
539fn pow_biguint(base: &BigUint, exp: u32) -> BigUint {
540 base.pow(exp)
541}
542
543fn nth_root_ratio_floor(target_num: &BigUint, target_den: &BigUint, q: u32) -> BigUint {
544 if q == 0 {
545 return BigUint::zero();
546 }
547
548 let mut low = BigUint::zero();
549 let mut high = BigUint::one();
550 while pow_biguint(&high, q) * target_den <= *target_num {
551 high <<= 1;
552 }
553
554 while low < high {
555 let mid = (&low + &high + 1u32) >> 1;
556 if pow_biguint(&mid, q) * target_den <= *target_num {
557 low = mid;
558 } else {
559 high = mid - BigUint::one();
560 }
561 }
562
563 low
564}
565
566fn ln1p_fixed(x_fp: &BigInt, scale: &BigInt, guard_factor: &BigInt, max_iters: usize) -> BigInt {
567 let mut term = x_fp.clone();
570 let mut result = term.clone();
571 let mut prev_rounded = round_to_precision(&result, guard_factor);
572 for n in 2..=max_iters {
573 term = (&term * x_fp).div_floor(scale);
574 if term.is_zero() {
575 break;
576 }
577
578 let next = term.div_floor(&BigInt::from(n as u32));
579 if next.is_zero() {
580 break;
581 }
582
583 if n % 2 == 0 {
584 result -= &next;
585 } else {
586 result += &next;
587 }
588
589 let rounded = round_to_precision(&result, guard_factor);
590 if next.abs() < guard_factor.abs() || rounded == prev_rounded {
591 break;
592 }
593 prev_rounded = rounded;
594 }
595
596 result
597}
598
599fn exp_fixed(x_fp: &BigInt, scale: &BigInt, guard_factor: &BigInt, max_iters: usize) -> BigInt {
600 let mut term = scale.clone(); let mut result = term.clone();
604 let mut prev_rounded = round_to_precision(&result, guard_factor);
605 for n in 1..=max_iters {
606 term = (&term * x_fp).div_floor(&(scale * BigInt::from(n as u32)));
607 if term.is_zero() {
608 break;
609 }
610 result += &term;
611
612 let rounded = round_to_precision(&result, guard_factor);
613 if term.abs() < guard_factor.abs() || rounded == prev_rounded {
614 break;
615 }
616 prev_rounded = rounded;
617 }
618
619 result
620}
621
622fn ln_biguint(
623 value: &BigUint,
624 internal_precision: u32,
625 internal_scale_uint: &BigUint,
626 internal_scale: &BigInt,
627 guard_factor: &BigInt,
628 ln_two: &BigInt,
629 max_iters: usize,
630) -> BigInt {
631 debug_assert!(!value.is_zero());
632 if value.is_zero() {
633 return BigInt::zero();
634 }
635
636 let int_prec = internal_precision as usize;
637 let mut shift = value.bits().saturating_sub(1);
638 let mut mantissa = value.clone() << int_prec;
639 mantissa >>= shift;
640
641 let half_scale = internal_scale_uint >> 1;
643 let scale_plus_half = internal_scale_uint + &half_scale;
644 if mantissa >= scale_plus_half {
645 mantissa >>= 1;
646 shift = shift.saturating_add(1);
647 }
648
649 let mantissa_int = BigInt::from_biguint(Sign::Plus, mantissa);
650 let ln_mantissa = ln1p_fixed(
651 &(mantissa_int - internal_scale),
652 internal_scale,
653 guard_factor,
654 max_iters,
655 );
656
657 ln_mantissa + ln_two * BigInt::from(shift)
658}
659
660fn round_to_precision(value: &BigInt, guard_factor: &BigInt) -> BigInt {
661 let (mut truncated, remainder) = value.div_rem(guard_factor);
662 if !remainder.is_zero() && (remainder.abs() << 1) >= guard_factor.abs() {
663 truncated += remainder.signum();
664 }
665 truncated
666}
667
668impl Neg for SafeInt {
669 type Output = SafeInt;
670
671 #[inline(always)]
672 fn neg(self) -> SafeInt {
673 SafeInt(-self.0)
674 }
675}
676
677impl Neg for &SafeInt {
678 type Output = SafeInt;
679
680 #[inline(always)]
681 fn neg(self) -> SafeInt {
682 SafeInt(-self.0.clone())
683 }
684}
685
686macro_rules! impl_pair_ops {
687 ($trait:ident, $method:ident) => {
688 impl $trait for SafeInt {
689 type Output = SafeInt;
690
691 #[inline(always)]
692 fn $method(self, other: SafeInt) -> SafeInt {
693 SafeInt(self.0.$method(other.0))
694 }
695 }
696
697 impl $trait<&SafeInt> for SafeInt {
698 type Output = SafeInt;
699
700 #[inline(always)]
701 fn $method(self, other: &SafeInt) -> SafeInt {
702 SafeInt(self.0.$method(&other.0))
703 }
704 }
705
706 impl $trait<SafeInt> for &SafeInt {
707 type Output = SafeInt;
708
709 #[inline(always)]
710 fn $method(self, other: SafeInt) -> SafeInt {
711 SafeInt(self.0.clone().$method(other.0))
712 }
713 }
714
715 impl $trait<&SafeInt> for &SafeInt {
716 type Output = SafeInt;
717
718 #[inline(always)]
719 fn $method(self, other: &SafeInt) -> SafeInt {
720 SafeInt(self.0.clone().$method(&other.0))
721 }
722 }
723 };
724}
725
726macro_rules! impl_pair_rem_ops {
727 () => {
728 impl Rem for SafeInt {
729 type Output = Option<SafeInt>;
730
731 #[inline(always)]
732 fn rem(self, other: SafeInt) -> Option<SafeInt> {
733 if other.0.is_zero() {
734 None
735 } else {
736 Some(SafeInt(self.0 % other.0))
737 }
738 }
739 }
740
741 impl Rem<&SafeInt> for SafeInt {
742 type Output = Option<SafeInt>;
743
744 #[inline(always)]
745 fn rem(self, other: &SafeInt) -> Option<SafeInt> {
746 if other.0.is_zero() {
747 None
748 } else {
749 Some(SafeInt(self.0 % &other.0))
750 }
751 }
752 }
753
754 impl Rem<SafeInt> for &SafeInt {
755 type Output = Option<SafeInt>;
756
757 #[inline(always)]
758 fn rem(self, other: SafeInt) -> Option<SafeInt> {
759 if other.0.is_zero() {
760 None
761 } else {
762 Some(SafeInt(self.0.clone() % other.0))
763 }
764 }
765 }
766
767 impl Rem<&SafeInt> for &SafeInt {
768 type Output = Option<SafeInt>;
769
770 #[inline(always)]
771 fn rem(self, other: &SafeInt) -> Option<SafeInt> {
772 if other.0.is_zero() {
773 None
774 } else {
775 Some(SafeInt(self.0.clone() % &other.0))
776 }
777 }
778 }
779 };
780}
781
782impl_pair_ops!(Add, add);
783impl_pair_ops!(Sub, sub);
784impl_pair_ops!(Mul, mul);
785impl_pair_rem_ops!();
786impl_pair_ops!(BitAnd, bitand);
787impl_pair_ops!(BitOr, bitor);
788impl_pair_ops!(BitXor, bitxor);
789
790macro_rules! impl_prim_ops {
791 ($trait:ident, $method:ident, [$($t:ty),*]) => {
792 $(
793 impl $trait<$t> for SafeInt {
794 type Output = SafeInt;
795
796 #[inline(always)]
797 fn $method(self, other: $t) -> SafeInt {
798 SafeInt(self.0.$method(BigInt::from(other)))
799 }
800 }
801
802 impl $trait<$t> for &SafeInt {
803 type Output = SafeInt;
804
805 #[inline(always)]
806 fn $method(self, other: $t) -> SafeInt {
807 SafeInt(self.0.clone().$method(BigInt::from(other)))
808 }
809 }
810
811 impl $trait<SafeInt> for $t {
812 type Output = SafeInt;
813
814 #[inline(always)]
815 fn $method(self, other: SafeInt) -> SafeInt {
816 SafeInt(BigInt::from(self).$method(other.0))
817 }
818 }
819
820 impl $trait<&SafeInt> for $t {
821 type Output = SafeInt;
822
823 #[inline(always)]
824 fn $method(self, other: &SafeInt) -> SafeInt {
825 SafeInt(BigInt::from(self).$method(other.0.clone()))
826 }
827 }
828 )*
829 };
830}
831
832macro_rules! impl_prim_rem_ops {
833 ($($t:ty),*) => {
834 $(
835 impl Rem<$t> for SafeInt {
836 type Output = Option<SafeInt>;
837
838 #[inline(always)]
839 fn rem(self, other: $t) -> Option<SafeInt> {
840 if other == 0 {
841 None
842 } else {
843 Some(SafeInt(self.0 % BigInt::from(other)))
844 }
845 }
846 }
847
848 impl Rem<$t> for &SafeInt {
849 type Output = Option<SafeInt>;
850
851 #[inline(always)]
852 fn rem(self, other: $t) -> Option<SafeInt> {
853 if other == 0 {
854 None
855 } else {
856 Some(SafeInt(self.0.clone() % BigInt::from(other)))
857 }
858 }
859 }
860
861 impl Rem<SafeInt> for $t {
862 type Output = Option<SafeInt>;
863
864 #[inline(always)]
865 fn rem(self, other: SafeInt) -> Option<SafeInt> {
866 if other.0.is_zero() {
867 None
868 } else {
869 Some(SafeInt(BigInt::from(self) % other.0))
870 }
871 }
872 }
873
874 impl Rem<&SafeInt> for $t {
875 type Output = Option<SafeInt>;
876
877 #[inline(always)]
878 fn rem(self, other: &SafeInt) -> Option<SafeInt> {
879 if other.0.is_zero() {
880 None
881 } else {
882 Some(SafeInt(BigInt::from(self) % other.0.clone()))
883 }
884 }
885 }
886 )*
887 };
888}
889
890impl_prim_ops!(
891 Add,
892 add,
893 [
894 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
895 ]
896);
897impl_prim_ops!(
898 Sub,
899 sub,
900 [
901 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
902 ]
903);
904impl_prim_ops!(
905 Mul,
906 mul,
907 [
908 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
909 ]
910);
911impl_prim_rem_ops!(
912 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
913);
914impl_prim_ops!(
915 BitAnd,
916 bitand,
917 [
918 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
919 ]
920);
921impl_prim_ops!(
922 BitOr,
923 bitor,
924 [
925 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
926 ]
927);
928impl_prim_ops!(
929 BitXor,
930 bitxor,
931 [
932 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
933 ]
934);
935
936impl AddAssign<SafeInt> for SafeInt {
937 #[inline(always)]
938 fn add_assign(&mut self, rhs: SafeInt) {
939 self.0 += rhs.0;
940 }
941}
942
943impl AddAssign<&SafeInt> for SafeInt {
944 #[inline(always)]
945 fn add_assign(&mut self, rhs: &SafeInt) {
946 self.0 += &rhs.0;
947 }
948}
949
950impl SubAssign<SafeInt> for SafeInt {
951 #[inline(always)]
952 fn sub_assign(&mut self, rhs: SafeInt) {
953 self.0 -= rhs.0;
954 }
955}
956
957impl SubAssign<&SafeInt> for SafeInt {
958 #[inline(always)]
959 fn sub_assign(&mut self, rhs: &SafeInt) {
960 self.0 -= &rhs.0;
961 }
962}
963
964impl MulAssign<SafeInt> for SafeInt {
965 #[inline(always)]
966 fn mul_assign(&mut self, rhs: SafeInt) {
967 self.0 *= rhs.0;
968 }
969}
970
971impl MulAssign<&SafeInt> for SafeInt {
972 #[inline(always)]
973 fn mul_assign(&mut self, rhs: &SafeInt) {
974 self.0 *= &rhs.0;
975 }
976}
977
978impl RemAssign<SafeInt> for SafeInt {
979 #[inline(always)]
980 fn rem_assign(&mut self, rhs: SafeInt) {
981 if !rhs.0.is_zero() {
982 self.0 %= rhs.0;
983 }
984 }
985}
986
987impl RemAssign<&SafeInt> for SafeInt {
988 #[inline(always)]
989 fn rem_assign(&mut self, rhs: &SafeInt) {
990 if !rhs.0.is_zero() {
991 self.0 %= &rhs.0;
992 }
993 }
994}
995
996impl BitAndAssign<SafeInt> for SafeInt {
997 #[inline(always)]
998 fn bitand_assign(&mut self, rhs: SafeInt) {
999 self.0 &= rhs.0;
1000 }
1001}
1002
1003impl BitAndAssign<&SafeInt> for SafeInt {
1004 #[inline(always)]
1005 fn bitand_assign(&mut self, rhs: &SafeInt) {
1006 self.0 &= &rhs.0;
1007 }
1008}
1009
1010impl BitOrAssign<SafeInt> for SafeInt {
1011 #[inline(always)]
1012 fn bitor_assign(&mut self, rhs: SafeInt) {
1013 self.0 |= rhs.0;
1014 }
1015}
1016
1017impl BitOrAssign<&SafeInt> for SafeInt {
1018 #[inline(always)]
1019 fn bitor_assign(&mut self, rhs: &SafeInt) {
1020 self.0 |= &rhs.0;
1021 }
1022}
1023
1024impl BitXorAssign<SafeInt> for SafeInt {
1025 #[inline(always)]
1026 fn bitxor_assign(&mut self, rhs: SafeInt) {
1027 self.0 ^= rhs.0;
1028 }
1029}
1030
1031impl BitXorAssign<&SafeInt> for SafeInt {
1032 #[inline(always)]
1033 fn bitxor_assign(&mut self, rhs: &SafeInt) {
1034 self.0 ^= &rhs.0;
1035 }
1036}
1037
1038macro_rules! impl_assign_prim {
1039 ($trait:ident, $method:ident, $op:tt, [$($t:ty),*]) => {
1040 $(
1041 impl $trait<$t> for SafeInt {
1042 #[inline(always)]
1043 fn $method(&mut self, rhs: $t) {
1044 self.0 $op BigInt::from(rhs);
1045 }
1046 }
1047 )*
1048 };
1049}
1050
1051macro_rules! impl_rem_assign_prim {
1052 ($($t:ty),*) => {
1053 $(
1054 impl RemAssign<$t> for SafeInt {
1055 #[inline(always)]
1056 fn rem_assign(&mut self, rhs: $t) {
1057 if rhs != 0 {
1058 self.0 %= BigInt::from(rhs);
1059 }
1060 }
1061 }
1062 )*
1063 };
1064}
1065
1066impl_assign_prim!(AddAssign, add_assign, +=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1067impl_assign_prim!(SubAssign, sub_assign, -=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1068impl_assign_prim!(MulAssign, mul_assign, *=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1069impl_rem_assign_prim!(
1070 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1071);
1072impl_assign_prim!(BitAndAssign, bitand_assign, &=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1073impl_assign_prim!(BitOrAssign, bitor_assign, |=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1074impl_assign_prim!(BitXorAssign, bitxor_assign, ^=, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]);
1075
1076impl Div for SafeInt {
1077 type Output = Option<SafeInt>;
1078
1079 #[inline(always)]
1080 fn div(self, other: SafeInt) -> Option<SafeInt> {
1081 if other.0.is_zero() {
1082 None
1083 } else {
1084 Some(SafeInt(self.0 / other.0))
1085 }
1086 }
1087}
1088
1089impl Div<&SafeInt> for SafeInt {
1090 type Output = Option<SafeInt>;
1091
1092 #[inline(always)]
1093 fn div(self, other: &SafeInt) -> Option<SafeInt> {
1094 if other.0.is_zero() {
1095 None
1096 } else {
1097 Some(SafeInt(self.0 / &other.0))
1098 }
1099 }
1100}
1101
1102impl Div<SafeInt> for &SafeInt {
1103 type Output = Option<SafeInt>;
1104
1105 #[inline(always)]
1106 fn div(self, other: SafeInt) -> Option<SafeInt> {
1107 if other.0.is_zero() {
1108 None
1109 } else {
1110 Some(SafeInt(self.0.clone() / other.0))
1111 }
1112 }
1113}
1114
1115impl Div<&SafeInt> for &SafeInt {
1116 type Output = Option<SafeInt>;
1117
1118 #[inline(always)]
1119 fn div(self, other: &SafeInt) -> Option<SafeInt> {
1120 if other.0.is_zero() {
1121 None
1122 } else {
1123 Some(SafeInt(self.0.clone() / &other.0))
1124 }
1125 }
1126}
1127
1128macro_rules! impl_div_safeint_rhs_prim {
1129 ($($t:ty),*) => {
1130 $(
1131 impl Div<$t> for SafeInt {
1132 type Output = Option<SafeInt>;
1133
1134 #[inline(always)]
1135 fn div(self, other: $t) -> Option<SafeInt> {
1136 if other == 0 {
1137 None
1138 } else {
1139 Some(SafeInt(self.0 / BigInt::from(other)))
1140 }
1141 }
1142 }
1143
1144 impl Div<$t> for &SafeInt {
1145 type Output = Option<SafeInt>;
1146
1147 #[inline(always)]
1148 fn div(self, other: $t) -> Option<SafeInt> {
1149 if other == 0 {
1150 None
1151 } else {
1152 Some(SafeInt(self.0.clone() / BigInt::from(other)))
1153 }
1154 }
1155 }
1156 )*
1157 };
1158}
1159
1160macro_rules! impl_div_prim_lhs_safeint {
1161 ($($t:ty),*) => {
1162 $(
1163 impl Div<SafeInt> for $t {
1164 type Output = Option<SafeInt>;
1165
1166 #[inline(always)]
1167 fn div(self, other: SafeInt) -> Option<SafeInt> {
1168 if other.0.is_zero() {
1169 None
1170 } else {
1171 Some(SafeInt(BigInt::from(self) / other.0))
1172 }
1173 }
1174 }
1175
1176 impl Div<&SafeInt> for $t {
1177 type Output = Option<SafeInt>;
1178
1179 #[inline(always)]
1180 fn div(self, other: &SafeInt) -> Option<SafeInt> {
1181 if other.0.is_zero() {
1182 None
1183 } else {
1184 Some(SafeInt(BigInt::from(self) / other.0.clone()))
1185 }
1186 }
1187 }
1188 )*
1189 };
1190}
1191
1192impl_div_safeint_rhs_prim!(
1193 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1194);
1195impl_div_prim_lhs_safeint!(
1196 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1197);
1198
1199impl<T: Into<BigInt>> From<T> for SafeInt {
1200 #[inline(always)]
1201 fn from(value: T) -> SafeInt {
1202 SafeInt(value.into())
1203 }
1204}
1205
1206impl<T> PartialEq<T> for SafeInt
1207where
1208 T: Copy,
1209 BigInt: From<T>,
1210{
1211 #[inline(always)]
1212 fn eq(&self, other: &T) -> bool {
1213 self.0 == BigInt::from(*other)
1214 }
1215}
1216
1217impl<T> PartialOrd<T> for SafeInt
1218where
1219 T: Copy,
1220 BigInt: From<T>,
1221{
1222 #[inline(always)]
1223 fn partial_cmp(&self, other: &T) -> Option<Ordering> {
1224 self.0.partial_cmp(&BigInt::from(*other))
1225 }
1226}
1227
1228macro_rules! impl_prim_cmp {
1229 ($($t:ty),*) => {
1230 $(
1231 impl PartialEq<SafeInt> for $t {
1232 #[inline(always)]
1233 fn eq(&self, other: &SafeInt) -> bool {
1234 BigInt::from(*self) == other.0
1235 }
1236 }
1237
1238 impl PartialOrd<SafeInt> for $t {
1239 #[inline(always)]
1240 fn partial_cmp(&self, other: &SafeInt) -> Option<Ordering> {
1241 BigInt::from(*self).partial_cmp(&other.0)
1242 }
1243 }
1244 )*
1245 };
1246}
1247
1248impl_prim_cmp!(
1249 u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
1250);
1251
1252#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1263#[repr(C)]
1264pub struct ConstSafeInt<const N: usize>([u8; N]);
1265
1266impl<const N: usize> ConstSafeInt<N> {
1267 pub const fn from_bytes(value: [u8; N]) -> Self {
1269 Self(value)
1270 }
1271
1272 pub const fn as_bytes(&self) -> &[u8; N] {
1274 &self.0
1275 }
1276
1277 pub fn to_val(self) -> SafeInt {
1279 self.into()
1280 }
1281}
1282
1283impl ConstSafeInt<17> {
1284 pub const fn from_i128(value: i128) -> Self {
1295 let is_neg = value < 0;
1296 let value = if value == i128::MIN {
1297 i128::MAX as u128 + 1
1298 } else {
1299 value.unsigned_abs()
1300 };
1301 let mut res = Self::from_u128(value);
1302 if is_neg {
1303 res.0[0] = 1;
1304 }
1305 res
1306 }
1307 pub const fn from_u128(value: u128) -> Self {
1309 let mut res = [0; 17];
1310 let mut value = value;
1311 let mut i = 17;
1312 while i > 0 {
1313 i -= 1;
1314 res[i] = (value & 0xff) as u8;
1315 value >>= 8;
1316 }
1317 Self(res)
1318 }
1319}
1320
1321impl<const N: usize> From<ConstSafeInt<N>> for SafeInt {
1322 #[inline(always)]
1323 fn from(value: ConstSafeInt<N>) -> SafeInt {
1324 let pos = value.0.first().cloned().unwrap_or(0) == 0;
1325 let magnitude = BigUint::from_bytes_be(&value.0[1..]);
1326 let mut res = SafeInt(BigInt::from_biguint(Sign::Plus, magnitude));
1327 if !pos {
1328 res = -res;
1329 }
1330 res
1331 }
1332}
1333
1334impl<const N: usize> From<&ConstSafeInt<N>> for SafeInt {
1335 #[inline(always)]
1336 fn from(value: &ConstSafeInt<N>) -> SafeInt {
1337 let pos = value.0.first().cloned().unwrap_or(0) == 0;
1338 let magnitude = BigUint::from_bytes_be(&value.0[1..]);
1339 let mut res = SafeInt(BigInt::from_biguint(Sign::Plus, magnitude));
1340 if !pos {
1341 res = -res;
1342 }
1343 res
1344 }
1345}
1346
1347#[test]
1348fn test_const_safe_int() {
1349 assert_eq!(
1350 SafeInt::from(ConstSafeInt::<4>::from_bytes([0, 0, 0, 1])),
1351 1
1352 );
1353 assert_eq!(SafeInt::from(ConstSafeInt::<2>::from_bytes([0, 1])), 1);
1354 assert_eq!(SafeInt::from(ConstSafeInt::<2>::from_bytes([1, 1])), -1);
1355 assert_eq!(SafeInt::from(ConstSafeInt::<2>::from_bytes([1, 0])), -0);
1356 assert_eq!(
1357 SafeInt::from(ConstSafeInt::<3>::from_bytes([1, 5, 254])),
1358 -1534
1359 );
1360 assert_eq!(
1361 SafeInt::from(ConstSafeInt::<17>::from_i128(-538525)),
1362 -538525
1363 );
1364 assert_eq!(
1365 SafeInt::from(ConstSafeInt::<17>::from_i128(123456789)),
1366 123456789
1367 );
1368 assert_eq!(
1369 SafeInt::from(ConstSafeInt::<17>::from_i128(i128::MIN)),
1370 i128::MIN
1371 );
1372 assert_eq!(
1373 SafeInt::from(ConstSafeInt::<17>::from_i128(i128::MAX)),
1374 i128::MAX
1375 );
1376 assert_eq!(
1377 SafeInt::from(ConstSafeInt::<17>::from_u128(u128::MAX)),
1378 u128::MAX
1379 );
1380 assert_eq!(
1381 SafeInt::from(ConstSafeInt::<17>::from_u128(39874398749837343434343434344)),
1382 39874398749837343434343434344u128
1383 );
1384 assert_eq!(SafeInt::from(ConstSafeInt::<17>::from_u128(0)), 0);
1385}
1386
1387#[test]
1388fn general() {
1389 let a = SafeInt::from(10);
1390 let b = SafeInt::from(20);
1391 let c = &a + &b;
1392 let d = a.clone() + c.clone();
1393 let e = a.clone() + &b;
1394 let f = &a + b.clone();
1395 assert_eq!(c, 30);
1396 assert!(d > a);
1397 assert!(a < d);
1398 assert!(a < b);
1399 assert_eq!(e, f);
1400 assert_eq!(f, a + b);
1401 assert_eq!((SafeInt::from(10) / SafeInt::from(3)).unwrap(), 3);
1402 assert_eq!(SafeInt::from(10) / SafeInt::from(0), None);
1403 assert_ne!(SafeInt::from(10), SafeInt::from(20));
1404 assert!(SafeInt::from(37984739847983497938479797988798789783u128).is_odd());
1405 assert!(
1406 SafeInt::from_str("3798473984798349793847979798879878978334738744739847983749837").unwrap()
1407 > 10
1408 );
1409 assert_eq!(
1410 SafeInt::from(33) / SafeInt::from(3),
1411 Some(SafeInt::from(11))
1412 );
1413 assert_eq!(33 / SafeInt::from(3), Some(SafeInt::from(11)));
1414 assert_eq!(SafeInt::from(33) / 3, Some(SafeInt::from(11)));
1415 assert_eq!(SafeInt::from(10) % SafeInt::from(3), Some(SafeInt::from(1)));
1416 assert_eq!(SafeInt::from(10) % SafeInt::from(0), None);
1417 assert_eq!(10 % SafeInt::from(3), Some(SafeInt::from(1)));
1418 assert_eq!(10 % SafeInt::from(0), None);
1419 assert_eq!(SafeInt::from(10) % 3, Some(SafeInt::from(1)));
1420 assert_eq!(SafeInt::from(10) % 0, None);
1421 assert_eq!(
1422 SafeInt::from(10).div_rem(SafeInt::from(3)),
1423 Some((SafeInt::from(3), SafeInt::from(1)))
1424 );
1425 assert_eq!(SafeInt::from(10).div_rem(SafeInt::from(0)), None);
1426 assert_eq!(33 + SafeInt::from(2), 35);
1427 assert_eq!(SafeInt::from(33) + 2, 35);
1428 assert_eq!(SafeInt::from(5) / SafeInt::from(0), None);
1429 assert_eq!(5 / SafeInt::from(0), None);
1430 assert_eq!(SafeInt::from(5) / 0, None);
1431 assert_eq!(&SafeInt::from(789) / 893797983, Some(SafeInt::from(0)));
1432 assert_eq!(&SafeInt::from(28249) / SafeInt::zero(), None);
1433}
1434
1435#[test]
1436fn test_perquintill_power() {
1437 const PRECISION: u32 = 256;
1438 const PERQUINTILL: u128 = 1_000_000_000_000_000_000;
1439
1440 let x = SafeInt::from(21_000_000_000_000_000u64);
1441 let delta = SafeInt::from(7_000_000_000_000_000u64);
1442 let w1 = SafeInt::from(600_000_000_000_000_000u128);
1443 let w2 = SafeInt::from(400_000_000_000_000_000u128);
1444 let denominator = &x + δ
1445 assert_eq!(w1.clone() + w2.clone(), SafeInt::from(PERQUINTILL));
1446
1447 let perquintill_result = SafeInt::pow_ratio_scaled(
1448 &x,
1449 &denominator,
1450 &w1,
1451 &w2,
1452 PRECISION,
1453 &SafeInt::from(PERQUINTILL),
1454 )
1455 .expect("perquintill integer result");
1456
1457 assert_eq!(
1458 perquintill_result,
1459 SafeInt::from(649_519_052_838_328_985u128)
1460 );
1461 let readable = crate::SafeDec::<18>::from_raw(perquintill_result);
1462 assert_eq!(format!("{}", readable), "0.649519052838328985");
1463}
1464
1465#[test]
1466fn pow_ratio_scaled_handles_large_weight_denominators() {
1467 let x = SafeInt::from(21_000_000_000_000_000i128);
1468 let denominator = SafeInt::from(21_000_000_000_000_100i128);
1469 let perquintill = SafeInt::from(1_000_000_000_000_000_000i128);
1470
1471 let cases = [
1472 (
1473 SafeInt::from(500_000_000_000_000_000i128),
1474 SafeInt::from(500_000_000_000_000_000i128),
1475 ),
1476 (
1477 SafeInt::from(499_999_999_999_500_000i128),
1478 SafeInt::from(500_000_000_000_500_000i128),
1479 ),
1480 (
1481 SafeInt::from(500_000_000_000_250_000i128),
1482 SafeInt::from(499_999_999_999_750_000i128),
1483 ),
1484 ];
1485
1486 for (w1, w2) in cases {
1487 let result =
1488 SafeInt::pow_ratio_scaled(&x, &denominator, &w1, &w2, 256, &perquintill).unwrap();
1489 assert_eq!(result, SafeInt::from(999_999_999_999_995_238i128));
1490 }
1491}
1492
1493#[test]
1494fn pow_ratio_scaled_converges_on_boundary_weights() {
1495 let x = SafeInt::from(21_000_000_000_000_000i128);
1496 let denominator = SafeInt::from(21_000_000_000_000_001i128);
1497 let w1 = SafeInt::from(499_999_999_500_000_000i128);
1498 let w2 = SafeInt::from(500_000_000_500_000_000i128);
1499 let scale = SafeInt::from(1_000_000_000_000_000_000i128);
1500 let precision = 256u32;
1501
1502 let start = std::time::Instant::now();
1503 let result = SafeInt::pow_ratio_scaled(&x, &denominator, &w1, &w2, precision, &scale).unwrap();
1504 let elapsed = start.elapsed();
1505
1506 assert_eq!(result, SafeInt::from(999_999_999_999_999_952i128));
1507 assert!(
1508 elapsed < core::time::Duration::from_secs(1),
1509 "pow_ratio_scaled took {:?}",
1510 elapsed
1511 );
1512}
1513
1514#[test]
1515fn pow_ratio_scaled_exact_path_handles_high_exponent() {
1516 let base_num = SafeInt::from(999_999_999i128);
1517 let base_den = SafeInt::from(1_000_000_001i128);
1518 let exp_num = SafeInt::from(MAX_EXACT_EXPONENT as i128 - 1);
1519 let exp_den = SafeInt::one();
1520 let scale = SafeInt::from(1_000_000i128);
1521 let precision = 64u32;
1522
1523 let start = std::time::Instant::now();
1524 let result =
1525 SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, precision, &scale)
1526 .expect("exact path should return");
1527 let elapsed = start.elapsed();
1528
1529 assert!(result > SafeInt::zero());
1530 assert!(
1531 elapsed < core::time::Duration::from_secs(1),
1532 "exact path took {:?}",
1533 elapsed
1534 );
1535}
1536
1537#[test]
1538fn pow_ratio_scaled_default_max_iters_completes_quickly() {
1539 let base_num = SafeInt::from(1i128);
1540 let base_den = SafeInt::from(1_000_000_000_000i128);
1541 let exp_num = SafeInt::one();
1542 let exp_den = SafeInt::from(1u128 << 40);
1543 let scale = SafeInt::one();
1544 let precision = 32u32;
1545
1546 let start = std::time::Instant::now();
1547 let default_iter =
1548 SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, precision, &scale)
1549 .unwrap();
1550 let elapsed = start.elapsed();
1551
1552 let explicit_default = SafeInt::pow_ratio_scaled_with_max_iters(
1553 &base_num,
1554 &base_den,
1555 &exp_num,
1556 &exp_den,
1557 precision,
1558 &scale,
1559 Some(DEFAULT_MAX_ITERS),
1560 )
1561 .unwrap();
1562
1563 assert_eq!(default_iter, explicit_default);
1564 assert!(
1565 elapsed < core::time::Duration::from_secs(2),
1566 "default iterations took {:?}",
1567 elapsed
1568 );
1569}
1570
1571#[test]
1572fn pow_ratio_scaled_uses_scale_to_pick_precision() {
1573 let base_num = SafeInt::from(123_456_789u64);
1576 let base_den = SafeInt::from(987_654_321u64);
1577 let exp_num = SafeInt::from(987_654_321_123_456_789u128);
1578 let exp_den = SafeInt::from(123_456_789_987_654_321u128);
1579 let scale = SafeInt::from(1_000_000_000_000_000_000i128);
1580
1581 let coarse = SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, 0, &scale)
1582 .expect("coarse precision result");
1583 let precise = SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, 256, &scale)
1584 .expect("high precision result");
1585 let delta = (precise.clone() - coarse.clone()).abs();
1586
1587 assert!(
1588 delta <= SafeInt::from(1u32),
1589 "coarse {coarse} vs precise {precise} differed by {delta}"
1590 );
1591}
1592
1593#[test]
1594fn pow_ratio_scaled_handles_small_base_fractional_exponent() {
1595 let base_num = SafeInt::from(1u8);
1597 let base_den = SafeInt::from(10u8);
1598 let exp_num = SafeInt::from(500_000_000_001u64);
1599 let exp_den = SafeInt::from(1_000_000_000_000u64);
1600 let scale = SafeInt::from(1_000_000_000_000_000_000u128);
1601 let precision = 128u32;
1602
1603 let result =
1604 SafeInt::pow_ratio_scaled(&base_num, &base_den, &exp_num, &exp_den, precision, &scale)
1605 .expect("small base fractional exponent");
1606 let expected =
1607 ((0.1f64).powf(0.500000000001f64) * 1_000_000_000_000_000_000f64).floor() as u128;
1608 let delta = (result.clone() - SafeInt::from(expected)).abs();
1609
1610 assert!(
1611 delta <= SafeInt::from(128u32),
1612 "result {result} vs expected {expected} (delta {delta})"
1613 );
1614}
1615
1616#[test]
1617fn pow_ratio_scaled_handles_extreme_delta_x() {
1618 let x = SafeInt::from(400_775_553u64);
1619 let dx = SafeInt::from(14_446_633_907_665_582u64);
1620 let base_den = &x + &dx;
1621 let w1 = SafeInt::from(102_337_248_363_782_924u128);
1622 let w2 = SafeInt::from(1_000_000_000_000_000_000u128) - &w1;
1623 let scale = SafeInt::from(1_000_000_000_000_000_000u128);
1624 let precision = 256u32;
1625
1626 let result = SafeInt::pow_ratio_scaled(&x, &base_den, &w1, &w2, precision, &scale)
1627 .expect("extreme delta x");
1628
1629 let expected = ((x.0.to_f64().unwrap() / base_den.0.to_f64().unwrap())
1630 .powf(w1.0.to_f64().unwrap() / w2.0.to_f64().unwrap())
1631 * 1_000_000_000_000_000_000f64)
1632 .floor() as u128;
1633 let delta = (result.clone() - SafeInt::from(expected)).abs();
1634
1635 assert!(
1636 delta <= SafeInt::from(1_000_000u128),
1637 "result {result} vs expected {expected} (delta {delta})"
1638 );
1639}
1640
1641#[test]
1642fn test_zero() {
1643 assert_eq!(SafeInt::zero(), 0);
1644 assert!(SafeInt::zero().is_zero());
1645}
1646
1647#[test]
1648fn test_one() {
1649 let one = SafeInt::one();
1650 assert_eq!(one, 1);
1651}