#[test] fn it_parses_positive_int_string() { let a = Decimal::from_str("233").unwrap();
assert_eq!(a.is_sign_negative(), false);
assert_eq!(a.scale(), 0);
assert_eq!("233", a.to_string());
}
#[test] fn it_parses_negative_int_string() { let a = Decimal::from_str("-233").unwrap();
assert_eq!(a.is_sign_negative(), true);
assert_eq!(a.scale(), 0);
assert_eq!("-233", a.to_string());
}
#[test] fn it_parses_positive_float_string() { let a = Decimal::from_str("233.323223").unwrap();
assert_eq!(a.is_sign_negative(), false);
assert_eq!(a.scale(), 6);
assert_eq!("233.323223", a.to_string());
}
#[test] fn it_parses_negative_float_string() { let a = Decimal::from_str("-233.43343").unwrap();
assert_eq!(a.is_sign_negative(), true);
assert_eq!(a.scale(), 5);
assert_eq!("-233.43343", a.to_string());
}
#[test] fn it_parses_positive_tiny_float_string() { let a = Decimal::from_str(".000001").unwrap();
assert_eq!(a.is_sign_negative(), false);
assert_eq!(a.scale(), 6);
assert_eq!("0.000001", a.to_string());
}
#[test] fn it_parses_negative_tiny_float_string() { let a = Decimal::from_str("-0.000001").unwrap();
assert_eq!(a.is_sign_negative(), true);
assert_eq!(a.scale(), 6);
assert_eq!("-0.000001", a.to_string());
}
#[test] fn it_parses_big_integer_string() { let a = Decimal::from_str("79228162514264337593543950330").unwrap();
assert_eq!("79228162514264337593543950330", a.to_string());
}
#[test] fn it_parses_big_float_string() { let a = Decimal::from_str("79.228162514264337593543950330").unwrap();
assert_eq!("79.228162514264337593543950330", a.to_string());
}
#[test] fn it_can_serialize_deserialize() { let tests = [ "12.3456789", "5233.9008808150288439427720175", "-5233.9008808150288439427720175",
]; for test in &tests { let a = Decimal::from_str(test).unwrap(); let bytes = a.serialize(); let b = Decimal::deserialize(bytes);
assert_eq!(test.to_string(), b.to_string());
}
}
#[test] #[cfg(feature = "borsh")] fn it_can_serialize_deserialize_borsh() { let tests = [ "12.3456789", "5233.9008808150288439427720175", "-5233.9008808150288439427720175",
]; for test in &tests { let a = Decimal::from_str(test).unwrap(); letmut bytes: Vec<u8> = Vec::new();
borsh::BorshSerialize::serialize(&a, &mut bytes).unwrap(); let b: Decimal = borsh::BorshDeserialize::deserialize(&mut bytes.as_slice()).unwrap();
assert_eq!(test.to_string(), b.to_string()); let bytes = borsh::try_to_vec_with_schema(&a);
assert!(bytes.is_ok(), "try_to_vec_with_schema.is_ok()"); let bytes = bytes.unwrap(); let result = borsh::try_from_slice_with_schema(&bytes);
assert!(result.is_ok(), "try_from_slice_with_schema.is_ok()"); let b: Decimal = result.unwrap();
assert_eq!(test.to_string(), b.to_string());
}
}
#[test] #[cfg(feature = "rkyv")] fn it_can_serialize_deserialize_rkyv() { use rkyv::Deserialize; let tests = [ "12.3456789", "5233.9008808150288439427720175", "-5233.9008808150288439427720175",
]; for test in &tests { let a = Decimal::from_str(test).unwrap(); let bytes = rkyv::to_bytes::<_, 256>(&a).unwrap();
#[test] fn it_can_add_simple() { // This is the most basic test for addition, intended largely for micro-optimization. let two = Decimal::ONE + Decimal::ONE;
assert_eq!(two.to_u32(), Some(2));
}
#[test] fn it_adds_decimals() { fn add(a: &str, b: &str, c: &str) { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap(); let result = a + b;
assert_eq!(c, result.to_string(), "{} + {}", a.to_string(), b.to_string()); let result = b + a;
assert_eq!(c, result.to_string(), "{} + {}", b.to_string(), a.to_string());
}
let tests = &[
("0", "0", "0"),
("0", "-0", "0"),
("-0", "0", "0"),
("-0", "-0", "0"),
("2", "3", "5"),
("2454495034", "3451204593", "5905699627"),
("24544.95034", ".3451204593", "24545.2954604593"),
(".1", ".1", "0.2"),
(".10", ".1", "0.20"),
(".1", "-.1", "0.0"),
("0", "1.001", "1.001"),
("2", "-3", "-1"),
("-2", "3", "1"),
("-2", "-3", "-5"),
("3", "-2", "1"),
("-3", "2", "-1"),
("1.234", "2.4567", "3.6907"),
( "11.815126050420168067226890757", "0.6386554621848739495798319328", "12.453781512605042016806722690",
),
( "-11.815126050420168067226890757", "0.6386554621848739495798319328", "-11.176470588235294117647058824",
),
( "11.815126050420168067226890757", "-0.6386554621848739495798319328", "11.176470588235294117647058824",
),
( "-11.815126050420168067226890757", "-0.6386554621848739495798319328", "-12.453781512605042016806722690",
),
( "11815126050420168067226890757", "0.4386554621848739495798319328", "11815126050420168067226890757",
),
( "-11815126050420168067226890757", "0.4386554621848739495798319328", "-11815126050420168067226890757",
),
( "11815126050420168067226890757", "-0.4386554621848739495798319328", "11815126050420168067226890757",
),
( "-11815126050420168067226890757", "-0.4386554621848739495798319328", "-11815126050420168067226890757",
),
( "0.0872727272727272727272727272", "843.65000000", "843.7372727272727272727272727",
),
( "7314.6229858868828353570724702", "1000", // Overflow causes this to round "8314.622985886882835357072470",
),
( "108053.27500000000000000000000", "0.00000000000000000000000", "108053.27500000000000000000000",
),
( "108053.27500000000000000000000", // This zero value has too high precision and will be trimmed "0.000000000000000000000000", "108053.27500000000000000000000",
),
( "108053.27500000000000000000000", // This value has too high precision and will be rounded "0.000000000000000000000001", "108053.27500000000000000000000",
),
( "108053.27500000000000000000000", // This value has too high precision and will be rounded "0.000000000000000000000005",
either!("108053.27500000000000000000000", "108053.27500000000000000000001"),
),
( "8097370036018690744.2590371109596744091", "3807285637671831400.15346897797550749555", "11904655673690522144.412506089",
),
]; for &(a, b, c) in tests {
add(a, b, c);
}
}
#[test] fn it_can_addassign() { letmut a = Decimal::from_str("1.01").unwrap(); let b = Decimal::from_str("0.99").unwrap();
a += b;
assert_eq!("2.00", a.to_string());
a += &b;
assert_eq!("2.99", a.to_string());
letmut c = &mut a;
c += b;
assert_eq!("3.98", a.to_string());
letmut c = &mut a;
c += &b;
assert_eq!("4.97", a.to_string());
}
// Subtraction
#[test] fn it_subtracts_decimals() { fn sub(a: &str, b: &str, c: &str) { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap(); let result = a - b;
assert_eq!(c, result.to_string(), "{} - {}", a.to_string(), b.to_string());
}
#[test] fn it_can_subassign() { letmut a = Decimal::from_str("1.01").unwrap(); let b = Decimal::from_str("0.51").unwrap();
a -= b;
assert_eq!("0.50", a.to_string());
a -= &b;
assert_eq!("-0.01", a.to_string());
letmut c = &mut a;
c -= b;
assert_eq!("-0.52", a.to_string());
letmut c = &mut a;
c -= &b;
assert_eq!("-1.03", a.to_string());
}
// Multiplication
#[test] fn it_multiplies_decimals() { fn mul(a: &str, b: &str, c: &str) { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap(); let result = a * b;
assert_eq!(c, result.to_string(), "{} * {}", a.to_string(), b.to_string()); let result = b * a;
assert_eq!(c, result.to_string(), "{} * {}", b.to_string(), a.to_string());
}
#[test] #[should_panic(expected = "Multiplication overflowed")] fn it_panics_when_multiply_with_overflow() { let a = Decimal::from_str("2000000000000000000001").unwrap(); let b = Decimal::from_str("3000000000000000000001").unwrap(); let _ = a * b;
}
#[test] fn it_can_mulassign() { letmut a = Decimal::from_str("1.25").unwrap(); let b = Decimal::from_str("0.01").unwrap();
a *= b;
assert_eq!("0.0125", a.to_string());
a *= &b;
assert_eq!("0.000125", a.to_string());
letmut c = &mut a;
c *= b;
assert_eq!("0.00000125", a.to_string());
letmut c = &mut a;
c *= &b;
assert_eq!("0.0000000125", a.to_string());
}
// Division
#[test] fn it_divides_decimals() { fn div(a: &str, b: &str, c: &str) { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap(); let result = a / b;
assert_eq!(c, result.to_string(), "{} / {}", a.to_string(), b.to_string());
}
#[test] #[should_panic(expected = "Division by zero")] fn it_can_divide_by_zero() { let a = Decimal::from_str("2").unwrap(); let _ = a / Decimal::ZERO;
}
#[test] fn it_can_divassign() { letmut a = Decimal::from_str("1.25").unwrap(); let b = Decimal::from_str("0.01").unwrap();
a /= b;
assert_eq!("125", a.to_string());
a /= &b;
assert_eq!("12500", a.to_string());
letmut c = &mut a;
c /= b;
assert_eq!("1250000", a.to_string());
letmut c = &mut a;
c /= &b;
assert_eq!("125000000", a.to_string());
}
#[test] fn it_rems_decimals() { fn rem(a: &str, b: &str, c: &str) { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap(); // a = qb + r let result = a % b;
assert_eq!(c, result.to_string(), "{} % {}", a.to_string(), b.to_string());
}
#[test] fn it_floors_decimals() { let tests = &[
("1", "1"),
("1.00", "1"),
("1.2345", "1"),
("-1", "-1"),
("-1.00", "-1"),
("-1.2345", "-2"),
]; for &(a, expected) in tests { let a = Decimal::from_str(a).unwrap();
assert_eq!(expected, a.floor().to_string(), "Failed flooring {}", a);
}
}
#[test] fn it_ceils_decimals() { let tests = &[
("1", "1"),
("1.00", "1"),
("1.2345", "2"),
("-1", "-1"),
("-1.00", "-1"),
("-1.2345", "-1"),
]; for &(a, expected) in tests { let a = Decimal::from_str(a).unwrap();
assert_eq!(expected, a.ceil().to_string(), "Failed ceiling {}", a);
}
}
#[test] fn it_finds_max_of_two() { let tests = &[("1", "1", "1"), ("2", "1", "2"), ("1", "2", "2")]; for &(a, b, expected) in tests { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap();
assert_eq!(expected, a.max(b).to_string());
}
}
#[test] fn it_finds_min_of_two() { let tests = &[("1", "1", "1"), ("2", "1", "1"), ("1", "2", "1")]; for &(a, b, expected) in tests { let a = Decimal::from_str(a).unwrap(); let b = Decimal::from_str(b).unwrap();
assert_eq!(expected, a.min(b).to_string());
}
}
#[test] fn test_max_compares() { let x = "225.33543601344182".parse::<Decimal>().unwrap(); let y = Decimal::MAX;
assert!(x < y);
assert!(y > x);
assert_ne!(y, x);
}
#[test] fn test_min_compares() { let x = "225.33543601344182".parse::<Decimal>().unwrap(); let y = Decimal::MIN;
assert!(x > y);
assert!(y < x);
assert_ne!(y, x);
}
#[test] fn it_can_parse_from_i32() { use num_traits::FromPrimitive;
let tests = &[
(0i32, "0"),
(1i32, "1"),
(-1i32, "-1"),
(i32::MAX, "2147483647"),
(i32::MIN, "-2147483648"),
]; for &(input, expected) in tests { let parsed = Decimal::from_i32(input).unwrap();
assert_eq!(
expected,
parsed.to_string(), "expected {} does not match parsed {}",
expected,
parsed
);
assert_eq!(
input.to_string(),
parsed.to_string(), "i32 to_string {} does not match parsed {}",
input,
parsed
);
}
}
#[test] fn it_can_parse_from_i64() { use num_traits::FromPrimitive;
let tests = &[
(0i64, "0"),
(1i64, "1"),
(-1i64, "-1"),
(i64::MAX, "9223372036854775807"),
(i64::MIN, "-9223372036854775808"),
]; for &(input, expected) in tests { let parsed = Decimal::from_i64(input).unwrap();
assert_eq!(
expected,
parsed.to_string(), "expected {} does not match parsed {}",
expected,
parsed
);
assert_eq!(
input.to_string(),
parsed.to_string(), "i64 to_string {} does not match parsed {}",
input,
parsed
);
}
}
#[test] fn it_can_round_to_2dp() { let a = Decimal::from_str("6.12345").unwrap(); let b = (Decimal::from_str("100").unwrap() * a).round() / Decimal::from_str("100").unwrap();
assert_eq!("6.12", b.to_string());
}
for &(input, strategy, expected) in tests { let a = Decimal::from_str(input).unwrap(); let b = a.round_dp_with_strategy(0, strategy);
assert_eq!(expected, b.to_string(), "{} > {} for {:?}", input, expected, strategy);
}
}
// Recommended replacement let b = a.round_dp_with_strategy(dp, RoundingStrategy::MidpointNearestEven);
assert_eq!(expected, b.to_string(), "MidpointNearestEven");
}
}
#[test] fn it_can_round_complex_numbers_using_bankers_rounding() { // Issue #71 let rate = Decimal::new(19, 2); // 0.19 let one = Decimal::new(1, 0); // 1 let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
#[allow(deprecated)] let part = part.round_dp_with_strategy(2, RoundingStrategy::BankersRounding); // 0.16
assert_eq!("0.16", part.to_string(), "BankersRounding");
// Recommended replacement let part = part.round_dp_with_strategy(2, RoundingStrategy::MidpointNearestEven); // 0.16
assert_eq!("0.16", part.to_string(), "MidpointNearestEven");
}
#[test] fn it_can_round_using_round_half_up() { let tests = &[
("0", 0, "0"),
("1.234", 3, "1.234"),
("1.12", 5, "1.12"),
("6.34567", 2, "6.35"),
("6.5", 0, "7"),
("12.49", 0, "12"),
("0.6666666666666666666666666666", 2, "0.67"),
("1.40", 0, "1"),
("2.60", 0, "3"),
("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"),
]; for &(input, dp, expected) in tests { let a = Decimal::from_str(input).unwrap(); #[allow(deprecated)] let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundHalfUp);
assert_eq!(expected, b.to_string(), "RoundHalfUp");
// Recommended replacement let b = a.round_dp_with_strategy(dp, RoundingStrategy::MidpointAwayFromZero);
assert_eq!(expected, b.to_string(), "MidpointAwayFromZero");
}
}
#[test] fn it_can_round_complex_numbers_using_round_half_up() { // Issue #71 let rate = Decimal::new(19, 2); // 0.19 let one = Decimal::new(1, 0); // 1 let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 #[allow(deprecated)] let part = part.round_dp_with_strategy(2, RoundingStrategy::RoundHalfUp); // 0.16
assert_eq!("0.16", part.to_string(), "RoundHalfUp");
// Recommended replacement let part = part.round_dp_with_strategy(2, RoundingStrategy::MidpointAwayFromZero); // 0.16
assert_eq!("0.16", part.to_string(), "MidpointAwayFromZero");
}
#[test] fn it_can_round_using_round_half_down() { let tests = &[
("0", 0, "0"),
("1.234", 3, "1.234"),
("1.12", 5, "1.12"),
("6.34567", 2, "6.35"),
("6.51", 0, "7"),
("12.5", 0, "12"),
("0.6666666666666666666666666666", 2, "0.67"),
("1.40", 0, "1"),
("2.60", 0, "3"),
("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"),
]; for &(input, dp, expected) in tests { let a = Decimal::from_str(input).unwrap(); #[allow(deprecated)] let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundHalfDown);
assert_eq!(expected, b.to_string(), "RoundHalfDown");
// Recommended replacement let b = a.round_dp_with_strategy(dp, RoundingStrategy::MidpointTowardZero);
assert_eq!(expected, b.to_string(), "MidpointTowardZero");
}
}
#[test] fn it_can_round_complex_numbers_using_round_half_down() { // Issue #71 let rate = Decimal::new(19, 2); // 0.19 let one = Decimal::new(1, 0); // 1 let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832
#[allow(deprecated)] let part = part.round_dp_with_strategy(2, RoundingStrategy::RoundHalfDown); // 0.16
assert_eq!("0.16", part.to_string(), "RoundHalfDown");
// Recommended replacement let part = part.round_dp_with_strategy(2, RoundingStrategy::MidpointTowardZero); // 0.16
assert_eq!("0.16", part.to_string(), "RoundHalfDown");
}
#[test] fn it_can_round_to_2dp_using_explicit_function() { let a = Decimal::from_str("6.12345").unwrap(); let b = a.round_dp(2u32);
assert_eq!("6.12", b.to_string());
}
#[test] fn it_can_round_up_to_2dp_using_explicit_function() { let a = Decimal::from_str("6.126").unwrap(); let b = a.round_dp(2u32);
assert_eq!("6.13", b.to_string());
}
#[test] fn it_can_round_down_to_2dp_using_explicit_function() { let a = Decimal::from_str("-6.126").unwrap(); let b = a.round_dp(2u32);
assert_eq!("-6.13", b.to_string());
}
#[test] fn it_can_round_down_using_bankers_rounding() { let a = Decimal::from_str("6.5").unwrap(); let b = a.round_dp(0u32);
assert_eq!("6", b.to_string());
}
#[test] fn it_can_round_up_using_bankers_rounding() { let a = Decimal::from_str("7.5").unwrap(); let b = a.round_dp(0u32);
assert_eq!("8", b.to_string());
}
#[test] fn it_can_round_correctly_using_bankers_rounding_1() { let a = Decimal::from_str("1.2250").unwrap(); let b = a.round_dp(2u32);
assert_eq!("1.22", b.to_string());
}
#[test] fn it_can_round_correctly_using_bankers_rounding_2() { let a = Decimal::from_str("1.2251").unwrap(); let b = a.round_dp(2u32);
assert_eq!("1.23", b.to_string());
}
#[test] fn it_can_round_down_when_required() { let a = Decimal::from_str("1.2249").unwrap(); let b = a.round_dp(2u32);
assert_eq!("1.22", b.to_string());
}
#[test] fn it_can_round_to_2dp_using_explicit_function_without_changing_value() { let a = Decimal::from_str("6.1").unwrap(); let b = a.round_dp(2u32);
assert_eq!("6.1", b.to_string());
}
#[test] fn it_can_round_zero() { let a = Decimal::from_str("0.0000").unwrap(); let b = a.round_dp(2u32);
assert_eq!("0.00", b.to_string());
}
#[test] fn it_can_round_large_decimals() { let a = Decimal::from_str("0.6666666666666666666666666666").unwrap(); let b = a.round_dp(2u32);
assert_eq!("0.67", b.to_string());
}
#[test] fn it_can_round_simple_numbers_down() { let a = Decimal::from_str("1.40").unwrap(); let b = a.round_dp(0u32);
assert_eq!("1", b.to_string());
}
#[test] fn it_can_round_simple_numbers_up() { let a = Decimal::from_str("2.60").unwrap(); let b = a.round_dp(0u32);
assert_eq!("3", b.to_string());
}
#[test] fn it_can_round_simple_numbers_with_high_precision() { let a = Decimal::from_str("2.1234567890123456789012345678").unwrap(); let b = a.round_dp(27u32);
assert_eq!("2.123456789012345678901234568", b.to_string());
}
#[test] fn it_can_round_complex_numbers() { // Issue #71 let rate = Decimal::new(19, 2); // 0.19 let one = Decimal::new(1, 0); // 1 let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 let part = part.round_dp(2); // 0.16
assert_eq!("0.16", part.to_string());
}
#[test] fn it_can_round_down() { let tests = &[
("0.470", 1, "0.4"),
("-0.470", 1, "-0.4"), // Toward zero
("0.400", 1, "0.4"),
("-0.400", 1, "-0.4"),
]; for &(input, dp, expected) in tests { let a = Decimal::from_str(input).unwrap(); #[allow(deprecated)] let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundDown);
assert_eq!(expected, b.to_string(), "RoundDown");
// Recommended replacement let b = a.round_dp_with_strategy(dp, RoundingStrategy::ToZero);
assert_eq!(expected, b.to_string(), "ToZero");
}
}
for &(input, dp, expected) in tests { let a = Decimal::from_str(input).unwrap(); #[allow(deprecated)] let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundUp);
assert_eq!(expected, b.to_string(), "RoundUp");
// Recommended replacement let b = a.round_dp_with_strategy(dp, RoundingStrategy::AwayFromZero);
assert_eq!(expected, b.to_string(), "AwayFromZero");
}
}
#[test] fn it_can_round_significant_figures() { let tests = &[
("305.459", 0u32, Some("0")),
("305.459", 1, Some("300")),
("305.459", 2, Some("310")),
("305.459", 3, Some("305")),
("305.459", 4, Some("305.5")),
("305.459", 5, Some("305.46")),
("305.459", 6, Some("305.459")),
("305.459", 7, Some("305.4590")),
("305.459", 10, Some("305.4590000")),
("-305.459", 3, Some("-305")),
("-305.459", 2, Some("-310")), // We ignore the negative
("-305.459", 5, Some("-305.46")),
( "79228162514264337593543950335", 29,
Some("79228162514264337593543950335"),
),
("79228162514264337593543950335", 1, None),
( "79228162514264337593543950335", 2,
Some("79000000000000000000000000000"),
),
( "79228162514264337593543950335", 30,
Some("79228162514264337593543950335"),
),
( "79228162514264337593543950335",
u32::MAX,
Some("79228162514264337593543950335"),
),
]; for &(input, sf, expected) in tests { let input = Decimal::from_str(input).unwrap(); let result = input.round_sf(sf); iflet Some(expected) = expected {
assert!(result.is_some(), "Expected result for {}.round_sf({})", input, sf);
assert_eq!(expected, result.unwrap().to_string(), "{}.round_sf({})", input, sf);
} else {
assert!(result.is_none(), "Unexpected result for {}.round_sf({})", input, sf);
}
}
}
#[test] fn it_can_round_significant_figures_with_strategy() { let tests = &[
("12301", 3u32, RoundingStrategy::AwayFromZero, Some("12400")),
("123.01", 3u32, RoundingStrategy::AwayFromZero, Some("124")),
("1.2301", 3u32, RoundingStrategy::AwayFromZero, Some("1.24")),
("0.12301", 3u32, RoundingStrategy::AwayFromZero, Some("0.124")),
("0.012301", 3u32, RoundingStrategy::AwayFromZero, Some("0.0124")),
("0.0000012301", 3u32, RoundingStrategy::AwayFromZero, Some("0.00000124")),
("1.012301", 3u32, RoundingStrategy::AwayFromZero, Some("1.02")),
]; for &(input, sf, strategy, expected) in tests { let input = Decimal::from_str(input).unwrap(); let result = input.round_sf_with_strategy(sf, strategy); iflet Some(expected) = expected {
assert!(
result.is_some(), "Expected result for {}.round_sf_with_strategy({}, {:?})",
input,
sf,
strategy
);
assert_eq!(
expected,
result.unwrap().to_string(), "{}.round_sf_with_strategy({}, {:?})",
input,
sf,
strategy
);
} else {
assert!(
result.is_none(), "Unexpected result for {}.round_sf_with_strategy({}, {:?})",
input,
sf,
strategy
);
}
}
}
for &(value, expected) in tests { let value = Decimal::from_str(value).unwrap(); let expected = Decimal::from_str(expected).unwrap(); let trunc = value.trunc();
assert_eq!(expected.to_string(), trunc.to_string());
}
}
for &(value, expected) in tests { let value = Decimal::from_str(value).unwrap(); let expected = Decimal::from_str(expected).unwrap(); let fract = value.fract();
assert_eq!(expected.to_string(), fract.to_string());
}
}
for &(value, expected) in tests { let value = Decimal::from_str(value).unwrap(); let expected = Decimal::from_str(expected).unwrap(); let normalized = value.normalize();
assert_eq!(expected.to_string(), normalized.to_string());
}
}
#[test] fn it_can_go_from_and_into() { let d = Decimal::from_str("5").unwrap(); let di8: Decimal = 5u8.into(); let di32: Decimal = 5i32.into(); let disize: Decimal = 5isize.into(); let di64: Decimal = 5i64.into(); let du8: Decimal = 5u8.into(); let du32: Decimal = 5u32.into(); let dusize: Decimal = 5usize.into(); let du64: Decimal = 5u64.into();
#[test] fn it_handles_simple_underflow() { // Issue #71 let rate = Decimal::new(19, 2); // 0.19 let one = Decimal::new(1, 0); // 1 let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 let result = one * part;
assert_eq!("0.1596638655462184873949579832", result.to_string());
// 169 * 0.1596638655462184873949579832 = 26.983193277310924 let result = part * Decimal::new(169, 0);
assert_eq!("26.983193277310924369747899161", result.to_string()); let result = Decimal::new(169, 0) * part;
assert_eq!("26.983193277310924369747899161", result.to_string());
}
let t = Type::new("".into(), 0, Kind::Simple, "".into());
for test in tests { let input = Decimal::from_str(test).unwrap(); letmut bytes = BytesMut::new();
input.to_sql(&t, &mut bytes).unwrap(); let output = Decimal::from_sql(&t, &bytes).unwrap();
assert_eq!(input, output);
}
}
fn hash_it(d: Decimal) -> u64 { use core::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher;
letmut h = DefaultHasher::new();
d.hash(&mut h);
h.finish()
}
#[test] fn it_computes_equal_hashes_for_equal_values() { // From the Rust Hash docs: // // "When implementing both Hash and Eq, it is important that the following property holds: // // k1 == k2 -> hash(k1) == hash(k2)"
let k1 = Decimal::from_str("1").unwrap(); let k2 = Decimal::from_str("1.0").unwrap(); let k3 = Decimal::from_str("1.00").unwrap(); let k4 = Decimal::from_str("1.01").unwrap();
// Test the application of Hash calculation to a HashMap.
letmut map = std::collections::HashMap::new();
map.insert(k1, k1.to_string()); // map[k2] should overwrite map[k1] because k1 == k2.
map.insert(k2, k2.to_string());
assert_eq!("1.0", map.get(&k3).expect("could not get k3"));
assert_eq!(1, map.len());
// map[k3] should overwrite map[k2] because k3 == k2.
map.insert(k3, k3.to_string()); // map[k4] should not overwrite map[k3] because k4 != k3.
map.insert(k4, k4.to_string());
assert_eq!(2, map.len());
assert_eq!("1.00", map.get(&k1).expect("could not get k1"));
}
#[test] fn it_computes_equal_hashes_for_positive_and_negative_zero() { // Verify 0 and -0 have the same hash let k1 = Decimal::from_str("0").unwrap(); let k2 = Decimal::from_str("-0").unwrap();
assert_eq!(k1, k2); let h1 = hash_it(k1); let h2 = hash_it(k2);
assert_eq!(h1, h2);
// Verify 0 and -0.0 have the same hash let k1 = Decimal::from_str("0").unwrap(); let k2 = Decimal::from_str("-0.0").unwrap();
assert_eq!(k1, k2); let h1 = hash_it(k1); let h2 = hash_it(k2);
assert_eq!(h1, h2);
}
#[test] #[should_panic(expected = "Number less than minimum value that can be represented.")] fn it_handles_i128_min() { let _ = Decimal::from_i128_with_scale(i128::MIN, 0);
}
#[test] fn it_handles_i128_min_safely() { let result = Decimal::try_from_i128_with_scale(i128::MIN, 0);
assert!(result.is_err());
assert_eq!(result.err().unwrap(), Error::LessThanMinimumPossibleValue);
}
#[test] fn it_can_rescale() { let tests = &[
("0", 6, "0.000000", 6),
("0.000000", 2, "0.00", 2),
("0.12345600000", 6, "0.123456", 6),
("0.123456", 12, "0.123456000000", 12),
("0.123456", 0, "0", 0),
("0.000001", 4, "0.0000", 4),
("1233456", 4, "1233456.0000", 4), // Cap to 28
("1.2", 30, "1.2000000000000000000000000000", 28),
("79228162514264337593543950335", 0, "79228162514264337593543950335", 0),
("4951760157141521099596496895", 1, "4951760157141521099596496895.0", 1),
("4951760157141521099596496896", 1, "4951760157141521099596496896.0", 1),
("18446744073709551615", 6, "18446744073709551615.000000", 6),
("-18446744073709551615", 6, "-18446744073709551615.000000", 6), // 27 since we can't fit a scale of 28 for this number
("11.76470588235294", 28, "11.764705882352940000000000000", 27),
];
for &(value_raw, new_scale, expected_value, expected_scale) in tests { letmut value = Decimal::from_str(value_raw).unwrap();
value.rescale(new_scale);
assert_eq!(expected_value, value.to_string());
assert_eq!(expected_scale, value.scale());
}
}
for (input, expected) in test_cases { let input = Decimal::from_str(input).unwrap(); let expected = Decimal::from_str(expected).unwrap();
assert_eq!(expected, input.ln(), "Failed to calculate ln({})", input);
}
}
for input in test_cases { let input = Decimal::from_str(input).unwrap();
assert_eq!("0", input.ln().to_string(), "Failed to calculate ln({})", input);
}
}
#[test] #[should_panic(expected = "Unable to calculate ln for zero")] #[cfg(not(feature = "maths-nopanic"))] fn test_invalid_ln_zero_panic() { let _ = Decimal::ZERO.ln();
}
#[test] #[should_panic(expected = "Unable to calculate ln for negative numbers")] #[cfg(not(feature = "maths-nopanic"))] fn test_invalid_ln_negative_panic() { let _ = Decimal::NEGATIVE_ONE.ln();
}
for (input, expected) in test_cases { let input = Decimal::from_str(input).unwrap(); let expected = Decimal::from_str(expected).unwrap();
assert_eq!(expected, input.log10(), "Failed to calculate log10({})", input);
}
}
for input in test_cases { let input = Decimal::from_str(input).unwrap();
assert_eq!("0", input.log10().to_string(), "Failed to calculate ln({})", input);
}
}
#[test] #[should_panic(expected = "Unable to calculate log10 for zero")] #[cfg(not(feature = "maths-nopanic"))] fn test_invalid_log10_zero_panic() { let _ = Decimal::ZERO.log10();
}
#[test] #[should_panic(expected = "Unable to calculate log10 for negative numbers")] #[cfg(not(feature = "maths-nopanic"))] fn test_invalid_log10_negative_panic() { let _ = Decimal::NEGATIVE_ONE.log10();
}
#[test] fn test_erf() { let test_cases = &[
(
Decimal::from_str("-2.0").unwrap(), // Wolfram give -0.9953222650189527
Decimal::from_str("-0.9953225170750043399400930073").unwrap(),
),
(
Decimal::from_str("-0.4").unwrap(),
Decimal::from_str("-0.4283924127205154977961931420").unwrap(),
),
(
Decimal::from_str("0.4").unwrap(),
Decimal::from_str("0.4283924127205154977961931420").unwrap(),
),
(
Decimal::one(),
Decimal::from_str("0.8427010463338918630217928957").unwrap(),
),
(
Decimal::from_str("2").unwrap(),
Decimal::from_str("0.9953225170750043399400930073").unwrap(),
),
]; for case in test_cases {
assert_eq!(case.1, case.0.erf());
}
}
#[test] fn test_checked_sin() { const ACCEPTED_PRECISION: u32 = 10; let test_cases = &[ // Sin(0)
("0", Some("0")), // Sin(PI/2)
("1.5707963267948966192313216916", Some("1")), // Sin(PI)
("3.1415926535897932384626433833", Some("0")), // Sin(3PI/2)
("4.7123889803846898576939650749", Some("-1")), // Sin(2PI)
("6.2831853071795864769252867666", Some("0")), // Sin(1) ~= 0.8414709848078965066525023216302989996225630607983710656727517099
("1", Some("0.8414709848078965066525023216")), // Sin(2) ~= 0.9092974268256816953960198659117448427022549714478902683789730115
("2", Some("0.9092974268256816953960198659")), // Sin(4) ~= -0.756802495307928251372639094511829094135912887336472571485416773
("4", Some("-0.7568024953079282513726390945")), // Sin(6) ~= -0.279415498198925872811555446611894759627994864318204318483351369
("6", Some("-0.2794154981989258728115554466")), // WA estimate: -0.893653245236708. Legacy ops is closer to f64 accuracy.
( "-79228162514264.337593543950335",
Some(either!("-0.893653245236708", "-0.8963358176")),
),
]; for (input, result) in test_cases { let radians = Decimal::from_str(input).unwrap(); let sin = radians.checked_sin(); iflet Some(result) = result {
assert!(sin.is_some(), "Expected result for sin({})", input); let result = Decimal::from_str(result).unwrap();
assert_approx_eq!(sin.unwrap(), result, ACCEPTED_PRECISION, "sin({})", input);
} else {
assert!(sin.is_none(), "Unexpected result for sin({})", input);
}
}
}
#[test] fn test_checked_cos() { const ACCEPTED_PRECISION: u32 = 10; let test_cases = &[ // Cos(0)
("0", Some("1")), // Cos(PI/2)
("1.5707963267948966192313216916", Some("0")), // Cos(PI)
("3.1415926535897932384626433833", Some("-1")), // Cos(3PI/2)
("4.7123889803846898576939650749", Some("0")), // Cos(2PI)
("6.2831853071795864769252867666", Some("1")), // Cos(1) ~= 0.5403023058681397174009366074429766037323104206179222276700972553
("1", Some("0.5403023058681397174009366074")), // Cos(2) ~= -0.416146836547142386997568229500762189766000771075544890755149973
("2", Some("-0.4161468365471423869975682295")), // Cos(4) ~= -0.653643620863611914639168183097750381424133596646218247007010283
("4", Some("-0.6536436208636119146391681831")), // Cos(6) ~= 0.9601702866503660205456522979229244054519376792110126981292864260
("6", Some("0.9601702866503660205456522979")), // WA estimate: 0.448758150096352. Legacy ops is closer to f64 accuracy.
( "-79228162514264.337593543950335",
Some(either!("0.448758150096352", "0.443375802326")),
),
]; for (input, result) in test_cases { let radians = Decimal::from_str(input).unwrap(); let cos = radians.checked_cos(); iflet Some(result) = result {
assert!(cos.is_some(), "Expected result for cos({})", input); let result = Decimal::from_str(result).unwrap();
assert_approx_eq!(cos.unwrap(), result, ACCEPTED_PRECISION, "cos({})", input);
} else {
assert!(cos.is_none(), "Unexpected result for cos({})", input);
}
}
}
#[test] fn test_checked_tan() { const ACCEPTED_PRECISION: u32 = 8; let test_cases = &[ // Tan(0)
("0", Some("0")), // Tan(PI/2)
("1.5707963267948966192313216916", None), // Tan(PI)
("3.1415926535897932384626433833", Some("0")), // Tan(3PI/2)
("4.7123889803846898576939650749", None), // Tan(2PI)
("6.2831853071795864769252867666", Some("0")), // Tan(1) ~= 1.5574077246549022305069748074583601730872507723815200383839466056
("1", Some("1.5574077246549022305069748075")), // Tan(2) ~= -2.185039863261518991643306102313682543432017746227663164562955869
("2", Some("-2.1850398632615189916433061023")), // Tan(4) ~= 1.1578212823495775831373424182673239231197627673671421300848571893
("4", Some("1.1578212823495775831373424183")), // Tan(6) ~= -0.291006191384749157053699588868175542831155570912339131608827193
("6", Some("-0.2910061913847491570536995889")), // WA estimate: -1.99139167733184. Legacy ops is closer to f64 accuracy.
( "-79228162514264.337593543950335",
Some(either!("-1.99139167733184", "-2.021616454709")),
),
]; for (input, result) in test_cases { let radians = Decimal::from_str(input).unwrap(); let tan = radians.checked_tan(); iflet Some(result) = result {
assert!(tan.is_some(), "Expected result for tan({})", input); let result = Decimal::from_str(result).unwrap();
assert_approx_eq!(tan.unwrap(), result, ACCEPTED_PRECISION, "tan({})", input);
} else {
assert!(tan.is_none(), "Unexpected result for tan({})", input);
}
}
}
}
// Generated tests #[cfg(not(feature = "legacy-ops"))] mod generated { use rust_decimal::prelude::*;
macro_rules! gen_test {
($name:ident, $csv:expr, $method:tt) => { #[test] fn $name() { let path = std::env::current_dir().unwrap(); letmut rdr = csv::Reader::from_reader(
std::fs::File::open(format!("{}/tests/generated/{}", path.display(), $csv)).unwrap(),
); letmut row = 0; for result in rdr.records() { let record = result.unwrap();
row += 1;
// Extract the data let d1 = record.get(0).unwrap(); let d2 = record.get(1).unwrap(); let result = record.get(2).unwrap(); let error = record.get(3).unwrap();
// Do the calc let d1 = Decimal::from_str(&d1).unwrap(); let d2 = Decimal::from_str(&d2).unwrap(); let expected = Decimal::from_str(&result).unwrap(); match d1.$method(d2) {
Some(v) => assert_eq!(expected, v, "Row {}", row),
None => assert!(!error.is_empty()),
}
}
}
};
}
#[cfg(feature = "rocket-traits")] mod rocket { usecrate::Decimal; use rocket::form::{Form, FromForm}; use std::str::FromStr;
#[derive(FromForm)] struct Example {
foo: Decimal,
bar: Decimal,
}
#[test] fn it_can_parse_form() { let parsed: Example = Form::parse("bar=0.12345678901234567890123456789&foo=-123456.78").unwrap();
assert_eq!(parsed.foo, Decimal::from_str("-123456.78").unwrap());
assert_eq!(
parsed.bar,
Decimal::from_str("0.12345678901234567890123456789").unwrap()
);
}
}
#[cfg(feature = "rust-fuzz")] mod rust_fuzz { use arbitrary::{Arbitrary, Unstructured};
usesuper::*;
#[test] fn it_can_generate_arbitrary_decimals() { letmut u = Unstructured::new(b"it_can_generate_arbitrary_decimals"); let d = Decimal::arbitrary(&mut u);
assert!(d.is_ok());
}
}
mod issues { use rust_decimal::prelude::*;
#[test] fn issue_384_neg_overflow_during_subtract_carry() { // 288230376151711744 let a = Decimal::from_parts(0, 67108864, 0, false, 0); // 714606955844629274884780.85120 let b = Decimal::from_parts(0, 0, 3873892070, false, 3873892070); let c = a.checked_sub(b);
assert!(c.is_some());
#[test] fn issue_392_overflow_during_remainder() { let a = Decimal::from_str("-79228157791897.854723898738431").unwrap(); let b = Decimal::from_str("184512476.73336922111").unwrap(); let c = a.checked_div(b);
assert!(c.is_some());
assert_eq!("-429391.87200000000002327170816", c.unwrap().to_string())
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.102 Sekunden
(vorverarbeitet am 2026-06-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.