@@ -374,6 +374,58 @@ impl Decimal256 {
374
374
Err ( _) => Self :: MAX ,
375
375
}
376
376
}
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
+ }
377
429
}
378
430
379
431
impl Fraction < Uint256 > for Decimal256 {
@@ -2149,6 +2201,65 @@ mod tests {
2149
2201
assert_eq ! ( Decimal256 :: MAX . checked_ceil( ) , Err ( RoundUpOverflowError ) ) ;
2150
2202
}
2151
2203
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
+
2152
2263
#[ test]
2153
2264
fn decimal256_partial_eq ( ) {
2154
2265
let test_cases = [
0 commit comments