@@ -374,6 +374,58 @@ impl Decimal256 {
374374 Err ( _) => Self :: MAX ,
375375 }
376376 }
377+
378+ /// Converts this decimal to an unsigned integer by truncating
379+ /// the fractional part, e.g. 22.5 becomes 22.
380+ ///
381+ /// ## Examples
382+ ///
383+ /// ```
384+ /// use std::str::FromStr;
385+ /// use cosmwasm_std::{Decimal256, Uint256};
386+ ///
387+ /// let d = Decimal256::from_str("12.345").unwrap();
388+ /// assert_eq!(d.to_uint_floor(), Uint256::from(12u64));
389+ ///
390+ /// let d = Decimal256::from_str("12.999").unwrap();
391+ /// assert_eq!(d.to_uint_floor(), Uint256::from(12u64));
392+ ///
393+ /// let d = Decimal256::from_str("75.0").unwrap();
394+ /// assert_eq!(d.to_uint_floor(), Uint256::from(75u64));
395+ /// ```
396+ pub fn to_uint_floor ( self ) -> Uint256 {
397+ self . 0 / Self :: DECIMAL_FRACTIONAL
398+ }
399+
400+ /// Converts this decimal to an unsigned integer by rounting up
401+ /// to the next integer, e.g. 22.3 becomes 23.
402+ ///
403+ /// ## Examples
404+ ///
405+ /// ```
406+ /// use std::str::FromStr;
407+ /// use cosmwasm_std::{Decimal256, Uint256};
408+ ///
409+ /// let d = Decimal256::from_str("12.345").unwrap();
410+ /// assert_eq!(d.to_uint_ceil(), Uint256::from(13u64));
411+ ///
412+ /// let d = Decimal256::from_str("12.999").unwrap();
413+ /// assert_eq!(d.to_uint_ceil(), Uint256::from(13u64));
414+ ///
415+ /// let d = Decimal256::from_str("75.0").unwrap();
416+ /// assert_eq!(d.to_uint_ceil(), Uint256::from(75u64));
417+ /// ```
418+ pub fn to_uint_ceil ( self ) -> Uint256 {
419+ // Using `q = 1 + ((x - 1) / y); // if x != 0` with unsigned integers x, y, q
420+ // from https://stackoverflow.com/a/2745086/2013738. We know `x + y` CAN overflow.
421+ let x = self . 0 ;
422+ let y = Self :: DECIMAL_FRACTIONAL ;
423+ if x. is_zero ( ) {
424+ Uint256 :: zero ( )
425+ } else {
426+ Uint256 :: one ( ) + ( ( x - Uint256 :: one ( ) ) / y)
427+ }
428+ }
377429}
378430
379431impl Fraction < Uint256 > for Decimal256 {
@@ -2149,6 +2201,65 @@ mod tests {
21492201 assert_eq ! ( Decimal256 :: MAX . checked_ceil( ) , Err ( RoundUpOverflowError ) ) ;
21502202 }
21512203
2204+ #[ test]
2205+ fn decimal256_to_uint_floor_works ( ) {
2206+ let d = Decimal256 :: from_str ( "12.000000000000000001" ) . unwrap ( ) ;
2207+ assert_eq ! ( d. to_uint_floor( ) , Uint256 :: from_u128( 12 ) ) ;
2208+ let d = Decimal256 :: from_str ( "12.345" ) . unwrap ( ) ;
2209+ assert_eq ! ( d. to_uint_floor( ) , Uint256 :: from_u128( 12 ) ) ;
2210+ let d = Decimal256 :: from_str ( "12.999" ) . unwrap ( ) ;
2211+ assert_eq ! ( d. to_uint_floor( ) , Uint256 :: from_u128( 12 ) ) ;
2212+ let d = Decimal256 :: from_str ( "0.98451384" ) . unwrap ( ) ;
2213+ assert_eq ! ( d. to_uint_floor( ) , Uint256 :: from_u128( 0 ) ) ;
2214+
2215+ let d = Decimal256 :: from_str ( "75.0" ) . unwrap ( ) ;
2216+ assert_eq ! ( d. to_uint_floor( ) , Uint256 :: from_u128( 75 ) ) ;
2217+ let d = Decimal256 :: from_str ( "0.0" ) . unwrap ( ) ;
2218+ assert_eq ! ( d. to_uint_floor( ) , Uint256 :: from_u128( 0 ) ) ;
2219+
2220+ let d = Decimal256 :: MAX ;
2221+ assert_eq ! (
2222+ d. to_uint_floor( ) ,
2223+ Uint256 :: from_str( "115792089237316195423570985008687907853269984665640564039457" )
2224+ . unwrap( )
2225+ ) ;
2226+
2227+ // Does the same as the old workaround `Uint256::one() * my_decimal`.
2228+ // This block can be deleted as part of https://github.com/CosmWasm/cosmwasm/issues/1485.
2229+ let tests = vec ! [
2230+ Decimal256 :: from_str( "12.345" ) . unwrap( ) ,
2231+ Decimal256 :: from_str( "0.98451384" ) . unwrap( ) ,
2232+ Decimal256 :: from_str( "178.0" ) . unwrap( ) ,
2233+ Decimal256 :: MIN ,
2234+ Decimal256 :: MAX ,
2235+ ] ;
2236+ for my_decimal in tests. into_iter ( ) {
2237+ assert_eq ! ( my_decimal. to_uint_floor( ) , Uint256 :: one( ) * my_decimal) ;
2238+ }
2239+ }
2240+
2241+ #[ test]
2242+ fn decimal256_to_uint_ceil_works ( ) {
2243+ let d = Decimal256 :: from_str ( "12.000000000000000001" ) . unwrap ( ) ;
2244+ assert_eq ! ( d. to_uint_ceil( ) , Uint256 :: from_u128( 13 ) ) ;
2245+ let d = Decimal256 :: from_str ( "12.345" ) . unwrap ( ) ;
2246+ assert_eq ! ( d. to_uint_ceil( ) , Uint256 :: from_u128( 13 ) ) ;
2247+ let d = Decimal256 :: from_str ( "12.999" ) . unwrap ( ) ;
2248+ assert_eq ! ( d. to_uint_ceil( ) , Uint256 :: from_u128( 13 ) ) ;
2249+
2250+ let d = Decimal256 :: from_str ( "75.0" ) . unwrap ( ) ;
2251+ assert_eq ! ( d. to_uint_ceil( ) , Uint256 :: from_u128( 75 ) ) ;
2252+ let d = Decimal256 :: from_str ( "0.0" ) . unwrap ( ) ;
2253+ assert_eq ! ( d. to_uint_ceil( ) , Uint256 :: from_u128( 0 ) ) ;
2254+
2255+ let d = Decimal256 :: MAX ;
2256+ assert_eq ! (
2257+ d. to_uint_ceil( ) ,
2258+ Uint256 :: from_str( "115792089237316195423570985008687907853269984665640564039458" )
2259+ . unwrap( )
2260+ ) ;
2261+ }
2262+
21522263 #[ test]
21532264 fn decimal256_partial_eq ( ) {
21542265 let test_cases = [
0 commit comments