#[allow(non_snake_case)] mod test_round_pair { use paste::paste; use super::*; macro_rules! impl_test { ( $($mode:ident),+ => $expected:literal) => { $( paste! { #[test] fn [< mode_ $mode >]() { let (pair, sign, trailing_zeros) = test_input(); let mode = self::RoundingMode::$mode; let result = mode.round_pair(sign, pair, trailing_zeros); assert_eq!(result, $expected); } } )* } } macro_rules! define_test_input { ( - $lhs:literal . $rhs:literal $($t:tt)* ) => { define_test_input!(sign=Sign::Minus, pair=($lhs, $rhs), $($t)*); }; ( $lhs:literal . $rhs:literal $($t:tt)*) => { define_test_input!(sign=Sign::Plus, pair=($lhs, $rhs), $($t)*); }; ( sign=$sign:expr, pair=$pair:expr, ) => { define_test_input!(sign=$sign, pair=$pair, trailing_zeros=true); }; ( sign=$sign:expr, pair=$pair:expr, 000x ) => { define_test_input!(sign=$sign, pair=$pair, trailing_zeros=false); }; ( sign=$sign:expr, pair=$pair:expr, trailing_zeros=$trailing_zeros:literal ) => { fn test_input() -> ((u8, u8), Sign, bool) { ($pair, $sign, $trailing_zeros) } }; } mod case_0_1 { use super::*; define_test_input!(0 . 1); impl_test!(Up, Ceiling => 1); impl_test!(Down, Floor, HalfUp, HalfDown, HalfEven => 0); } mod case_neg_0_1 { use super::*; define_test_input!(-0 . 1); impl_test!(Up, Floor => 1); impl_test!(Down, Ceiling, HalfUp, HalfDown, HalfEven => 0); } mod case_0_5 { use super::*; define_test_input!( 0 . 5 ); impl_test!(Up, Ceiling, HalfUp => 1); impl_test!(Down, Floor, HalfDown, HalfEven => 0); } mod case_neg_0_5 { use super::*; define_test_input!(-0 . 5); impl_test!(Up, Floor, HalfUp => 1); impl_test!(Down, Ceiling, HalfDown, HalfEven => 0); } mod case_0_5_000x { use super::*; // ...000x indicates a non-zero trailing digit; affects behavior of rounding N.0 and N.5 define_test_input!(0 . 5 000x); impl_test!(Up, Ceiling, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Floor => 0); } mod case_neg_0_5_000x { use super::*; define_test_input!(-0 . 5 000x); impl_test!(Up, Floor, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Ceiling => 0); } mod case_0_7 { use super::*; define_test_input!(0 . 7); impl_test!(Up, Ceiling, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Floor => 0); } mod case_neg_0_7 { use super::*; define_test_input!(-0 . 7); impl_test!(Up, Floor, HalfUp, HalfDown, HalfEven => 1); impl_test!(Down, Ceiling => 0); } mod case_neg_4_3_000x { use super::*; define_test_input!(-4 . 3 000x); impl_test!(Up, Floor => 5); impl_test!(Down, Ceiling, HalfUp, HalfDown, HalfEven => 4); } mod case_9_5_000x { use super::*; define_test_input!(9 . 5 000x); impl_test!(Up, Ceiling, HalfDown, HalfUp, HalfEven => 10); impl_test!(Down, Floor => 9); } mod case_9_5 { use super::*; define_test_input!(9 . 5); impl_test!(Up, Ceiling, HalfUp, HalfEven => 10); impl_test!(Down, Floor, HalfDown => 9); } mod case_8_5 { use super::*; define_test_input!(8 . 5); impl_test!(Up, Ceiling, HalfUp => 9); impl_test!(Down, Floor, HalfDown, HalfEven => 8); } mod case_neg_6_5 { use super::*; define_test_input!(-6 . 5); impl_test!(Up, Floor, HalfUp => 7); impl_test!(Down, Ceiling, HalfDown, HalfEven => 6); } mod case_neg_6_5_000x { use super::*; define_test_input!(-6 . 5 000x); impl_test!(Up, Floor, HalfUp, HalfDown, HalfEven => 7); impl_test!(Down, Ceiling => 6); } mod case_3_0 { use super::*; define_test_input!(3 . 0); impl_test!(Up, Down, Ceiling, Floor, HalfUp, HalfDown, HalfEven => 3); } mod case_3_0_000x { use super::*; define_test_input!(3 . 0 000x); impl_test!(Up, Ceiling => 4); impl_test!(Down, Floor, HalfUp, HalfDown, HalfEven => 3); } mod case_neg_2_0 { use super::*; define_test_input!(-2 . 0); impl_test!(Up, Down, Ceiling, Floor, HalfUp, HalfDown, HalfEven => 2); } mod case_neg_2_0_000x { use super::*; define_test_input!(-2 . 0 000x); impl_test!(Up, Floor => 3); impl_test!(Down, Ceiling, HalfUp, HalfDown, HalfEven => 2); } } #[cfg(test)] #[allow(non_snake_case)] mod test_round_u32 { use paste::paste; use super::*; macro_rules! impl_test { ( $pos:literal :: $($mode:ident),+ => $expected:literal) => { $( paste! { #[test] fn [< digit_ $pos _mode_ $mode >]() { let (value, sign, trailing_zeros) = test_input(); let mode = self::RoundingMode::$mode; let pos = stdlib::num::NonZeroU8::new($pos as u8).unwrap(); let result = mode.round_u32(pos, sign, value, trailing_zeros); assert_eq!(result, $expected); } } )* } } macro_rules! define_test_input { ( - $value:literal $($t:tt)* ) => { define_test_input!(sign=Sign::Minus, value=$value $($t)*); }; ( $value:literal $($t:tt)* ) => { define_test_input!(sign=Sign::Plus, value=$value $($t)*); }; ( sign=$sign:expr, value=$value:literal ...000x ) => { define_test_input!(sign=$sign, value=$value, trailing_zeros=false); }; ( sign=$sign:expr, value=$value:literal ) => { define_test_input!(sign=$sign, value=$value, trailing_zeros=true); }; ( sign=$sign:expr, value=$value:expr, trailing_zeros=$trailing_zeros:literal ) => { fn test_input() -> (u32, Sign, bool) { ($value, $sign, $trailing_zeros) } }; } mod case_13950000 { use super::*; define_test_input!(13950000); impl_test!(3 :: Up => 13950000); impl_test!(5 :: Up, Ceiling, HalfUp, HalfEven => 14000000); impl_test!(5 :: Down, HalfDown => 13900000); } mod case_neg_35488622_000x { use super::*; // ...000x indicates non-zero trailing digit define_test_input!(-35488622 ...000x); impl_test!(1 :: Up => 35488630); impl_test!(1 :: Down => 35488620); impl_test!(2 :: Up => 35488700); impl_test!(2 :: Down => 35488600); impl_test!(7 :: Up, Floor => 40000000); impl_test!(7 :: Down, Ceiling => 30000000); impl_test!(8 :: Up => 100000000); impl_test!(8 :: Down => 0); } } #[allow(non_snake_case)] mod test_round_biguint_inplace { use super::*; use paste::paste; macro_rules! impl_test { (IMPL; $prec:literal, $mode:ident => $expected:literal, $exp:literal) => { paste! { #[test] fn [< prec $prec _mode_ $mode >]() { let mut n = test_input(); let rounder = NonDigitRoundingData { mode: self::RoundingMode::$mode, sign: Sign::Plus, }; let prec = NonZeroU64::new($prec).unwrap(); let result = round_biguint_inplace(&mut n, prec, rounder); let expected: BigUint = $expected.parse().unwrap(); assert_eq!(&expected, &n); assert_eq!($exp, result); } } }; ($prec:literal: $($mode:ident),+ => $expected:literal E $exp:literal) => { $( impl_test!(IMPL; $prec, $mode => $expected, $exp); )* }; ($prec:literal: $($($mode:ident),+ => $expected:literal E $exp:literal),+ ) => { $( impl_test!($prec: $($mode),* => $expected E $exp); )* }; } mod case_14414008876e200 { use super::*; fn test_input() -> BigUint { "1441400887642029388383856645559897315584165538408309505171135258930500598075662511441702498467332463786833300335785089981027498174604649257434184055851638492438374046355824930138046686225938550901559011829587689".parse().unwrap() } impl_test!(15: Up => "144140088764203" E 196, Down => "144140088764202" E 196); impl_test!(11: Down, HalfEven => "14414008876" E 200, Up => "14414008877" E 200); impl_test!(1: Down, HalfEven => "1" E 210, Up => "2" E 210); } mod case_99191529355902971933631238546419824884699 { use super::*; fn test_input() -> BigUint { "99191529355902971933631238546419824884699".parse().unwrap() } impl_test!(42: Down, Up => "99191529355902971933631238546419824884699" E 0); impl_test!(41: Down, Up, HalfEven => "99191529355902971933631238546419824884699" E 0); impl_test!(40: Up => "9919152935590297193363123854641982488470" E 1, Down => "9919152935590297193363123854641982488469" E 1); impl_test!(13: Up => "9919152935591" E 28, Down => "9919152935590" E 28); impl_test!(4: Up => "9920" E 37, Down => "9919" E 37); impl_test!(3: Up => "992" E 38, Down => "991" E 38); impl_test!(2: Up => "10" E 40, Down => "99" E 39); impl_test!(1: Up => "1" E 41, Down => "9" E 40); } mod case_99 { use super::*; fn test_input() -> BigUint { "99".parse().unwrap() } impl_test!(2: Up => "99" E 0, Down => "99" E 0); impl_test!(1: Up => "1" E 2, Down => "9" E 1); } }