@@ -12,3 +12,175 @@ pub trait Fraction<T>: Sized {
12
12
/// If `p` is zero, None is returned.
13
13
fn inv ( & self ) -> Option < Self > ;
14
14
}
15
+
16
+ impl < T : Copy + From < u8 > + PartialEq > Fraction < T > for ( T , T ) {
17
+ fn numerator ( & self ) -> T {
18
+ self . 0
19
+ }
20
+
21
+ fn denominator ( & self ) -> T {
22
+ self . 1
23
+ }
24
+
25
+ fn inv ( & self ) -> Option < Self > {
26
+ if self . numerator ( ) == 0u8 . into ( ) {
27
+ None
28
+ } else {
29
+ Some ( ( self . 1 , self . 0 ) )
30
+ }
31
+ }
32
+ }
33
+
34
+ #[ macro_export]
35
+ macro_rules! impl_mul_fraction {
36
+ ( $Uint: ident) => {
37
+ impl $Uint {
38
+ /// Multiply `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]).
39
+ /// Result is rounded down.
40
+ ///
41
+ /// ## Examples
42
+ ///
43
+ /// ```
44
+ /// use cosmwasm_std::Uint128;
45
+ /// let fraction = (8u128, 21u128);
46
+ /// let res = Uint128::new(123456).checked_mul_floor(fraction).unwrap();
47
+ /// assert_eq!(Uint128::new(47030), res); // 47030.8571 rounds down
48
+ /// ```
49
+ pub fn checked_mul_floor<F : Fraction <T >, T : Into <$Uint>>(
50
+ self ,
51
+ rhs: F ,
52
+ ) -> Result <Self , CheckedMultiplyFractionError > {
53
+ let divisor = rhs. denominator( ) . into( ) ;
54
+ let res = self
55
+ . full_mul( rhs. numerator( ) . into( ) )
56
+ . checked_div( divisor. into( ) ) ?;
57
+ Ok ( res. try_into( ) ?)
58
+ }
59
+
60
+ /// Same operation as `checked_mul_floor` except unwrapped
61
+ pub fn mul_floor<F : Fraction <T >, T : Into <$Uint>>( self , rhs: F ) -> Self {
62
+ self . checked_mul_floor( rhs) . unwrap( )
63
+ }
64
+
65
+ /// Multiply `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]).
66
+ /// Result is rounded up.
67
+ ///
68
+ /// ## Examples
69
+ ///
70
+ /// ```
71
+ /// use cosmwasm_std::Uint128;
72
+ /// let fraction = (8u128, 21u128);
73
+ /// let res = Uint128::new(123456).checked_mul_ceil(fraction).unwrap();
74
+ /// assert_eq!(Uint128::new(47031), res); // 47030.8571 rounds up
75
+ /// ```
76
+ pub fn checked_mul_ceil<F : Fraction <T >, T : Into <$Uint>>(
77
+ self ,
78
+ rhs: F ,
79
+ ) -> Result <Self , CheckedMultiplyFractionError > {
80
+ let dividend = self . full_mul( rhs. numerator( ) . into( ) ) ;
81
+ let divisor = rhs. denominator( ) . into( ) . into( ) ;
82
+ let floor_result = dividend. checked_div( divisor) ?. try_into( ) ?;
83
+ let remainder = dividend. checked_rem( divisor) ?;
84
+ if !remainder. is_zero( ) {
85
+ Ok ( $Uint:: one( ) . checked_add( floor_result) ?)
86
+ } else {
87
+ Ok ( floor_result)
88
+ }
89
+ }
90
+
91
+ /// Same operation as `checked_mul_ceil` except unwrapped
92
+ pub fn mul_ceil<F : Fraction <T >, T : Into <$Uint>>( self , rhs: F ) -> Self {
93
+ self . checked_mul_ceil( rhs) . unwrap( )
94
+ }
95
+
96
+ /// Divide `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]).
97
+ /// Result is rounded down.
98
+ ///
99
+ /// ## Examples
100
+ ///
101
+ /// ```
102
+ /// use cosmwasm_std::Uint128;
103
+ /// let fraction = (4u128, 5u128);
104
+ /// let res = Uint128::new(789).checked_div_floor(fraction).unwrap();
105
+ /// assert_eq!(Uint128::new(986), res); // 986.25 rounds down
106
+ /// ```
107
+ pub fn checked_div_floor<F : Fraction <T >, T : Into <$Uint>>(
108
+ self ,
109
+ rhs: F ,
110
+ ) -> Result <Self , CheckedMultiplyFractionError >
111
+ where
112
+ Self : Sized ,
113
+ {
114
+ let divisor = rhs. numerator( ) . into( ) ;
115
+ let res = self
116
+ . full_mul( rhs. denominator( ) . into( ) )
117
+ . checked_div( divisor. into( ) ) ?;
118
+ Ok ( res. try_into( ) ?)
119
+ }
120
+
121
+ /// Same operation as `checked_div_floor` except unwrapped
122
+ pub fn div_floor<F : Fraction <T >, T : Into <$Uint>>( self , rhs: F ) -> Self
123
+ where
124
+ Self : Sized ,
125
+ {
126
+ self . checked_div_floor( rhs) . unwrap( )
127
+ }
128
+
129
+ /// Divide `self` with a struct implementing [`Fraction`] (e.g. [`crate::Decimal`]).
130
+ /// Result is rounded up.
131
+ ///
132
+ /// ## Examples
133
+ ///
134
+ /// ```
135
+ /// use cosmwasm_std::Uint128;
136
+ /// let fraction = (4u128, 5u128);
137
+ /// let res = Uint128::new(789).checked_div_ceil(fraction).unwrap();
138
+ /// assert_eq!(Uint128::new(987), res); // 986.25 rounds up
139
+ /// ```
140
+ pub fn checked_div_ceil<F : Fraction <T >, T : Into <$Uint>>(
141
+ self ,
142
+ rhs: F ,
143
+ ) -> Result <Self , CheckedMultiplyFractionError >
144
+ where
145
+ Self : Sized ,
146
+ {
147
+ let dividend = self . full_mul( rhs. denominator( ) . into( ) ) ;
148
+ let divisor = rhs. numerator( ) . into( ) . into( ) ;
149
+ let floor_result = dividend. checked_div( divisor) ?. try_into( ) ?;
150
+ let remainder = dividend. checked_rem( divisor) ?;
151
+ if !remainder. is_zero( ) {
152
+ Ok ( $Uint:: one( ) . checked_add( floor_result) ?)
153
+ } else {
154
+ Ok ( floor_result)
155
+ }
156
+ }
157
+
158
+ /// Same operation as `checked_div_ceil` except unwrapped
159
+ pub fn div_ceil<F : Fraction <T >, T : Into <$Uint>>( self , rhs: F ) -> Self
160
+ where
161
+ Self : Sized ,
162
+ {
163
+ self . checked_div_ceil( rhs) . unwrap( )
164
+ }
165
+ }
166
+ } ;
167
+ }
168
+
169
+ #[ cfg( test) ]
170
+ mod tests {
171
+ use crate :: { Fraction , Uint128 , Uint64 } ;
172
+
173
+ #[ test]
174
+ fn fraction_tuple_methods ( ) {
175
+ let fraction = ( Uint64 :: one ( ) , Uint64 :: new ( 2 ) ) ;
176
+ assert_eq ! ( Uint64 :: one( ) , fraction. numerator( ) ) ;
177
+ assert_eq ! ( Uint64 :: new( 2 ) , fraction. denominator( ) ) ;
178
+ assert_eq ! ( Some ( ( Uint64 :: new( 2 ) , Uint64 :: one( ) ) ) , fraction. inv( ) ) ;
179
+ }
180
+
181
+ #[ test]
182
+ fn inverse_with_zero_denominator ( ) {
183
+ let fraction = ( Uint128 :: zero ( ) , Uint128 :: one ( ) ) ;
184
+ assert_eq ! ( None , fraction. inv( ) ) ;
185
+ }
186
+ }
0 commit comments