@@ -512,8 +512,8 @@ impl DenominatedAmount {
512
512
}
513
513
}
514
514
515
- /// Attempt to increase the precision of an amount . Can fail
516
- /// if the resulting amount does not fit into 256 bits.
515
+ /// Return an equivalent denominated amount with the given denomination . Can
516
+ /// fail if the resulting amount does not fit into 256 bits.
517
517
pub fn increase_precision (
518
518
self ,
519
519
denom : Denomination ,
@@ -534,8 +534,43 @@ impl DenominatedAmount {
534
534
. ok_or ( AmountParseError :: PrecisionOverflow )
535
535
}
536
536
537
+ /// Return the closest denominated amount with the given denomination and
538
+ /// the error.
539
+ pub fn approximate (
540
+ self ,
541
+ denom : Denomination ,
542
+ ) -> Result < ( Self , Self ) , AmountParseError > {
543
+ if denom. 0 < self . denom . 0 {
544
+ // Divide numerator and denominator by a power of 10
545
+ let amount = self . amount . raw_amount ( ) ;
546
+ #[ allow( clippy:: arithmetic_side_effects) ]
547
+ let ( quot, rem) = Uint :: from ( 10 )
548
+ . checked_pow ( Uint :: from ( self . denom . 0 - denom. 0 ) )
549
+ . and_then ( |scaling| {
550
+ amount. checked_div ( scaling) . zip ( amount. checked_rem ( scaling) )
551
+ } )
552
+ . ok_or ( AmountParseError :: PrecisionOverflow ) ?;
553
+ let approx = Self {
554
+ amount : quot. into ( ) ,
555
+ denom,
556
+ } ;
557
+ let error = Self {
558
+ amount : rem. into ( ) ,
559
+ denom : self . denom ,
560
+ } ;
561
+ Ok ( ( approx, error) )
562
+ } else {
563
+ // Multiply numerator and denominator by a power of 10
564
+ let error = Self {
565
+ amount : 0 . into ( ) ,
566
+ denom : self . denom ,
567
+ } ;
568
+ self . increase_precision ( denom) . map ( |x| ( x, error) )
569
+ }
570
+ }
571
+
537
572
/// Create a new [`DenominatedAmount`] with the same underlying
538
- /// amout but a new denomination.
573
+ /// amount but a new denomination.
539
574
pub fn redenominate ( self , new_denom : u8 ) -> Self {
540
575
Self {
541
576
amount : self . amount ,
@@ -590,6 +625,38 @@ impl DenominatedAmount {
590
625
} )
591
626
}
592
627
628
+ /// Checked division computed to the given precision. Returns `None` on
629
+ /// overflow.
630
+ pub fn checked_div_precision (
631
+ & self ,
632
+ rhs : DenominatedAmount ,
633
+ denom : Denomination ,
634
+ ) -> Option < Self > {
635
+ #[ allow( clippy:: arithmetic_side_effects) ]
636
+ let pow = i16:: from ( rhs. denom . 0 ) + i16:: from ( denom. 0 )
637
+ - i16:: from ( self . denom . 0 ) ;
638
+ if pow < 0 {
639
+ return None ;
640
+ }
641
+ let amount = Uint :: from ( 10 ) . checked_pow ( Uint :: from ( pow) ) . and_then (
642
+ |scaling| {
643
+ scaling. checked_mul_div (
644
+ self . amount . raw_amount ( ) ,
645
+ rhs. amount . raw_amount ( ) ,
646
+ )
647
+ } ,
648
+ ) ?;
649
+ Some ( Self {
650
+ amount : amount. 0 . into ( ) ,
651
+ denom,
652
+ } )
653
+ }
654
+
655
+ /// Checked division. Returns `None` on overflow.
656
+ pub fn checked_div ( & self , rhs : DenominatedAmount ) -> Option < Self > {
657
+ self . checked_div_precision ( rhs, self . denom )
658
+ }
659
+
593
660
/// Returns the significand of this number
594
661
pub const fn amount ( & self ) -> Amount {
595
662
self . amount
0 commit comments