summaryrefslogtreecommitdiffstats
path: root/third_party/rust/rust_decimal/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/rust_decimal/tests
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/rust_decimal/tests')
-rw-r--r--third_party/rust/rust_decimal/tests/decimal_tests.rs4595
-rw-r--r--third_party/rust/rust_decimal/tests/macros.rs49
-rw-r--r--third_party/rust/rust_decimal/tests/version-numbers.rs9
3 files changed, 4653 insertions, 0 deletions
diff --git a/third_party/rust/rust_decimal/tests/decimal_tests.rs b/third_party/rust/rust_decimal/tests/decimal_tests.rs
new file mode 100644
index 0000000000..71dcf00856
--- /dev/null
+++ b/third_party/rust/rust_decimal/tests/decimal_tests.rs
@@ -0,0 +1,4595 @@
+mod macros;
+
+use core::{cmp::Ordering::*, str::FromStr};
+use num_traits::{Inv, Signed, ToPrimitive};
+use rust_decimal::{Decimal, Error, RoundingStrategy};
+
+#[test]
+#[cfg(feature = "c-repr")]
+fn layout_is_correct() {
+ assert_eq!(std::mem::size_of::<Decimal>(), std::mem::size_of::<u128>());
+}
+
+#[test]
+fn it_can_extract_the_mantissa() {
+ let tests = [
+ ("1", 1i128, 0),
+ ("1.123456", 1123456i128, 6),
+ ("-0.123456", -123456i128, 6),
+ ];
+ for &(input, mantissa, scale) in &tests {
+ let num = Decimal::from_str(input).unwrap();
+ assert_eq!(num.mantissa(), mantissa, "Mantissa for {}", input);
+ assert_eq!(num.scale(), scale, "Scale for {}", input);
+ }
+}
+
+// Parsing
+
+#[test]
+fn it_creates_a_new_negative_decimal() {
+ let a = Decimal::new(-100, 2);
+ assert_eq!(a.is_sign_negative(), true);
+ assert_eq!(a.scale(), 2);
+ assert_eq!("-1.00", a.to_string());
+}
+
+#[test]
+fn it_creates_a_new_decimal_using_numeric_boundaries() {
+ let a = Decimal::new(i64::MAX, 2);
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 2);
+ assert_eq!("92233720368547758.07", a.to_string());
+
+ let b = Decimal::new(i64::MIN, 2);
+ assert_eq!(b.is_sign_negative(), true);
+ assert_eq!(b.scale(), 2);
+ assert_eq!("-92233720368547758.08", b.to_string());
+}
+
+#[test]
+fn it_parses_empty_string() {
+ assert!(Decimal::from_str("").is_err());
+ assert!(Decimal::from_str(" ").is_err());
+}
+
+#[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();
+ let mut 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();
+
+ #[cfg(feature = "rkyv-safe")]
+ {
+ let archived = rkyv::check_archived_root::<Decimal>(&bytes[..]).unwrap();
+ assert_eq!(archived, &a);
+ }
+
+ let archived = unsafe { rkyv::archived_root::<Decimal>(&bytes[..]) };
+ assert_eq!(archived, &a);
+
+ let deserialized: Decimal = archived.deserialize(&mut rkyv::Infallible).unwrap();
+ assert_eq!(deserialized, a);
+ }
+}
+
+#[test]
+fn it_can_deserialize_unbounded_values() {
+ // Mantissa for these: 19393111376951473493673267553
+ let tests = [
+ (
+ [1u8, 0, 28, 206, 97, 81, 216, 182, 20, 30, 165, 78, 18, 155, 169, 62],
+ // Scale 28: -1.9393111376951473493673267553
+ "-1.9393111376951473493673267553",
+ ),
+ (
+ [1u8, 0, 29, 206, 97, 81, 216, 182, 20, 30, 165, 78, 18, 155, 169, 62],
+ // Scale 29: -0.19393111376951473493673267553
+ "-0.1939311137695147349367326755",
+ ),
+ (
+ [1u8, 0, 30, 206, 97, 81, 216, 182, 20, 30, 165, 78, 18, 155, 169, 62],
+ // Scale 30: -0.019393111376951473493673267553
+ "-0.0193931113769514734936732676",
+ ),
+ (
+ [1u8, 0, 31, 206, 97, 81, 216, 182, 20, 30, 165, 78, 18, 155, 169, 62],
+ // Scale 31: -0.0019393111376951473493673267553
+ "-0.0019393111376951473493673268",
+ ),
+ ];
+ for &(bytes, expected) in &tests {
+ let dec = Decimal::deserialize(bytes);
+ let string = format!("{:.9999}", dec);
+ let dec2 = Decimal::from_str(&string).unwrap();
+ assert_eq!(dec, dec2);
+ assert_eq!(dec.to_string(), expected, "dec.to_string()");
+ assert_eq!(dec2.to_string(), expected, "dec2.to_string()");
+ }
+}
+
+// Formatting
+
+#[test]
+fn it_formats() {
+ let a = Decimal::from_str("233.323223").unwrap();
+ assert_eq!(format!("{}", a), "233.323223");
+ assert_eq!(format!("{:.9}", a), "233.323223000");
+ assert_eq!(format!("{:.0}", a), "233");
+ assert_eq!(format!("{:.2}", a), "233.32");
+ assert_eq!(format!("{:010.2}", a), "0000233.32");
+ assert_eq!(format!("{:0<10.2}", a), "233.320000");
+}
+#[test]
+fn it_formats_neg() {
+ let a = Decimal::from_str("-233.323223").unwrap();
+ assert_eq!(format!("{}", a), "-233.323223");
+ assert_eq!(format!("{:.9}", a), "-233.323223000");
+ assert_eq!(format!("{:.0}", a), "-233");
+ assert_eq!(format!("{:.2}", a), "-233.32");
+ assert_eq!(format!("{:010.2}", a), "-000233.32");
+ assert_eq!(format!("{:0<10.2}", a), "-233.32000");
+}
+#[test]
+fn it_formats_small() {
+ let a = Decimal::from_str("0.2223").unwrap();
+ assert_eq!(format!("{}", a), "0.2223");
+ assert_eq!(format!("{:.9}", a), "0.222300000");
+ assert_eq!(format!("{:.0}", a), "0");
+ assert_eq!(format!("{:.2}", a), "0.22");
+ assert_eq!(format!("{:010.2}", a), "0000000.22");
+ assert_eq!(format!("{:0<10.2}", a), "0.22000000");
+}
+#[test]
+fn it_formats_small_leading_zeros() {
+ let a = Decimal::from_str("0.0023554701772169").unwrap();
+ assert_eq!(format!("{}", a), "0.0023554701772169");
+ assert_eq!(format!("{:.9}", a), "0.002355470");
+ assert_eq!(format!("{:.0}", a), "0");
+ assert_eq!(format!("{:.2}", a), "0.00");
+ assert_eq!(format!("{:010.2}", a), "0000000.00");
+ assert_eq!(format!("{:0<10.2}", a), "0.00000000");
+}
+#[test]
+fn it_formats_small_neg() {
+ let a = Decimal::from_str("-0.2223").unwrap();
+ assert_eq!(format!("{}", a), "-0.2223");
+ assert_eq!(format!("{:.9}", a), "-0.222300000");
+ assert_eq!(format!("{:.0}", a), "-0");
+ assert_eq!(format!("{:.2}", a), "-0.22");
+ assert_eq!(format!("{:010.2}", a), "-000000.22");
+ assert_eq!(format!("{:0<10.2}", a), "-0.2200000");
+}
+
+#[test]
+fn it_formats_zero() {
+ let a = Decimal::from_str("0").unwrap();
+ assert_eq!(format!("{}", a), "0");
+ assert_eq!(format!("{:.9}", a), "0.000000000");
+ assert_eq!(format!("{:.0}", a), "0");
+ assert_eq!(format!("{:.2}", a), "0.00");
+ assert_eq!(format!("{:010.2}", a), "0000000.00");
+ assert_eq!(format!("{:0<10.2}", a), "0.00000000");
+}
+
+#[test]
+fn it_formats_int() {
+ let a = Decimal::from_str("5").unwrap();
+ assert_eq!(format!("{}", a), "5");
+ assert_eq!(format!("{:.9}", a), "5.000000000");
+ assert_eq!(format!("{:.0}", a), "5");
+ assert_eq!(format!("{:.2}", a), "5.00");
+ assert_eq!(format!("{:010.2}", a), "0000005.00");
+ assert_eq!(format!("{:0<10.2}", a), "5.00000000");
+}
+
+#[test]
+fn it_formats_lower_exp() {
+ let tests = [
+ ("0.00001", "1e-5"),
+ ("-0.00001", "-1e-5"),
+ ("42.123", "4.2123e1"),
+ ("-42.123", "-4.2123e1"),
+ ("100", "1e2"),
+ ];
+ for (value, expected) in &tests {
+ let a = Decimal::from_str(value).unwrap();
+ assert_eq!(&format!("{:e}", a), *expected, "format!(\"{{:e}}\", {})", a);
+ }
+}
+
+#[test]
+fn it_formats_lower_exp_padding() {
+ let tests = [
+ ("0.00001", "01e-5"),
+ ("-0.00001", "-1e-5"),
+ ("42.123", "4.2123e1"),
+ ("-42.123", "-4.2123e1"),
+ ("100", "001e2"),
+ ];
+ for (value, expected) in &tests {
+ let a = Decimal::from_str(value).unwrap();
+ assert_eq!(&format!("{:05e}", a), *expected, "format!(\"{{:05e}}\", {})", a);
+ }
+}
+
+#[test]
+fn it_formats_scientific_precision() {
+ for (num, scale, expected_no_precision, expected_precision) in [
+ (
+ 123456,
+ 10,
+ "1.23456e-5",
+ [
+ "1e-5",
+ "1.2e-5",
+ "1.23e-5",
+ "1.234e-5",
+ "1.2345e-5",
+ "1.23456e-5",
+ "1.234560e-5",
+ "1.2345600e-5",
+ ],
+ ),
+ (
+ 123456,
+ 0,
+ "1.23456e5",
+ [
+ "1e5",
+ "1.2e5",
+ "1.23e5",
+ "1.234e5",
+ "1.2345e5",
+ "1.23456e5",
+ "1.234560e5",
+ "1.2345600e5",
+ ],
+ ),
+ (
+ 1,
+ 0,
+ "1e0",
+ [
+ "1e0",
+ "1.0e0",
+ "1.00e0",
+ "1.000e0",
+ "1.0000e0",
+ "1.00000e0",
+ "1.000000e0",
+ "1.0000000e0",
+ ],
+ ),
+ (
+ -123456,
+ 10,
+ "-1.23456e-5",
+ [
+ "-1e-5",
+ "-1.2e-5",
+ "-1.23e-5",
+ "-1.234e-5",
+ "-1.2345e-5",
+ "-1.23456e-5",
+ "-1.234560e-5",
+ "-1.2345600e-5",
+ ],
+ ),
+ (
+ -100000,
+ 10,
+ "-1e-5",
+ [
+ "-1e-5",
+ "-1.0e-5",
+ "-1.00e-5",
+ "-1.000e-5",
+ "-1.0000e-5",
+ "-1.00000e-5",
+ "-1.000000e-5",
+ "-1.0000000e-5",
+ ],
+ ),
+ ] {
+ assert_eq!(format!("{:e}", Decimal::new(num, scale)), expected_no_precision);
+ for i in 0..expected_precision.len() {
+ assert_eq!(
+ format!("{:.prec$e}", Decimal::new(num, scale), prec = i),
+ expected_precision[i]
+ );
+ }
+ }
+}
+
+// Negation
+#[test]
+fn it_negates_decimals() {
+ fn neg(a: &str, b: &str) {
+ let a = Decimal::from_str(a).unwrap();
+ let result = -a;
+ assert_eq!(b, result.to_string(), "- {}", a.to_string());
+ }
+
+ let tests = &[
+ ("1", "-1"),
+ ("2", "-2"),
+ ("2454495034", "-2454495034"),
+ ("0.1", "-0.1"),
+ ("11.815126050420168067226890757", "-11.815126050420168067226890757"),
+ ];
+
+ for &(a, b) in tests {
+ neg(a, b);
+ neg(b, a);
+ }
+}
+
+// Addition
+
+#[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() {
+ let mut 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());
+
+ let mut c = &mut a;
+ c += b;
+ assert_eq!("3.98", a.to_string());
+
+ let mut 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());
+ }
+
+ let tests = &[
+ ("0", "0", "0"),
+ ("0", "-0", "0"),
+ ("-0", "0", "0"),
+ ("-0", "-0", "0"),
+ ("2", "3", "-1"),
+ ("3451204593", "2323322332", "1127882261"),
+ ("24544.95034", ".3451204593", "24544.6052195407"),
+ (".1", ".1", "0.0"),
+ (".1", "-.1", "0.2"),
+ ("1.001", "0", "1.001"),
+ ("2", "-3", "5"),
+ ("-2", "3", "-5"),
+ ("-2", "-3", "1"),
+ ("3", "-2", "5"),
+ ("-3", "2", "-5"),
+ ("1.234", "2.4567", "-1.2227"),
+ ("844.13000000", "843.65000000", "0.48000000"),
+ ("79228162514264337593543950335", "79228162514264337593543950335", "0"), // 0xFFFF_FFFF_FFFF_FFFF_FFF_FFFF - 0xFFFF_FFFF_FFFF_FFFF_FFF_FFFF
+ ("79228162514264337593543950335", "0", "79228162514264337593543950335"),
+ ("79228162514264337593543950335", "79228162514264337593543950333", "2"),
+ ("4951760157141521099596496896", "1", "4951760157141521099596496895"), // 0x1000_0000_0000_0000_0000_0000 - 1 = 0x0FFF_FFFF_FFFF_FFFF_FFF_FFFF
+ ("79228162514264337593543950334", "79228162514264337593543950335", "-1"),
+ ("1", "4951760157141521099596496895", "-4951760157141521099596496894"),
+ ("18446744073709551615", "-18446744073709551615", "36893488147419103230"), // 0xFFFF_FFFF_FFFF_FFFF - -0xFFFF_FFFF_FFFF_FFFF
+ ];
+ for &(a, b, c) in tests {
+ sub(a, b, c);
+ }
+}
+
+#[test]
+fn it_can_subassign() {
+ let mut 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());
+
+ let mut c = &mut a;
+ c -= b;
+ assert_eq!("-0.52", a.to_string());
+
+ let mut 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());
+ }
+
+ let tests = &[
+ ("2", "3", "6"),
+ ("2454495034", "3451204593", "8470964534836491162"),
+ ("24544.95034", ".3451204593", "8470.964534836491162"),
+ (".1", ".1", "0.01"),
+ ("0", "1.001", "0"),
+ ("2", "-3", "-6"),
+ ("-2", "3", "-6"),
+ ("-2", "-3", "6"),
+ ("1", "2.01", "2.01"),
+ ("1.0", "2.01", "2.010"), // Scale is always additive
+ (
+ "0.00000000000000001",
+ "0.00000000000000001",
+ "0.0000000000000000000000000000",
+ ),
+ ("0.0000000000000000000000000001", "0.0000000000000000000000000001", "0"),
+ (
+ "0.6386554621848739495798319328",
+ "11.815126050420168067226890757",
+ "7.5457947885036367488171739292",
+ ),
+ (
+ "2123456789012345678901234567.8",
+ "11.815126050420168067226890757",
+ "25088909624801327937270048761",
+ ),
+ (
+ "2123456789012345678901234567.8",
+ "-11.815126050420168067226890757",
+ "-25088909624801327937270048761",
+ ),
+ (
+ "2.1234567890123456789012345678",
+ "2.1234567890123456789012345678",
+ "4.5090687348026215523554336227",
+ ),
+ (
+ "0.48000000",
+ "0.1818181818181818181818181818",
+ either!("0.0872727272727272727272727273", "0.0872727272727272727272727272"),
+ ),
+ ];
+ for &(a, b, c) in tests {
+ mul(a, b, c);
+ }
+}
+
+#[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() {
+ let mut 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());
+
+ let mut c = &mut a;
+ c *= b;
+ assert_eq!("0.00000125", a.to_string());
+
+ let mut 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());
+ }
+
+ let tests = &[
+ ("6", "3", "2"),
+ ("10", "2", "5"),
+ ("2.2", "1.1", "2"),
+ ("-2.2", "-1.1", "2"),
+ ("12.88", "5.6", "2.3"),
+ (
+ "1023427554493",
+ "43432632",
+ either!("23563.562864276795382789603909", "23563.562864276795382789603908"),
+ ),
+ ("10000", "3", "3333.3333333333333333333333333"),
+ ("2", "3", "0.6666666666666666666666666667"),
+ ("1", "3", "0.3333333333333333333333333333"),
+ ("-2", "3", "-0.6666666666666666666666666667"),
+ ("2", "-3", "-0.6666666666666666666666666667"),
+ ("-2", "-3", "0.6666666666666666666666666667"),
+ (
+ "1234.5678",
+ "0.1234567890123456",
+ either!("9999.99926999999982999953127", "9999.999269999999829999531269"),
+ ),
+ ("1234.567890123456789012345678", "1.234567890123456789012345678", "1000"),
+ (
+ "32.91625929004387114334488",
+ "3.27629537",
+ either!("10.046792359274942644546996384", "10.046792359274942644546996383"),
+ ),
+ ("5000", "1000.26957490549", "4.9986524887277738570721416846"),
+ ("6142.6941216127122745222131114", "2", "3071.3470608063561372611065557"),
+ (
+ "3071.3470608063561372611065557",
+ "1228.87000756",
+ either!("2.4993262443638869285360708423", "2.4993262443638869285360708422"),
+ ),
+ (
+ "590.3274854004009467754255123",
+ "53.68997202826239",
+ "10.995116277759516850521689988",
+ ),
+ ];
+ for &(a, b, c) in tests {
+ div(a, b, c);
+ }
+}
+
+#[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() {
+ let mut 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());
+
+ let mut c = &mut a;
+ c /= b;
+ assert_eq!("1250000", a.to_string());
+
+ let mut c = &mut a;
+ c /= &b;
+ assert_eq!("125000000", a.to_string());
+}
+
+// Modulus and Remainder are not the same thing!
+// https://math.stackexchange.com/q/801962/82277
+
+#[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());
+ }
+
+ let tests = &[
+ ("2", "3", "2"),
+ ("-2", "3", "-2"),
+ ("2", "-3", "2"),
+ ("-2", "-3", "-2"),
+ ("6", "3", "0"),
+ ("42.2", "11.9", "6.5"),
+ ("2.1", "3", "2.1"),
+ ("2", "3.1", "2"),
+ ("2.0", "3.1", "2.0"),
+ ("4", "3.1", "0.9"),
+ ("2", "2", "0"),
+ ("2", "-2", "0"),
+ // Legacy keeps sign from lhs operand
+ ("-2", "2", "0"),
+ ("-2", "-2", "0"),
+ ];
+ for &(a, b, c) in tests {
+ rem(a, b, c);
+ }
+}
+
+#[test]
+fn it_can_remassign() {
+ let mut a = Decimal::from_str("5").unwrap();
+ let b = Decimal::from_str("2").unwrap();
+
+ a %= b;
+ assert_eq!("1", a.to_string());
+
+ a %= &b;
+ assert_eq!("1", a.to_string());
+
+ let mut c = &mut a;
+ c %= b;
+ assert_eq!("1", a.to_string());
+
+ let mut c = &mut a;
+ c %= &b;
+ assert_eq!("1", a.to_string());
+}
+
+#[test]
+fn it_eqs_decimals() {
+ fn eq(a: &str, b: &str, c: bool) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ assert_eq!(c, a.eq(&b), "{} == {}", a.to_string(), b.to_string());
+ assert_eq!(c, b.eq(&a), "{} == {}", b.to_string(), a.to_string());
+ }
+
+ let tests = &[
+ ("1", "1", true),
+ ("1", "-1", false),
+ ("1", "1.00", true),
+ ("1.2345000000000", "1.2345", true),
+ ("1.0000000000000000000000000000", "1.0000000000000000000000000000", true),
+ (
+ "1.0000000000000000000000000001",
+ "1.0000000000000000000000000000",
+ false,
+ ),
+ ];
+ for &(a, b, c) in tests {
+ eq(a, b, c);
+ }
+}
+
+#[test]
+fn it_cmps_decimals() {
+ fn cmp(a: &str, b: &str, c: core::cmp::Ordering) {
+ let a = Decimal::from_str(a).unwrap();
+ let b = Decimal::from_str(b).unwrap();
+ assert_eq!(
+ c,
+ a.cmp(&b),
+ "{} {} {}",
+ a.to_string(),
+ match c {
+ Less => "<",
+ Equal => "==",
+ Greater => ">",
+ },
+ b.to_string()
+ );
+ }
+
+ let tests = &[
+ ("1", "1", Equal),
+ ("1", "-1", Greater),
+ ("1", "1.00", Equal),
+ ("1.2345000000000", "1.2345", Equal),
+ (
+ "1.0000000000000000000000000001",
+ "1.0000000000000000000000000000",
+ Greater,
+ ),
+ ("1.0000000000000000000000000000", "1.0000000000000000000000000001", Less),
+ ("-1", "100", Less),
+ ("-100", "1", Less),
+ ("0", "0.5", Less),
+ ("0.5", "0", Greater),
+ ("100", "0.0098", Greater),
+ ("1000000000000000", "999000000000000.0001", Greater),
+ ("2.0001", "2.0001", Equal),
+ (
+ "11.815126050420168067226890757",
+ "0.6386554621848739495798319328",
+ Greater,
+ ),
+ ("0.6386554621848739495798319328", "11.815126050420168067226890757", Less),
+ ("-0.5", "-0.01", Less),
+ ("-0.5", "-0.1", Less),
+ ("-0.01", "-0.5", Greater),
+ ("-0.1", "-0.5", Greater),
+ // 000 equality
+ ("0.00000000", "0.00000000", Equal),
+ // 000 000 same scale
+ ("0.00000000", "0.00000000", Equal),
+ ("-0.00000000", "0.00000000", Equal),
+ ("0.00000000", "-0.00000000", Equal),
+ ("-0.00000000", "-0.00000000", Equal),
+ // 000 000 different scale
+ ("0.000000000", "0.00000000000000000000000", Equal),
+ ("-0.000000000", "0.00000000000000000000000", Equal),
+ ("0.000000000", "-0.00000000000000000000000", Equal),
+ ("-0.000000000", "-0.00000000000000000000000", Equal),
+ // 000 100 same scale
+ ("0.00000000", "6.56792910", Less),
+ ("-0.00000000", "6.56792910", Less),
+ ("0.00000000", "-6.56792910", Greater),
+ ("-0.00000000", "-6.56792910", Greater),
+ // 000 100 different scale
+ ("0.0000000000000000000", "0.00000000000000001916236746", Less),
+ ("-0.0000000000000000000", "0.00000000000000001916236746", Less),
+ ("0.0000000000000000000", "-0.00000000000000001916236746", Greater),
+ ("-0.0000000000000000000", "-0.00000000000000001916236746", Greater),
+ // 000 010 same scale
+ ("0.00000000", "49037796231.72571136", Less),
+ ("-0.00000000", "49037796231.72571136", Less),
+ ("0.00000000", "-49037796231.72571136", Greater),
+ ("-0.00000000", "-49037796231.72571136", Greater),
+ // 000 010 different scale
+ ("0", "14459264155.12895488", Less),
+ ("-0", "14459264155.12895488", Less),
+ ("0", "-14459264155.12895488", Greater),
+ ("-0", "-14459264155.12895488", Greater),
+ // 000 110 same scale
+ ("0.00000000", "38675108055.09052783", Less),
+ ("-0.00000000", "38675108055.09052783", Less),
+ ("0.00000000", "-38675108055.09052783", Greater),
+ ("-0.00000000", "-38675108055.09052783", Greater),
+ // 000 110 different scale
+ ("0.00", "1495767034080324868", Less),
+ ("-0.00", "1495767034080324868", Less),
+ ("0.00", "-1495767034080324868", Greater),
+ ("-0.00", "-1495767034080324868", Greater),
+ // 000 001 same scale
+ ("0.00000000", "359299289270893106016.81305600", Less),
+ ("-0.00000000", "359299289270893106016.81305600", Less),
+ ("0.00000000", "-359299289270893106016.81305600", Greater),
+ ("-0.00000000", "-359299289270893106016.81305600", Greater),
+ // 000 001 different scale
+ ("0.00000000000000000000000000", "261631091689.9518486763536384", Less),
+ ("-0.00000000000000000000000000", "261631091689.9518486763536384", Less),
+ (
+ "0.00000000000000000000000000",
+ "-261631091689.9518486763536384",
+ Greater,
+ ),
+ (
+ "-0.00000000000000000000000000",
+ "-261631091689.9518486763536384",
+ Greater,
+ ),
+ // 000 101 same scale
+ ("0.00000000", "184137107696737410476.63166815", Less),
+ ("-0.00000000", "184137107696737410476.63166815", Less),
+ ("0.00000000", "-184137107696737410476.63166815", Greater),
+ ("-0.00000000", "-184137107696737410476.63166815", Greater),
+ // 000 101 different scale
+ ("0.000000000", "2286857871088.7514840434334478", Less),
+ ("-0.000000000", "2286857871088.7514840434334478", Less),
+ ("0.000000000", "-2286857871088.7514840434334478", Greater),
+ ("-0.000000000", "-2286857871088.7514840434334478", Greater),
+ // 000 011 same scale
+ ("0.00000000", "169194696640288819908.07715840", Less),
+ ("-0.00000000", "169194696640288819908.07715840", Less),
+ ("0.00000000", "-169194696640288819908.07715840", Greater),
+ ("-0.00000000", "-169194696640288819908.07715840", Greater),
+ // 000 011 different scale
+ ("0.00000000", "2757550691.7650076909569048576", Less),
+ ("-0.00000000", "2757550691.7650076909569048576", Less),
+ ("0.00000000", "-2757550691.7650076909569048576", Greater),
+ ("-0.00000000", "-2757550691.7650076909569048576", Greater),
+ // 000 111 same scale
+ ("0.00000000", "133610725292915899001.10059212", Less),
+ ("-0.00000000", "133610725292915899001.10059212", Less),
+ ("0.00000000", "-133610725292915899001.10059212", Greater),
+ ("-0.00000000", "-133610725292915899001.10059212", Greater),
+ // 000 111 different scale
+ ("0.00000000000000000000", "86.25432767926620368822165265", Less),
+ ("-0.00000000000000000000", "86.25432767926620368822165265", Less),
+ ("0.00000000000000000000", "-86.25432767926620368822165265", Greater),
+ ("-0.00000000000000000000", "-86.25432767926620368822165265", Greater),
+ // 100 equality
+ ("0.0000000000598992228", "0.0000000000598992228", Equal),
+ // 100 000 same scale
+ ("0.0000000000598992228", "0.0000000000000000000", Greater),
+ ("-0.0000000000598992228", "0.0000000000000000000", Less),
+ ("0.0000000000598992228", "-0.0000000000000000000", Greater),
+ ("-0.0000000000598992228", "-0.0000000000000000000", Less),
+ // 100 000 different scale
+ ("0.1797407597", "0.0000000000000000000", Greater),
+ ("-0.1797407597", "0.0000000000000000000", Less),
+ ("0.1797407597", "-0.0000000000000000000", Greater),
+ ("-0.1797407597", "-0.0000000000000000000", Less),
+ // 100 100 same scale
+ ("0.0000000000598992228", "0.0000000000064510789", Greater),
+ ("-0.0000000000598992228", "0.0000000000064510789", Less),
+ ("0.0000000000598992228", "-0.0000000000064510789", Greater),
+ ("-0.0000000000598992228", "-0.0000000000064510789", Less),
+ // 100 100 different scale
+ ("0.000000000000011217354", "0.0000000000217735186", Less),
+ ("-0.000000000000011217354", "0.0000000000217735186", Less),
+ ("0.000000000000011217354", "-0.0000000000217735186", Greater),
+ ("-0.000000000000011217354", "-0.0000000000217735186", Greater),
+ // 100 010 same scale
+ ("0.0000000000598992228", "0.0659116848159129600", Less),
+ ("-0.0000000000598992228", "0.0659116848159129600", Less),
+ ("0.0000000000598992228", "-0.0659116848159129600", Greater),
+ ("-0.0000000000598992228", "-0.0659116848159129600", Greater),
+ // 100 010 different scale
+ ("0.00042035421", "0.004709460588143575040", Less),
+ ("-0.00042035421", "0.004709460588143575040", Less),
+ ("0.00042035421", "-0.004709460588143575040", Greater),
+ ("-0.00042035421", "-0.004709460588143575040", Greater),
+ // 100 110 same scale
+ ("0.0000000000598992228", "0.0755686585127091375", Less),
+ ("-0.0000000000598992228", "0.0755686585127091375", Less),
+ ("0.0000000000598992228", "-0.0755686585127091375", Greater),
+ ("-0.0000000000598992228", "-0.0755686585127091375", Greater),
+ // 100 110 different scale
+ ("14872.94465", "1284707831905.854085", Less),
+ ("-14872.94465", "1284707831905.854085", Less),
+ ("14872.94465", "-1284707831905.854085", Greater),
+ ("-14872.94465", "-1284707831905.854085", Greater),
+ // 100 001 same scale
+ ("0.0000000000598992228", "888767595.6145376468836286464", Less),
+ ("-0.0000000000598992228", "888767595.6145376468836286464", Less),
+ ("0.0000000000598992228", "-888767595.6145376468836286464", Greater),
+ ("-0.0000000000598992228", "-888767595.6145376468836286464", Greater),
+ // 100 001 different scale
+ ("0.0002108155975", "36.07555527243968476014968832", Less),
+ ("-0.0002108155975", "36.07555527243968476014968832", Less),
+ ("0.0002108155975", "-36.07555527243968476014968832", Greater),
+ ("-0.0002108155975", "-36.07555527243968476014968832", Greater),
+ // 100 101 same scale
+ ("0.0000000000598992228", "125730345.7412344676309569911", Less),
+ ("-0.0000000000598992228", "125730345.7412344676309569911", Less),
+ ("0.0000000000598992228", "-125730345.7412344676309569911", Greater),
+ ("-0.0000000000598992228", "-125730345.7412344676309569911", Greater),
+ // 100 101 different scale
+ ("0.0000000000871576741", "1.7283925558865766140690239662", Less),
+ ("-0.0000000000871576741", "1.7283925558865766140690239662", Less),
+ ("0.0000000000871576741", "-1.7283925558865766140690239662", Greater),
+ ("-0.0000000000871576741", "-1.7283925558865766140690239662", Greater),
+ // 100 011 same scale
+ ("0.0000000000598992228", "645513262.9193254090737451008", Less),
+ ("-0.0000000000598992228", "645513262.9193254090737451008", Less),
+ ("0.0000000000598992228", "-645513262.9193254090737451008", Greater),
+ ("-0.0000000000598992228", "-645513262.9193254090737451008", Greater),
+ // 100 011 different scale
+ ("0.000000000000000760885021", "3718370638.2004059326675681280", Less),
+ ("-0.000000000000000760885021", "3718370638.2004059326675681280", Less),
+ ("0.000000000000000760885021", "-3718370638.2004059326675681280", Greater),
+ (
+ "-0.000000000000000760885021",
+ "-3718370638.2004059326675681280",
+ Greater,
+ ),
+ // 100 111 same scale
+ ("0.0000000000598992228", "422482675.5515775479939306437", Less),
+ ("-0.0000000000598992228", "422482675.5515775479939306437", Less),
+ ("0.0000000000598992228", "-422482675.5515775479939306437", Greater),
+ ("-0.0000000000598992228", "-422482675.5515775479939306437", Greater),
+ // 100 111 different scale
+ ("0.000000044182898", "25.452953262109919998605674045", Less),
+ ("-0.000000044182898", "25.452953262109919998605674045", Less),
+ ("0.000000044182898", "-25.452953262109919998605674045", Greater),
+ ("-0.000000044182898", "-25.452953262109919998605674045", Greater),
+ // 010 equality
+ ("423.1744746042687488", "423.1744746042687488", Equal),
+ // 010 000 same scale
+ ("423.1744746042687488", "0.0000000000000000", Greater),
+ ("-423.1744746042687488", "0.0000000000000000", Less),
+ ("423.1744746042687488", "-0.0000000000000000", Greater),
+ ("-423.1744746042687488", "-0.0000000000000000", Less),
+ // 010 000 different scale
+ ("9002354991.192604672", "0.00000000000000000000000000", Greater),
+ ("-9002354991.192604672", "0.00000000000000000000000000", Less),
+ ("9002354991.192604672", "-0.00000000000000000000000000", Greater),
+ ("-9002354991.192604672", "-0.00000000000000000000000000", Less),
+ // 010 100 same scale
+ ("423.1744746042687488", "0.0000000981820809", Greater),
+ ("-423.1744746042687488", "0.0000000981820809", Less),
+ ("423.1744746042687488", "-0.0000000981820809", Greater),
+ ("-423.1744746042687488", "-0.0000000981820809", Less),
+ // 010 100 different scale
+ ("4327019125101559.808", "0.00484846050", Greater),
+ ("-4327019125101559.808", "0.00484846050", Less),
+ ("4327019125101559.808", "-0.00484846050", Greater),
+ ("-4327019125101559.808", "-0.00484846050", Less),
+ // 010 010 same scale
+ ("423.1744746042687488", "786.9082854590775296", Less),
+ ("-423.1744746042687488", "786.9082854590775296", Less),
+ ("423.1744746042687488", "-786.9082854590775296", Greater),
+ ("-423.1744746042687488", "-786.9082854590775296", Greater),
+ // 010 010 different scale
+ ("793.0067125291450368", "0.0001587297248335626240", Greater),
+ ("-793.0067125291450368", "0.0001587297248335626240", Less),
+ ("793.0067125291450368", "-0.0001587297248335626240", Greater),
+ ("-793.0067125291450368", "-0.0001587297248335626240", Less),
+ // 010 110 same scale
+ ("423.1744746042687488", "300.0541360230572049", Greater),
+ ("-423.1744746042687488", "300.0541360230572049", Less),
+ ("423.1744746042687488", "-300.0541360230572049", Greater),
+ ("-423.1744746042687488", "-300.0541360230572049", Less),
+ // 010 110 different scale
+ ("90627.2042582540288", "4472414566654924.741", Less),
+ ("-90627.2042582540288", "4472414566654924.741", Less),
+ ("90627.2042582540288", "-4472414566654924.741", Greater),
+ ("-90627.2042582540288", "-4472414566654924.741", Greater),
+ // 010 001 same scale
+ ("423.1744746042687488", "3960577151543.5796707636412416", Less),
+ ("-423.1744746042687488", "3960577151543.5796707636412416", Less),
+ ("423.1744746042687488", "-3960577151543.5796707636412416", Greater),
+ ("-423.1744746042687488", "-3960577151543.5796707636412416", Greater),
+ // 010 001 different scale
+ ("0.000008867461591822499840", "185286.04378228713249986052096", Less),
+ ("-0.000008867461591822499840", "185286.04378228713249986052096", Less),
+ ("0.000008867461591822499840", "-185286.04378228713249986052096", Greater),
+ (
+ "-0.000008867461591822499840",
+ "-185286.04378228713249986052096",
+ Greater,
+ ),
+ // 010 101 same scale
+ ("423.1744746042687488", "2825958416017.6213507229869501", Less),
+ ("-423.1744746042687488", "2825958416017.6213507229869501", Less),
+ ("423.1744746042687488", "-2825958416017.6213507229869501", Greater),
+ ("-423.1744746042687488", "-2825958416017.6213507229869501", Greater),
+ // 010 101 different scale
+ ("0.01901870767742648320", "37662082383021542232.529651212", Less),
+ ("-0.01901870767742648320", "37662082383021542232.529651212", Less),
+ ("0.01901870767742648320", "-37662082383021542232.529651212", Greater),
+ ("-0.01901870767742648320", "-37662082383021542232.529651212", Greater),
+ // 010 011 same scale
+ ("423.1744746042687488", "3628063966991.6759417059016704", Less),
+ ("-423.1744746042687488", "3628063966991.6759417059016704", Less),
+ ("423.1744746042687488", "-3628063966991.6759417059016704", Greater),
+ ("-423.1744746042687488", "-3628063966991.6759417059016704", Greater),
+ // 010 011 different scale
+ ("45359904.32470925312", "2.4203452488052342918570049536", Greater),
+ ("-45359904.32470925312", "2.4203452488052342918570049536", Less),
+ ("45359904.32470925312", "-2.4203452488052342918570049536", Greater),
+ ("-45359904.32470925312", "-2.4203452488052342918570049536", Less),
+ // 010 111 same scale
+ ("423.1744746042687488", "2629665172331.9610693820109120", Less),
+ ("-423.1744746042687488", "2629665172331.9610693820109120", Less),
+ ("423.1744746042687488", "-2629665172331.9610693820109120", Greater),
+ ("-423.1744746042687488", "-2629665172331.9610693820109120", Greater),
+ // 010 111 different scale
+ ("0.0006420803252266205184", "8172.032417576265900588945489", Less),
+ ("-0.0006420803252266205184", "8172.032417576265900588945489", Less),
+ ("0.0006420803252266205184", "-8172.032417576265900588945489", Greater),
+ ("-0.0006420803252266205184", "-8172.032417576265900588945489", Greater),
+ // 110 equality
+ ("844.5530620517286511", "844.5530620517286511", Equal),
+ // 110 000 same scale
+ ("844.5530620517286511", "0.0000000000000000", Greater),
+ ("-844.5530620517286511", "0.0000000000000000", Less),
+ ("844.5530620517286511", "-0.0000000000000000", Greater),
+ ("-844.5530620517286511", "-0.0000000000000000", Less),
+ // 110 000 different scale
+ ("3285.530033386074797", "0.00000000000000000000", Greater),
+ ("-3285.530033386074797", "0.00000000000000000000", Less),
+ ("3285.530033386074797", "-0.00000000000000000000", Greater),
+ ("-3285.530033386074797", "-0.00000000000000000000", Less),
+ // 110 100 same scale
+ ("844.5530620517286511", "0.0000001953470063", Greater),
+ ("-844.5530620517286511", "0.0000001953470063", Less),
+ ("844.5530620517286511", "-0.0000001953470063", Greater),
+ ("-844.5530620517286511", "-0.0000001953470063", Less),
+ // 110 100 different scale
+ ("371284.0210972493371", "0.000000000000001307794657", Greater),
+ ("-371284.0210972493371", "0.000000000000001307794657", Less),
+ ("371284.0210972493371", "-0.000000000000001307794657", Greater),
+ ("-371284.0210972493371", "-0.000000000000001307794657", Less),
+ // 110 010 same scale
+ ("844.5530620517286511", "612.1542773033140224", Greater),
+ ("-844.5530620517286511", "612.1542773033140224", Less),
+ ("844.5530620517286511", "-612.1542773033140224", Greater),
+ ("-844.5530620517286511", "-612.1542773033140224", Less),
+ // 110 010 different scale
+ ("0.00004869219159821525572", "23341676485159.15776", Less),
+ ("-0.00004869219159821525572", "23341676485159.15776", Less),
+ ("0.00004869219159821525572", "-23341676485159.15776", Greater),
+ ("-0.00004869219159821525572", "-23341676485159.15776", Greater),
+ // 110 110 same scale
+ ("844.5530620517286511", "326.6132818317622015", Greater),
+ ("-844.5530620517286511", "326.6132818317622015", Less),
+ ("844.5530620517286511", "-326.6132818317622015", Greater),
+ ("-844.5530620517286511", "-326.6132818317622015", Less),
+ // 110 110 different scale
+ ("4752139369958.820619", "1330851022882027.972", Less),
+ ("-4752139369958.820619", "1330851022882027.972", Less),
+ ("4752139369958.820619", "-1330851022882027.972", Greater),
+ ("-4752139369958.820619", "-1330851022882027.972", Greater),
+ // 110 001 same scale
+ ("844.5530620517286511", "3585610241942.1922435648192512", Less),
+ ("-844.5530620517286511", "3585610241942.1922435648192512", Less),
+ ("844.5530620517286511", "-3585610241942.1922435648192512", Greater),
+ ("-844.5530620517286511", "-3585610241942.1922435648192512", Greater),
+ // 110 001 different scale
+ ("539313715923.4424678", "12410950080603997079634706432", Less),
+ ("-539313715923.4424678", "12410950080603997079634706432", Less),
+ ("539313715923.4424678", "-12410950080603997079634706432", Greater),
+ ("-539313715923.4424678", "-12410950080603997079634706432", Greater),
+ // 110 101 same scale
+ ("844.5530620517286511", "1947825396031.6933708908343230", Less),
+ ("-844.5530620517286511", "1947825396031.6933708908343230", Less),
+ ("844.5530620517286511", "-1947825396031.6933708908343230", Greater),
+ ("-844.5530620517286511", "-1947825396031.6933708908343230", Greater),
+ // 110 101 different scale
+ ("0.2301405445512525317", "245433629587.71206426704897154", Less),
+ ("-0.2301405445512525317", "245433629587.71206426704897154", Less),
+ ("0.2301405445512525317", "-245433629587.71206426704897154", Greater),
+ ("-0.2301405445512525317", "-245433629587.71206426704897154", Greater),
+ // 110 011 same scale
+ ("844.5530620517286511", "3637850451015.0843464291450880", Less),
+ ("-844.5530620517286511", "3637850451015.0843464291450880", Less),
+ ("844.5530620517286511", "-3637850451015.0843464291450880", Greater),
+ ("-844.5530620517286511", "-3637850451015.0843464291450880", Greater),
+ // 110 011 different scale
+ ("0.00000000717944802566514691", "18143443615.480512395717115904", Less),
+ ("-0.00000000717944802566514691", "18143443615.480512395717115904", Less),
+ (
+ "0.00000000717944802566514691",
+ "-18143443615.480512395717115904",
+ Greater,
+ ),
+ (
+ "-0.00000000717944802566514691",
+ "-18143443615.480512395717115904",
+ Greater,
+ ),
+ // 110 111 same scale
+ ("844.5530620517286511", "2738424264600.4917875777303163", Less),
+ ("-844.5530620517286511", "2738424264600.4917875777303163", Less),
+ ("844.5530620517286511", "-2738424264600.4917875777303163", Greater),
+ ("-844.5530620517286511", "-2738424264600.4917875777303163", Greater),
+ // 110 111 different scale
+ ("0.0000000007762706076409491335", "2489879185787497651.6458518595", Less),
+ (
+ "-0.0000000007762706076409491335",
+ "2489879185787497651.6458518595",
+ Less,
+ ),
+ (
+ "0.0000000007762706076409491335",
+ "-2489879185787497651.6458518595",
+ Greater,
+ ),
+ (
+ "-0.0000000007762706076409491335",
+ "-2489879185787497651.6458518595",
+ Greater,
+ ),
+ // 001 equality
+ ("316007568232.9263258873102336", "316007568232.9263258873102336", Equal),
+ // 001 000 same scale
+ ("316007568232.9263258873102336", "0.0000000000000000", Greater),
+ ("-316007568232.9263258873102336", "0.0000000000000000", Less),
+ ("316007568232.9263258873102336", "-0.0000000000000000", Greater),
+ ("-316007568232.9263258873102336", "-0.0000000000000000", Less),
+ // 001 000 different scale
+ ("3522055990024364385815547084.8", "0.000000000000", Greater),
+ ("-3522055990024364385815547084.8", "0.000000000000", Less),
+ ("3522055990024364385815547084.8", "-0.000000000000", Greater),
+ ("-3522055990024364385815547084.8", "-0.000000000000", Less),
+ // 001 100 same scale
+ ("316007568232.9263258873102336", "0.0000001073412971", Greater),
+ ("-316007568232.9263258873102336", "0.0000001073412971", Less),
+ ("316007568232.9263258873102336", "-0.0000001073412971", Greater),
+ ("-316007568232.9263258873102336", "-0.0000001073412971", Less),
+ // 001 100 different scale
+ ("1319006.0491408208640440532992", "0.00000000000000611866432", Greater),
+ ("-1319006.0491408208640440532992", "0.00000000000000611866432", Less),
+ ("1319006.0491408208640440532992", "-0.00000000000000611866432", Greater),
+ ("-1319006.0491408208640440532992", "-0.00000000000000611866432", Less),
+ // 001 010 same scale
+ ("316007568232.9263258873102336", "159.1054215143227392", Greater),
+ ("-316007568232.9263258873102336", "159.1054215143227392", Less),
+ ("316007568232.9263258873102336", "-159.1054215143227392", Greater),
+ ("-316007568232.9263258873102336", "-159.1054215143227392", Less),
+ // 001 010 different scale
+ ("2470144.7146711063666704252928", "211.0186916505714688", Greater),
+ ("-2470144.7146711063666704252928", "211.0186916505714688", Less),
+ ("2470144.7146711063666704252928", "-211.0186916505714688", Greater),
+ ("-2470144.7146711063666704252928", "-211.0186916505714688", Less),
+ // 001 110 same scale
+ ("316007568232.9263258873102336", "15.1186658969096112", Greater),
+ ("-316007568232.9263258873102336", "15.1186658969096112", Less),
+ ("316007568232.9263258873102336", "-15.1186658969096112", Greater),
+ ("-316007568232.9263258873102336", "-15.1186658969096112", Less),
+ // 001 110 different scale
+ ("3840504199004148630832.3360768", "7581138850996748864", Greater),
+ ("-3840504199004148630832.3360768", "7581138850996748864", Less),
+ ("3840504199004148630832.3360768", "-7581138850996748864", Greater),
+ ("-3840504199004148630832.3360768", "-7581138850996748864", Less),
+ // 001 001 same scale
+ ("316007568232.9263258873102336", "810157633226.6053390856880128", Less),
+ ("-316007568232.9263258873102336", "810157633226.6053390856880128", Less),
+ (
+ "316007568232.9263258873102336",
+ "-810157633226.6053390856880128",
+ Greater,
+ ),
+ (
+ "-316007568232.9263258873102336",
+ "-810157633226.6053390856880128",
+ Greater,
+ ),
+ // 001 001 different scale
+ ("1951046382014.4037956952260608", "3626102772868740412010083.1232", Less),
+ (
+ "-1951046382014.4037956952260608",
+ "3626102772868740412010083.1232",
+ Less,
+ ),
+ (
+ "1951046382014.4037956952260608",
+ "-3626102772868740412010083.1232",
+ Greater,
+ ),
+ (
+ "-1951046382014.4037956952260608",
+ "-3626102772868740412010083.1232",
+ Greater,
+ ),
+ // 001 101 same scale
+ ("316007568232.9263258873102336", "3258394380359.1965879291312453", Less),
+ ("-316007568232.9263258873102336", "3258394380359.1965879291312453", Less),
+ (
+ "316007568232.9263258873102336",
+ "-3258394380359.1965879291312453",
+ Greater,
+ ),
+ (
+ "-316007568232.9263258873102336",
+ "-3258394380359.1965879291312453",
+ Greater,
+ ),
+ // 001 101 different scale
+ (
+ "17580513970289834.943527780352",
+ "3.7977957031395371036126086595",
+ Greater,
+ ),
+ (
+ "-17580513970289834.943527780352",
+ "3.7977957031395371036126086595",
+ Less,
+ ),
+ (
+ "17580513970289834.943527780352",
+ "-3.7977957031395371036126086595",
+ Greater,
+ ),
+ (
+ "-17580513970289834.943527780352",
+ "-3.7977957031395371036126086595",
+ Less,
+ ),
+ // 001 011 same scale
+ ("316007568232.9263258873102336", "1154574080460.9867510617997312", Less),
+ ("-316007568232.9263258873102336", "1154574080460.9867510617997312", Less),
+ (
+ "316007568232.9263258873102336",
+ "-1154574080460.9867510617997312",
+ Greater,
+ ),
+ (
+ "-316007568232.9263258873102336",
+ "-1154574080460.9867510617997312",
+ Greater,
+ ),
+ // 001 011 different scale
+ ("2008379587.5525351789031325696", "32824109460554.341800487157760", Less),
+ (
+ "-2008379587.5525351789031325696",
+ "32824109460554.341800487157760",
+ Less,
+ ),
+ (
+ "2008379587.5525351789031325696",
+ "-32824109460554.341800487157760",
+ Greater,
+ ),
+ (
+ "-2008379587.5525351789031325696",
+ "-32824109460554.341800487157760",
+ Greater,
+ ),
+ // 001 111 same scale
+ ("316007568232.9263258873102336", "2816795479724.6069787794805311", Less),
+ ("-316007568232.9263258873102336", "2816795479724.6069787794805311", Less),
+ (
+ "316007568232.9263258873102336",
+ "-2816795479724.6069787794805311",
+ Greater,
+ ),
+ (
+ "-316007568232.9263258873102336",
+ "-2816795479724.6069787794805311",
+ Greater,
+ ),
+ // 001 111 different scale
+ (
+ "3536806574745420013541890.4576",
+ "9793146.81730411145833529126",
+ Greater,
+ ),
+ ("-3536806574745420013541890.4576", "9793146.81730411145833529126", Less),
+ (
+ "3536806574745420013541890.4576",
+ "-9793146.81730411145833529126",
+ Greater,
+ ),
+ ("-3536806574745420013541890.4576", "-9793146.81730411145833529126", Less),
+ // 101 equality
+ (
+ "254208186622762823842.71629992",
+ "254208186622762823842.71629992",
+ Equal,
+ ),
+ // 101 000 same scale
+ ("254208186622762823842.71629992", "0.00000000", Greater),
+ ("-254208186622762823842.71629992", "0.00000000", Less),
+ ("254208186622762823842.71629992", "-0.00000000", Greater),
+ ("-254208186622762823842.71629992", "-0.00000000", Less),
+ // 101 000 different scale
+ ("975421950664039.3614304091804", "0.0000000000000000", Greater),
+ ("-975421950664039.3614304091804", "0.0000000000000000", Less),
+ ("975421950664039.3614304091804", "-0.0000000000000000", Greater),
+ ("-975421950664039.3614304091804", "-0.0000000000000000", Less),
+ // 101 100 same scale
+ ("254208186622762823842.71629992", "10.74141379", Greater),
+ ("-254208186622762823842.71629992", "10.74141379", Less),
+ ("254208186622762823842.71629992", "-10.74141379", Greater),
+ ("-254208186622762823842.71629992", "-10.74141379", Less),
+ // 101 100 different scale
+ ("2552221405032275.8358630506229", "0.000000000000000592656995", Greater),
+ ("-2552221405032275.8358630506229", "0.000000000000000592656995", Less),
+ ("2552221405032275.8358630506229", "-0.000000000000000592656995", Greater),
+ ("-2552221405032275.8358630506229", "-0.000000000000000592656995", Less),
+ // 101 010 same scale
+ ("254208186622762823842.71629992", "62767493748.48499712", Greater),
+ ("-254208186622762823842.71629992", "62767493748.48499712", Less),
+ ("254208186622762823842.71629992", "-62767493748.48499712", Greater),
+ ("-254208186622762823842.71629992", "-62767493748.48499712", Less),
+ // 101 010 different scale
+ ("197346074219.25327589999174264", "0.7623493575178715136", Greater),
+ ("-197346074219.25327589999174264", "0.7623493575178715136", Less),
+ ("197346074219.25327589999174264", "-0.7623493575178715136", Greater),
+ ("-197346074219.25327589999174264", "-0.7623493575178715136", Less),
+ // 101 110 same scale
+ ("254208186622762823842.71629992", "76597126194.51389094", Greater),
+ ("-254208186622762823842.71629992", "76597126194.51389094", Less),
+ ("254208186622762823842.71629992", "-76597126194.51389094", Greater),
+ ("-254208186622762823842.71629992", "-76597126194.51389094", Less),
+ // 101 110 different scale
+ ("25899773651648.380071130043467", "61306258142804903.38", Less),
+ ("-25899773651648.380071130043467", "61306258142804903.38", Less),
+ ("25899773651648.380071130043467", "-61306258142804903.38", Greater),
+ ("-25899773651648.380071130043467", "-61306258142804903.38", Greater),
+ // 101 001 same scale
+ (
+ "254208186622762823842.71629992",
+ "83547191565151621967.28086528",
+ Greater,
+ ),
+ ("-254208186622762823842.71629992", "83547191565151621967.28086528", Less),
+ (
+ "254208186622762823842.71629992",
+ "-83547191565151621967.28086528",
+ Greater,
+ ),
+ (
+ "-254208186622762823842.71629992",
+ "-83547191565151621967.28086528",
+ Less,
+ ),
+ // 101 001 different scale
+ ("244762.90302171293318719286219", "9964072.600255221193011888128", Less),
+ ("-244762.90302171293318719286219", "9964072.600255221193011888128", Less),
+ (
+ "244762.90302171293318719286219",
+ "-9964072.600255221193011888128",
+ Greater,
+ ),
+ (
+ "-244762.90302171293318719286219",
+ "-9964072.600255221193011888128",
+ Greater,
+ ),
+ // 101 101 same scale
+ (
+ "254208186622762823842.71629992",
+ "106541875981662806348.63716235",
+ Greater,
+ ),
+ (
+ "-254208186622762823842.71629992",
+ "106541875981662806348.63716235",
+ Less,
+ ),
+ (
+ "254208186622762823842.71629992",
+ "-106541875981662806348.63716235",
+ Greater,
+ ),
+ (
+ "-254208186622762823842.71629992",
+ "-106541875981662806348.63716235",
+ Less,
+ ),
+ // 101 101 different scale
+ ("362319.18250030256385507568342", "3619454249020577423546109236", Less),
+ ("-362319.18250030256385507568342", "3619454249020577423546109236", Less),
+ (
+ "362319.18250030256385507568342",
+ "-3619454249020577423546109236",
+ Greater,
+ ),
+ (
+ "-362319.18250030256385507568342",
+ "-3619454249020577423546109236",
+ Greater,
+ ),
+ // 101 011 same scale
+ (
+ "254208186622762823842.71629992",
+ "156781478378762688050.06557184",
+ Greater,
+ ),
+ (
+ "-254208186622762823842.71629992",
+ "156781478378762688050.06557184",
+ Less,
+ ),
+ (
+ "254208186622762823842.71629992",
+ "-156781478378762688050.06557184",
+ Greater,
+ ),
+ (
+ "-254208186622762823842.71629992",
+ "-156781478378762688050.06557184",
+ Less,
+ ),
+ // 101 011 different scale
+ ("2486073465266.0337130589931876", "153874906950888902858.19691008", Less),
+ (
+ "-2486073465266.0337130589931876",
+ "153874906950888902858.19691008",
+ Less,
+ ),
+ (
+ "2486073465266.0337130589931876",
+ "-153874906950888902858.19691008",
+ Greater,
+ ),
+ (
+ "-2486073465266.0337130589931876",
+ "-153874906950888902858.19691008",
+ Greater,
+ ),
+ // 101 111 same scale
+ (
+ "254208186622762823842.71629992",
+ "10101645723744656462.08148676",
+ Greater,
+ ),
+ ("-254208186622762823842.71629992", "10101645723744656462.08148676", Less),
+ (
+ "254208186622762823842.71629992",
+ "-10101645723744656462.08148676",
+ Greater,
+ ),
+ (
+ "-254208186622762823842.71629992",
+ "-10101645723744656462.08148676",
+ Less,
+ ),
+ // 101 111 different scale
+ ("14107601965.909635434653634526", "111238758546502973973477.99454", Less),
+ (
+ "-14107601965.909635434653634526",
+ "111238758546502973973477.99454",
+ Less,
+ ),
+ (
+ "14107601965.909635434653634526",
+ "-111238758546502973973477.99454",
+ Greater,
+ ),
+ (
+ "-14107601965.909635434653634526",
+ "-111238758546502973973477.99454",
+ Greater,
+ ),
+ // 011 equality
+ (
+ "272322.48219624218537039495168",
+ "272322.48219624218537039495168",
+ Equal,
+ ),
+ // 011 000 same scale
+ ("272322.48219624218537039495168", "0.00000000000000000000000", Greater),
+ ("-272322.48219624218537039495168", "0.00000000000000000000000", Less),
+ ("272322.48219624218537039495168", "-0.00000000000000000000000", Greater),
+ ("-272322.48219624218537039495168", "-0.00000000000000000000000", Less),
+ // 011 000 different scale
+ ("3214885516.0787854158246969344", "0.00000000000000000", Greater),
+ ("-3214885516.0787854158246969344", "0.00000000000000000", Less),
+ ("3214885516.0787854158246969344", "-0.00000000000000000", Greater),
+ ("-3214885516.0787854158246969344", "-0.00000000000000000", Less),
+ // 011 100 same scale
+ ("272322.48219624218537039495168", "0.00000000000000379487994", Greater),
+ ("-272322.48219624218537039495168", "0.00000000000000379487994", Less),
+ ("272322.48219624218537039495168", "-0.00000000000000379487994", Greater),
+ ("-272322.48219624218537039495168", "-0.00000000000000379487994", Less),
+ // 011 100 different scale
+ ("388166715906.19371912596291584", "0.000000000000001996700736", Greater),
+ ("-388166715906.19371912596291584", "0.000000000000001996700736", Less),
+ ("388166715906.19371912596291584", "-0.000000000000001996700736", Greater),
+ ("-388166715906.19371912596291584", "-0.000000000000001996700736", Less),
+ // 011 010 same scale
+ ("272322.48219624218537039495168", "0.00000175873997328613376", Greater),
+ ("-272322.48219624218537039495168", "0.00000175873997328613376", Less),
+ ("272322.48219624218537039495168", "-0.00000175873997328613376", Greater),
+ ("-272322.48219624218537039495168", "-0.00000175873997328613376", Less),
+ // 011 010 different scale
+ (
+ "17963864.0946434527121637376",
+ "0.0000000001112699367808040960",
+ Greater,
+ ),
+ ("-17963864.0946434527121637376", "0.0000000001112699367808040960", Less),
+ (
+ "17963864.0946434527121637376",
+ "-0.0000000001112699367808040960",
+ Greater,
+ ),
+ ("-17963864.0946434527121637376", "-0.0000000001112699367808040960", Less),
+ // 011 110 same scale
+ ("272322.48219624218537039495168", "0.00009168252278596474115", Greater),
+ ("-272322.48219624218537039495168", "0.00009168252278596474115", Less),
+ ("272322.48219624218537039495168", "-0.00009168252278596474115", Greater),
+ ("-272322.48219624218537039495168", "-0.00009168252278596474115", Less),
+ // 011 110 different scale
+ ("3.1530040332824324172729548800", "0.05636139104712652784", Greater),
+ ("-3.1530040332824324172729548800", "0.05636139104712652784", Less),
+ ("3.1530040332824324172729548800", "-0.05636139104712652784", Greater),
+ ("-3.1530040332824324172729548800", "-0.05636139104712652784", Less),
+ // 011 001 same scale
+ (
+ "272322.48219624218537039495168",
+ "78956.15667671475190631497728",
+ Greater,
+ ),
+ ("-272322.48219624218537039495168", "78956.15667671475190631497728", Less),
+ (
+ "272322.48219624218537039495168",
+ "-78956.15667671475190631497728",
+ Greater,
+ ),
+ (
+ "-272322.48219624218537039495168",
+ "-78956.15667671475190631497728",
+ Less,
+ ),
+ // 011 001 different scale
+ (
+ "247159638929.90774677497446400",
+ "18573048.37697991870462820352",
+ Greater,
+ ),
+ ("-247159638929.90774677497446400", "18573048.37697991870462820352", Less),
+ (
+ "247159638929.90774677497446400",
+ "-18573048.37697991870462820352",
+ Greater,
+ ),
+ (
+ "-247159638929.90774677497446400",
+ "-18573048.37697991870462820352",
+ Less,
+ ),
+ // 011 101 same scale
+ ("272322.48219624218537039495168", "311953.28803357654172947915942", Less),
+ (
+ "-272322.48219624218537039495168",
+ "311953.28803357654172947915942",
+ Less,
+ ),
+ (
+ "272322.48219624218537039495168",
+ "-311953.28803357654172947915942",
+ Greater,
+ ),
+ (
+ "-272322.48219624218537039495168",
+ "-311953.28803357654172947915942",
+ Greater,
+ ),
+ // 011 101 different scale
+ ("2922696937234119470.0273745920", "22441101906503785827606686629", Less),
+ ("-2922696937234119470.0273745920", "22441101906503785827606686629", Less),
+ (
+ "2922696937234119470.0273745920",
+ "-22441101906503785827606686629",
+ Greater,
+ ),
+ (
+ "-2922696937234119470.0273745920",
+ "-22441101906503785827606686629",
+ Greater,
+ ),
+ // 011 011 same scale
+ ("272322.48219624218537039495168", "348316.28306497394164006649856", Less),
+ (
+ "-272322.48219624218537039495168",
+ "348316.28306497394164006649856",
+ Less,
+ ),
+ (
+ "272322.48219624218537039495168",
+ "-348316.28306497394164006649856",
+ Greater,
+ ),
+ (
+ "-272322.48219624218537039495168",
+ "-348316.28306497394164006649856",
+ Greater,
+ ),
+ // 011 011 different scale
+ ("178190346.76624086261395619840", "62208030746.22038852927225856", Less),
+ ("-178190346.76624086261395619840", "62208030746.22038852927225856", Less),
+ (
+ "178190346.76624086261395619840",
+ "-62208030746.22038852927225856",
+ Greater,
+ ),
+ (
+ "-178190346.76624086261395619840",
+ "-62208030746.22038852927225856",
+ Greater,
+ ),
+ // 011 111 same scale
+ (
+ "272322.48219624218537039495168",
+ "41534.52021391898039335355927",
+ Greater,
+ ),
+ ("-272322.48219624218537039495168", "41534.52021391898039335355927", Less),
+ (
+ "272322.48219624218537039495168",
+ "-41534.52021391898039335355927",
+ Greater,
+ ),
+ (
+ "-272322.48219624218537039495168",
+ "-41534.52021391898039335355927",
+ Less,
+ ),
+ // 011 111 different scale
+ ("11.959910518519677083499626496", "2844684364802261541879551.2259", Less),
+ (
+ "-11.959910518519677083499626496",
+ "2844684364802261541879551.2259",
+ Less,
+ ),
+ (
+ "11.959910518519677083499626496",
+ "-2844684364802261541879551.2259",
+ Greater,
+ ),
+ (
+ "-11.959910518519677083499626496",
+ "-2844684364802261541879551.2259",
+ Greater,
+ ),
+ // 111 equality
+ (
+ "3836286746260530032892706.6174",
+ "3836286746260530032892706.6174",
+ Equal,
+ ),
+ // 111 000 same scale
+ ("3836286746260530032892706.6174", "0.0000", Greater),
+ ("-3836286746260530032892706.6174", "0.0000", Less),
+ ("3836286746260530032892706.6174", "-0.0000", Greater),
+ ("-3836286746260530032892706.6174", "-0.0000", Less),
+ // 111 000 different scale
+ ("4401861854803552.033657814547", "0.0000000", Greater),
+ ("-4401861854803552.033657814547", "0.0000000", Less),
+ ("4401861854803552.033657814547", "-0.0000000", Greater),
+ ("-4401861854803552.033657814547", "-0.0000000", Less),
+ // 111 100 same scale
+ ("3836286746260530032892706.6174", "68758.6561", Greater),
+ ("-3836286746260530032892706.6174", "68758.6561", Less),
+ ("3836286746260530032892706.6174", "-68758.6561", Greater),
+ ("-3836286746260530032892706.6174", "-68758.6561", Less),
+ // 111 100 different scale
+ (
+ "18794337354296131695536777.153",
+ "0.000000000000000001563875977",
+ Greater,
+ ),
+ ("-18794337354296131695536777.153", "0.000000000000000001563875977", Less),
+ (
+ "18794337354296131695536777.153",
+ "-0.000000000000000001563875977",
+ Greater,
+ ),
+ (
+ "-18794337354296131695536777.153",
+ "-0.000000000000000001563875977",
+ Less,
+ ),
+ // 111 010 same scale
+ ("3836286746260530032892706.6174", "439097665563236.7616", Greater),
+ ("-3836286746260530032892706.6174", "439097665563236.7616", Less),
+ ("3836286746260530032892706.6174", "-439097665563236.7616", Greater),
+ ("-3836286746260530032892706.6174", "-439097665563236.7616", Less),
+ // 111 010 different scale
+ ("219364497389.57405761662363679", "0.6569644274462228480", Greater),
+ ("-219364497389.57405761662363679", "0.6569644274462228480", Less),
+ ("219364497389.57405761662363679", "-0.6569644274462228480", Greater),
+ ("-219364497389.57405761662363679", "-0.6569644274462228480", Less),
+ // 111 110 same scale
+ ("3836286746260530032892706.6174", "100013274294974.8269", Greater),
+ ("-3836286746260530032892706.6174", "100013274294974.8269", Less),
+ ("3836286746260530032892706.6174", "-100013274294974.8269", Greater),
+ ("-3836286746260530032892706.6174", "-100013274294974.8269", Less),
+ // 111 110 different scale
+ ("76072704083682.85472479207171", "50.52437989651117182", Greater),
+ ("-76072704083682.85472479207171", "50.52437989651117182", Less),
+ ("76072704083682.85472479207171", "-50.52437989651117182", Greater),
+ ("-76072704083682.85472479207171", "-50.52437989651117182", Less),
+ // 111 001 same scale
+ (
+ "3836286746260530032892706.6174",
+ "2766133872545894272402142.0032",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "2766133872545894272402142.0032",
+ Less,
+ ),
+ (
+ "3836286746260530032892706.6174",
+ "-2766133872545894272402142.0032",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "-2766133872545894272402142.0032",
+ Less,
+ ),
+ // 111 001 different scale
+ (
+ "38199979438250010.80610984395",
+ "31104752430710.408848162684928",
+ Greater,
+ ),
+ ("-38199979438250010.80610984395", "31104752430710.408848162684928", Less),
+ (
+ "38199979438250010.80610984395",
+ "-31104752430710.408848162684928",
+ Greater,
+ ),
+ (
+ "-38199979438250010.80610984395",
+ "-31104752430710.408848162684928",
+ Less,
+ ),
+ // 111 101 same scale
+ (
+ "3836286746260530032892706.6174",
+ "441847458119168110406908.6115",
+ Greater,
+ ),
+ ("-3836286746260530032892706.6174", "441847458119168110406908.6115", Less),
+ (
+ "3836286746260530032892706.6174",
+ "-441847458119168110406908.6115",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "-441847458119168110406908.6115",
+ Less,
+ ),
+ // 111 101 different scale
+ ("255945012905633524.15746865235", "1005021647855597114428453997.8", Less),
+ (
+ "-255945012905633524.15746865235",
+ "1005021647855597114428453997.8",
+ Less,
+ ),
+ (
+ "255945012905633524.15746865235",
+ "-1005021647855597114428453997.8",
+ Greater,
+ ),
+ (
+ "-255945012905633524.15746865235",
+ "-1005021647855597114428453997.8",
+ Greater,
+ ),
+ // 111 011 same scale
+ (
+ "3836286746260530032892706.6174",
+ "1111481055212557787730018.3040",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "1111481055212557787730018.3040",
+ Less,
+ ),
+ (
+ "3836286746260530032892706.6174",
+ "-1111481055212557787730018.3040",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "-1111481055212557787730018.3040",
+ Less,
+ ),
+ // 111 011 different scale
+ (
+ "79710135995301690627798250.27",
+ "4613684285077.479267304996864",
+ Greater,
+ ),
+ ("-79710135995301690627798250.27", "4613684285077.479267304996864", Less),
+ (
+ "79710135995301690627798250.27",
+ "-4613684285077.479267304996864",
+ Greater,
+ ),
+ ("-79710135995301690627798250.27", "-4613684285077.479267304996864", Less),
+ // 111 111 same scale
+ (
+ "3836286746260530032892706.6174",
+ "1881105048659612897896770.8539",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "1881105048659612897896770.8539",
+ Less,
+ ),
+ (
+ "3836286746260530032892706.6174",
+ "-1881105048659612897896770.8539",
+ Greater,
+ ),
+ (
+ "-3836286746260530032892706.6174",
+ "-1881105048659612897896770.8539",
+ Less,
+ ),
+ // 111 111 different scale
+ (
+ "3879592276836332218003.2886500",
+ "35612499407667292.686490959658",
+ Greater,
+ ),
+ (
+ "-3879592276836332218003.2886500",
+ "35612499407667292.686490959658",
+ Less,
+ ),
+ (
+ "3879592276836332218003.2886500",
+ "-35612499407667292.686490959658",
+ Greater,
+ ),
+ (
+ "-3879592276836332218003.2886500",
+ "-35612499407667292.686490959658",
+ Less,
+ ),
+ ];
+ for &(a, b, c) in tests {
+ cmp(a, b, c);
+ }
+}
+
+#[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());
+}
+
+#[test]
+fn it_can_round_using_basic_midpoint_rules() {
+ let tests = &[
+ ("3.5", RoundingStrategy::MidpointAwayFromZero, "4"),
+ ("2.8", RoundingStrategy::MidpointAwayFromZero, "3"),
+ ("2.5", RoundingStrategy::MidpointAwayFromZero, "3"),
+ ("2.1", RoundingStrategy::MidpointAwayFromZero, "2"),
+ ("-2.1", RoundingStrategy::MidpointAwayFromZero, "-2"),
+ ("-2.5", RoundingStrategy::MidpointAwayFromZero, "-3"),
+ ("-2.8", RoundingStrategy::MidpointAwayFromZero, "-3"),
+ ("-3.5", RoundingStrategy::MidpointAwayFromZero, "-4"),
+ ("3.5", RoundingStrategy::MidpointNearestEven, "4"),
+ ("2.8", RoundingStrategy::MidpointNearestEven, "3"),
+ ("2.5", RoundingStrategy::MidpointNearestEven, "2"),
+ ("2.1", RoundingStrategy::MidpointNearestEven, "2"),
+ ("-2.1", RoundingStrategy::MidpointNearestEven, "-2"),
+ ("-2.5", RoundingStrategy::MidpointNearestEven, "-2"),
+ ("-2.8", RoundingStrategy::MidpointNearestEven, "-3"),
+ ("-3.5", RoundingStrategy::MidpointNearestEven, "-4"),
+ ("3.5", RoundingStrategy::MidpointTowardZero, "3"),
+ ("2.8", RoundingStrategy::MidpointTowardZero, "3"),
+ ("2.5", RoundingStrategy::MidpointTowardZero, "2"),
+ ("2.1", RoundingStrategy::MidpointTowardZero, "2"),
+ ("-2.1", RoundingStrategy::MidpointTowardZero, "-2"),
+ ("-2.5", RoundingStrategy::MidpointTowardZero, "-2"),
+ ("-2.8", RoundingStrategy::MidpointTowardZero, "-3"),
+ ("-3.5", RoundingStrategy::MidpointTowardZero, "-3"),
+ ("2.8", RoundingStrategy::ToNegativeInfinity, "2"),
+ ("2.5", RoundingStrategy::ToNegativeInfinity, "2"),
+ ("2.1", RoundingStrategy::ToNegativeInfinity, "2"),
+ ("-2.1", RoundingStrategy::ToNegativeInfinity, "-3"),
+ ("-2.5", RoundingStrategy::ToNegativeInfinity, "-3"),
+ ("-2.8", RoundingStrategy::ToNegativeInfinity, "-3"),
+ ("2.8", RoundingStrategy::ToPositiveInfinity, "3"),
+ ("2.5", RoundingStrategy::ToPositiveInfinity, "3"),
+ ("2.1", RoundingStrategy::ToPositiveInfinity, "3"),
+ ("-2.1", RoundingStrategy::ToPositiveInfinity, "-2"),
+ ("-2.5", RoundingStrategy::ToPositiveInfinity, "-2"),
+ ("-2.8", RoundingStrategy::ToPositiveInfinity, "-2"),
+ ("2.8", RoundingStrategy::ToZero, "2"),
+ ("2.5", RoundingStrategy::ToZero, "2"),
+ ("2.1", RoundingStrategy::ToZero, "2"),
+ ("-2.1", RoundingStrategy::ToZero, "-2"),
+ ("-2.5", RoundingStrategy::ToZero, "-2"),
+ ("-2.8", RoundingStrategy::ToZero, "-2"),
+ ("2.8", RoundingStrategy::AwayFromZero, "3"),
+ ("2.5", RoundingStrategy::AwayFromZero, "3"),
+ ("2.1", RoundingStrategy::AwayFromZero, "3"),
+ ("-2.1", RoundingStrategy::AwayFromZero, "-3"),
+ ("-2.5", RoundingStrategy::AwayFromZero, "-3"),
+ ("-2.8", RoundingStrategy::AwayFromZero, "-3"),
+ ];
+
+ 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);
+ }
+}
+
+#[test]
+fn it_can_round_using_bankers_rounding() {
+ let tests = &[
+ ("6.12345", 2, "6.12"),
+ ("6.126", 2, "6.13"),
+ ("-6.126", 2, "-6.13"),
+ ("6.5", 0, "6"),
+ ("7.5", 0, "8"),
+ ("1.2250", 2, "1.22"),
+ ("1.2252", 2, "1.23"),
+ ("1.2249", 2, "1.22"),
+ ("6.1", 2, "6.1"),
+ ("0.0000", 2, "0.00"),
+ ("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::BankersRounding);
+ assert_eq!(expected, b.to_string(), "BankersRounding");
+
+ // 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");
+ }
+}
+
+#[test]
+fn it_can_round_up() {
+ let tests = &[
+ ("2.8", 0, "3"),
+ ("2.5", 0, "3"),
+ ("2.1", 0, "3"),
+ ("-2.1", 0, "-3"),
+ ("-2.5", 0, "-3"),
+ ("-2.8", 0, "-3"),
+ ("0.320", 1, "0.4"),
+ ("-0.320", 1, "-0.4"),
+ ("0.300", 1, "0.3"),
+ ("-0.300", 1, "-0.3"),
+ ];
+
+ 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);
+ if let 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);
+ if let 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
+ );
+ }
+ }
+}
+
+#[test]
+fn it_can_trunc() {
+ let tests = &[("1.00000000000000000000", "1"), ("1.000000000000000000000001", "1")];
+
+ 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());
+ }
+}
+
+#[test]
+fn it_can_fract() {
+ let tests = &[
+ ("1.00000000000000000000", "0.00000000000000000000"),
+ ("1.000000000000000000000001", "0.000000000000000000000001"),
+ ];
+
+ 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());
+ }
+}
+
+#[test]
+fn it_can_normalize() {
+ let tests = &[
+ ("1.00000000000000000000", "1"),
+ ("1.10000000000000000000000", "1.1"),
+ ("1.00010000000000000000000", "1.0001"),
+ ("1", "1"),
+ ("1.1", "1.1"),
+ ("1.0001", "1.0001"),
+ ("-0", "0"),
+ ("-0.0", "0"),
+ ("-0.010", "-0.01"),
+ ("0.0", "0"),
+ ];
+
+ 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_return_the_max_value() {
+ assert_eq!("79228162514264337593543950335", Decimal::MAX.to_string());
+}
+
+#[test]
+fn it_can_return_the_min_value() {
+ assert_eq!("-79228162514264337593543950335", Decimal::MIN.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();
+
+ assert_eq!(d, di8);
+ assert_eq!(di8, di32);
+ assert_eq!(di32, disize);
+ assert_eq!(disize, di64);
+ assert_eq!(di64, du8);
+ assert_eq!(du8, du32);
+ assert_eq!(du32, dusize);
+ assert_eq!(dusize, du64);
+}
+
+#[test]
+fn it_converts_to_f64() {
+ let tests = &[
+ ("5", Some(5f64)),
+ ("-5", Some(-5f64)),
+ ("0.1", Some(0.1f64)),
+ ("0.0", Some(0f64)),
+ ("-0.0", Some(0f64)),
+ ("0.0000000000025", Some(0.25e-11f64)),
+ ("1000000.0000000000025", Some(1e6f64)),
+ ("0.000000000000000000000000025", Some(0.25e-25_f64)),
+ (
+ "2.1234567890123456789012345678",
+ Some(2.1234567890123456789012345678_f64),
+ ),
+ ("21234567890123456789012345678", Some(21234567890123458000000000000_f64)),
+ (
+ "-21234567890123456789012345678",
+ Some(-21234567890123458000000000000_f64),
+ ),
+ ("1.59283191", Some(1.59283191_f64)),
+ ("2.2238", Some(2.2238_f64)),
+ ("2.2238123", Some(2.2238123_f64)),
+ ("22238", Some(22238_f64)),
+ ];
+ for &(value, expected) in tests {
+ let value = Decimal::from_str(value).unwrap().to_f64();
+ assert_eq!(expected, value);
+ }
+}
+
+#[test]
+fn it_converts_to_f64_try() {
+ let tests = &[
+ ("5", Some(5f64)),
+ ("-5", Some(-5f64)),
+ ("0.1", Some(0.1f64)),
+ ("0.0", Some(0f64)),
+ ("-0.0", Some(0f64)),
+ ("0.0000000000025", Some(0.25e-11f64)),
+ ("1000000.0000000000025", Some(1e6f64)),
+ ("0.000000000000000000000000025", Some(0.25e-25_f64)),
+ (
+ "2.1234567890123456789012345678",
+ Some(2.1234567890123456789012345678_f64),
+ ),
+ ("21234567890123456789012345678", Some(21234567890123458000000000000_f64)),
+ (
+ "-21234567890123456789012345678",
+ Some(-21234567890123458000000000000_f64),
+ ),
+ ("1.59283191", Some(1.59283191_f64)),
+ ];
+ for &(value, expected) in tests {
+ let value = Decimal::from_str(value).unwrap().try_into().ok();
+ assert_eq!(expected, value);
+ }
+}
+
+#[test]
+fn it_converts_to_i64() {
+ let tests = [
+ ("5", Some(5_i64)),
+ ("-5", Some(-5_i64)),
+ ("5.12345", Some(5_i64)),
+ ("-5.12345", Some(-5_i64)),
+ ("-9223372036854775808", Some(-9223372036854775808_i64)),
+ ("-9223372036854775808", Some(i64::MIN)),
+ ("9223372036854775807", Some(9223372036854775807_i64)),
+ ("9223372036854775807", Some(i64::MAX)),
+ ("-9223372036854775809", None), // i64::MIN - 1
+ ("9223372036854775808", None), // i64::MAX + 1
+ // Clear overflows in hi bit
+ ("-92233720368547758089", None),
+ ("92233720368547758088", None),
+ ];
+ for (input, expected) in tests {
+ let input = Decimal::from_str(input).unwrap();
+ let actual = input.to_i64();
+ assert_eq!(expected, actual, "Input: {}", input);
+ }
+}
+
+#[test]
+fn it_converts_to_u64() {
+ assert_eq!(5u64, Decimal::from_str("5").unwrap().to_u64().unwrap());
+ assert_eq!(None, Decimal::from_str("-5").unwrap().to_u64());
+ assert_eq!(5u64, Decimal::from_str("5.12345").unwrap().to_u64().unwrap());
+ assert_eq!(
+ 0xFFFF_FFFF_FFFF_FFFF,
+ Decimal::from_str("18446744073709551615").unwrap().to_u64().unwrap()
+ );
+ assert_eq!(None, Decimal::from_str("18446744073709551616").unwrap().to_u64());
+}
+
+#[test]
+fn it_converts_to_i128() {
+ let tests = &[
+ ("5", Some(5i128)),
+ ("-5", Some(-5i128)),
+ ("5.12345", Some(5i128)),
+ ("-5.12345", Some(-5i128)),
+ ("9223372036854775807", Some(0x7FFF_FFFF_FFFF_FFFF)),
+ ("92233720368547758089", Some(92233720368547758089i128)),
+ ];
+ for (dec, expected) in tests {
+ assert_eq!(Decimal::from_str(dec).unwrap().to_i128(), *expected);
+ }
+
+ assert_eq!(
+ 79_228_162_514_264_337_593_543_950_335_i128,
+ Decimal::MAX.to_i128().unwrap()
+ );
+}
+
+#[test]
+fn it_converts_to_u128() {
+ let tests = &[
+ ("5", Some(5u128)),
+ ("-5", None),
+ ("5.12345", Some(5u128)),
+ ("-5.12345", None),
+ ("18446744073709551615", Some(0xFFFF_FFFF_FFFF_FFFF)),
+ ("18446744073709551616", Some(18446744073709551616u128)),
+ ];
+ for (dec, expected) in tests {
+ assert_eq!(Decimal::from_str(dec).unwrap().to_u128(), *expected);
+ }
+ assert_eq!(
+ 79_228_162_514_264_337_593_543_950_335_u128,
+ Decimal::MAX.to_u128().unwrap()
+ );
+}
+
+#[test]
+fn it_converts_from_i128() {
+ let tests: &[(i128, Option<&str>)] = &[
+ (5, Some("5")),
+ (-5, Some("-5")),
+ (0x7FFF_FFFF_FFFF_FFFF, Some("9223372036854775807")),
+ (92233720368547758089, Some("92233720368547758089")),
+ (0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF, Some("79228162514264337593543950335")),
+ (0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, None),
+ ];
+ for (value, expected) in tests {
+ if let Some(expected_value) = expected {
+ let decimal = Decimal::from_str(expected_value).unwrap();
+ assert_eq!(num_traits::FromPrimitive::from_i128(*value), Some(decimal));
+ }
+ }
+}
+
+#[test]
+fn it_converts_from_u128() {
+ let tests: &[(u128, Option<&str>)] = &[
+ (5, Some("5")),
+ (0xFFFF_FFFF_FFFF_FFFF, Some("18446744073709551615")),
+ (0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF, Some("79228162514264337593543950335")),
+ (0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, None),
+ ];
+ for (value, expected) in tests {
+ if let Some(expected_value) = expected {
+ let decimal = Decimal::from_str(expected_value).unwrap();
+ assert_eq!(num_traits::FromPrimitive::from_u128(*value), Some(decimal));
+ }
+ }
+}
+
+#[test]
+fn it_converts_from_str() {
+ assert_eq!(Decimal::try_from("1").unwrap(), Decimal::ONE);
+ assert_eq!(Decimal::try_from("10").unwrap(), Decimal::TEN);
+}
+
+#[test]
+fn it_converts_from_f32() {
+ use num_traits::FromPrimitive;
+
+ let tests = [
+ (0.1_f32, "0.1"),
+ (1_f32, "1"),
+ (0_f32, "0"),
+ (0.12345_f32, "0.12345"),
+ (0.1234567800123456789012345678_f32, "0.12345678"),
+ (0.12345678901234567890123456789_f32, "0.12345679"),
+ (0.00000000000000000000000000001_f32, "0"),
+ (5.1_f32, "5.1"),
+ ];
+
+ for &(input, expected) in &tests {
+ assert_eq!(
+ expected,
+ Decimal::from_f32(input).unwrap().to_string(),
+ "from_f32({})",
+ input
+ );
+ assert_eq!(
+ expected,
+ Decimal::try_from(input).unwrap().to_string(),
+ "try_from({})",
+ input
+ );
+ }
+}
+
+#[test]
+fn it_converts_from_f32_limits() {
+ use num_traits::FromPrimitive;
+
+ assert!(Decimal::from_f32(f32::NAN).is_none(), "from_f32(f32::NAN)");
+ assert!(Decimal::from_f32(f32::INFINITY).is_none(), "from_f32(f32::INFINITY)");
+ assert!(Decimal::try_from(f32::NAN).is_err(), "try_from(f32::NAN)");
+ assert!(Decimal::try_from(f32::INFINITY).is_err(), "try_from(f32::INFINITY)");
+
+ // These overflow
+ assert!(Decimal::from_f32(f32::MAX).is_none(), "from_f32(f32::MAX)");
+ assert!(Decimal::from_f32(f32::MIN).is_none(), "from_f32(f32::MIN)");
+ assert!(Decimal::try_from(f32::MAX).is_err(), "try_from(f32::MAX)");
+ assert!(Decimal::try_from(f32::MIN).is_err(), "try_from(f32::MIN)");
+}
+
+#[test]
+fn it_converts_from_f32_retaining_bits() {
+ let tests = [
+ (0.1_f32, "0.100000001490116119384765625"),
+ (2_f32, "2"),
+ (4.000_f32, "4"),
+ (5.1_f32, "5.099999904632568359375"),
+ ];
+
+ for &(input, expected) in &tests {
+ assert_eq!(
+ expected,
+ Decimal::from_f32_retain(input).unwrap().to_string(),
+ "from_f32_retain({})",
+ input
+ );
+ }
+}
+
+#[test]
+fn it_converts_from_f64() {
+ use num_traits::FromPrimitive;
+
+ let tests = [
+ (0.1_f64, "0.1"),
+ (1_f64, "1"),
+ (0_f64, "0"),
+ (0.12345_f64, "0.12345"),
+ (0.1234567890123456089012345678_f64, "0.1234567890123456"),
+ (0.12345678901234567890123456789_f64, "0.1234567890123457"),
+ (0.00000000000000000000000000001_f64, "0"),
+ (0.6927_f64, "0.6927"),
+ (0.00006927_f64, "0.00006927"),
+ (0.000000006927_f64, "0.000000006927"),
+ (5.1_f64, "5.1"),
+ ];
+
+ for &(input, expected) in &tests {
+ assert_eq!(
+ expected,
+ Decimal::from_f64(input).unwrap().to_string(),
+ "from_f64({})",
+ input
+ );
+ assert_eq!(
+ expected,
+ Decimal::try_from(input).unwrap().to_string(),
+ "try_from({})",
+ input
+ );
+ }
+}
+
+#[test]
+fn it_converts_from_f64_limits() {
+ use num_traits::FromPrimitive;
+
+ assert!(Decimal::from_f64(f64::NAN).is_none(), "from_f64(f64::NAN)");
+ assert!(Decimal::from_f64(f64::INFINITY).is_none(), "from_f64(f64::INFINITY)");
+ assert!(Decimal::try_from(f64::NAN).is_err(), "try_from(f64::NAN)");
+ assert!(Decimal::try_from(f64::INFINITY).is_err(), "try_from(f64::INFINITY)");
+
+ // These overflow
+ assert!(Decimal::from_f64(f64::MAX).is_none(), "from_f64(f64::MAX)");
+ assert!(Decimal::from_f64(f64::MIN).is_none(), "from_f64(f64::MIN)");
+ assert!(Decimal::try_from(f64::MAX).is_err(), "try_from(f64::MIN)");
+ assert!(Decimal::try_from(f64::MIN).is_err(), "try_from(f64::MAX)");
+}
+
+#[test]
+fn it_converts_from_f64_retaining_bits() {
+ let tests = [
+ (0.1_f64, "0.1000000000000000055511151231"),
+ (2_f64, "2"),
+ (4.000_f64, "4"),
+ (5.1_f64, "5.0999999999999996447286321175"),
+ ];
+
+ for &(input, expected) in &tests {
+ assert_eq!(
+ expected,
+ Decimal::from_f64_retain(input).unwrap().to_string(),
+ "from_f64_retain({})",
+ input
+ );
+ }
+}
+
+#[test]
+fn it_converts_to_integers() {
+ assert_eq!(i64::try_from(Decimal::ONE), Ok(1));
+ assert_eq!(i64::try_from(Decimal::MAX), Err(Error::ConversionTo("i64".to_string())));
+ assert_eq!(u128::try_from(Decimal::ONE_HUNDRED), Ok(100));
+}
+
+#[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());
+}
+
+#[test]
+fn it_can_parse_highly_significant_numbers() {
+ let tests = &[
+ ("11.111111111111111111111111111", "11.111111111111111111111111111"),
+ ("11.11111111111111111111111111111", "11.111111111111111111111111111"),
+ ("11.1111111111111111111111111115", "11.111111111111111111111111112"),
+ ("115.111111111111111111111111111", "115.11111111111111111111111111"),
+ ("1115.11111111111111111111111111", "1115.1111111111111111111111111"),
+ ("11.1111111111111111111111111195", "11.111111111111111111111111120"),
+ ("99.9999999999999999999999999995", "100.00000000000000000000000000"),
+ ("-11.1111111111111111111111111195", "-11.111111111111111111111111120"),
+ ("-99.9999999999999999999999999995", "-100.00000000000000000000000000"),
+ ("3.1415926535897932384626433832", "3.1415926535897932384626433832"),
+ (
+ "8808257419827262908.5944405087133154018",
+ "8808257419827262908.594440509",
+ ),
+ (
+ "8097370036018690744.2590371109596744091",
+ "8097370036018690744.259037111",
+ ),
+ (
+ "8097370036018690744.2590371149596744091",
+ "8097370036018690744.259037115",
+ ),
+ (
+ "8097370036018690744.2590371159596744091",
+ "8097370036018690744.259037116",
+ ),
+ ("1.234567890123456789012345678949999", "1.2345678901234567890123456789"),
+ (".00000000000000000000000000001", "0.0000000000000000000000000000"),
+ (".10000000000000000000000000000", "0.1000000000000000000000000000"),
+ ];
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_str(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_parse_exact_highly_significant_numbers() {
+ use rust_decimal::Error;
+
+ let tests = &[
+ (
+ "11.111111111111111111111111111",
+ Ok("11.111111111111111111111111111".to_string()),
+ ),
+ ("11.11111111111111111111111111111", Err(Error::Underflow)),
+ ("11.1111111111111111111111111115", Err(Error::Underflow)),
+ ("115.111111111111111111111111111", Err(Error::Underflow)),
+ ("1115.11111111111111111111111111", Err(Error::Underflow)),
+ ("11.1111111111111111111111111195", Err(Error::Underflow)),
+ ("99.9999999999999999999999999995", Err(Error::Underflow)),
+ ("-11.1111111111111111111111111195", Err(Error::Underflow)),
+ ("-99.9999999999999999999999999995", Err(Error::Underflow)),
+ (
+ "3.1415926535897932384626433832",
+ Ok("3.1415926535897932384626433832".to_string()),
+ ),
+ ("8808257419827262908.5944405087133154018", Err(Error::Underflow)),
+ ("8097370036018690744.2590371109596744091", Err(Error::Underflow)),
+ ("8097370036018690744.2590371149596744091", Err(Error::Underflow)),
+ ("8097370036018690744.2590371159596744091", Err(Error::Underflow)),
+ ("1.234567890123456789012345678949999", Err(Error::Underflow)),
+ (".00000000000000000000000000001", Err(Error::Underflow)),
+ (".10000000000000000000000000000", Err(Error::Underflow)),
+ ];
+ for &(value, ref expected) in tests.into_iter() {
+ let actual = Decimal::from_str_exact(value).map(|d| d.to_string());
+ assert_eq!(*expected, actual);
+ }
+}
+
+#[test]
+fn it_can_parse_alternative_formats() {
+ let tests = &[
+ ("1_000", "1000"),
+ ("1_000_000", "1000000"),
+ ("10_000_000", "10000000"),
+ ("100_000", "100000"),
+ // At the moment, we'll accept this
+ ("1_____________0", "10"),
+ ];
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_str(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_parse_fractional_numbers_with_underscore_separators() {
+ let a = Decimal::from_str("0.1_23_456").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 6);
+ assert_eq!("0.123456", a.to_string());
+}
+
+#[test]
+fn it_can_parse_numbers_with_underscore_separators_before_decimal_point() {
+ let a = Decimal::from_str("1_234.56").unwrap();
+ assert_eq!(a.is_sign_negative(), false);
+ assert_eq!(a.scale(), 2);
+ assert_eq!("1234.56", a.to_string());
+}
+
+#[test]
+fn it_can_parse_numbers_and_round_correctly_with_underscore_separators_before_decimal_point() {
+ let tests = &[
+ (
+ "8_097_370_036_018_690_744.2590371159596744091",
+ "8097370036018690744.259037116",
+ ),
+ (
+ "8097370036018690744.259_037_115_959_674_409_1",
+ "8097370036018690744.259037116",
+ ),
+ (
+ "8_097_370_036_018_690_744.259_037_115_959_674_409_1",
+ "8097370036018690744.259037116",
+ ),
+ ];
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_str(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_can_reject_invalid_formats() {
+ let tests = &["_1", "1.0.0", "10_00.0_00.0"];
+ for &value in tests {
+ assert!(
+ Decimal::from_str(value).is_err(),
+ "This succeeded unexpectedly: {}",
+ value
+ );
+ }
+}
+
+#[test]
+fn it_can_reject_large_numbers_with_panic() {
+ let tests = &[
+ // The maximum number supported is 79,228,162,514,264,337,593,543,950,335
+ "79228162514264337593543950336",
+ "79228162514264337593543950337",
+ "79228162514264337593543950338",
+ "79228162514264337593543950339",
+ "79228162514264337593543950340",
+ ];
+ for &value in tests {
+ if let Ok(out) = Decimal::from_str(value) {
+ panic!("Unexpectedly parsed {} into {}", value, out)
+ }
+ }
+}
+
+#[test]
+fn it_can_parse_individual_parts() {
+ let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28);
+ assert_eq!(pi.to_string(), "3.1415926535897932384626433832");
+}
+
+#[test]
+fn it_can_parse_scientific_notation() {
+ let tests = &[
+ ("9.7e-7", "0.00000097"),
+ ("9e-7", "0.0000009"),
+ ("1.2e10", "12000000000"),
+ ("1.2e+10", "12000000000"),
+ ("12e10", "120000000000"),
+ ("9.7E-7", "0.00000097"),
+ ("1.2345E-24", "0.0000000000000000000000012345"),
+ ("12345E-28", "0.0000000000000000000000012345"),
+ ("1.2345E0", "1.2345"),
+ ("1E28", "10000000000000000000000000000"),
+ ];
+
+ for &(value, expected) in tests {
+ assert_eq!(expected, Decimal::from_scientific(value).unwrap().to_string());
+ }
+}
+
+#[test]
+fn it_errors_parsing_large_scientific_notation() {
+ let result = Decimal::from_scientific("1.2345E-28");
+ assert!(result.is_err());
+ assert_eq!(
+ result.err(),
+ Some(Error::ScaleExceedsMaximumPrecision(32)) // 4 + 28
+ );
+
+ let result = Decimal::from_scientific("12345E29");
+ assert!(result.is_err());
+ assert_eq!(result.err(), Some(Error::ScaleExceedsMaximumPrecision(29)));
+
+ let result = Decimal::from_scientific("12345E28");
+ assert!(result.is_err());
+ assert_eq!(result.err(), Some(Error::ExceedsMaximumPossibleValue));
+}
+
+#[test]
+fn it_can_parse_different_radix() {
+ let tests = &[
+ // Input, Radix, Success, to_string()
+ ("123", 10, true, "123"),
+ ("123", 8, true, "83"),
+ ("123", 16, true, "291"),
+ ("abc", 10, false, ""),
+ ("abc", 16, true, "2748"),
+ ("78", 10, true, "78"),
+ ("78", 8, false, ""),
+ ("101", 2, true, "5"),
+ // Parse base 2
+ ("1111_1111_1111_1111_1111_1111_1111_1111", 2, true, "4294967295"),
+ // Max supported value
+ (
+ "1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_\
+ 1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111",
+ 2,
+ true,
+ &Decimal::MAX.to_string(),
+ ),
+ // We limit to 28 dp
+ (
+ "843.6500000000000000000000000000",
+ 10,
+ true,
+ "843.6500000000000000000000000",
+ ),
+ ];
+
+ for &(input, radix, success, expected) in tests {
+ let result = Decimal::from_str_radix(input, radix);
+ assert_eq!(
+ success,
+ result.is_ok(),
+ "Failed to parse: {} radix {}: {:?}",
+ input,
+ radix,
+ result.err()
+ );
+ if result.is_ok() {
+ assert_eq!(
+ expected,
+ result.unwrap().to_string(),
+ "Original input: {} radix {}",
+ input,
+ radix
+ );
+ }
+ }
+}
+
+#[test]
+fn it_can_calculate_signum() {
+ let tests = &[("123", 1), ("-123", -1), ("0", 0)];
+
+ for &(input, expected) in tests {
+ let input = Decimal::from_str(input).unwrap();
+ assert_eq!(expected, input.signum().to_i32().unwrap(), "Input: {}", input);
+ }
+}
+
+#[test]
+fn it_can_calculate_abs_sub() {
+ let tests = &[
+ ("123", "124", 0),
+ ("123", "123", 0),
+ ("123", "122", 123),
+ ("-123", "-124", 123),
+ ("-123", "-123", 0),
+ ("-123", "-122", 0),
+ ];
+
+ for &(input1, input2, expected) in tests {
+ let input1 = Decimal::from_str(input1).unwrap();
+ let input2 = Decimal::from_str(input2).unwrap();
+ assert_eq!(
+ expected,
+ input1.abs_sub(&input2).to_i32().unwrap(),
+ "Input: {} {}",
+ input1,
+ input2
+ );
+ }
+}
+
+#[test]
+#[should_panic(expected = "Scale exceeds the maximum precision allowed: 29 > 28")]
+fn it_panics_when_scale_too_large() {
+ let _ = Decimal::new(1, 29);
+}
+
+#[test]
+fn test_zero_eq_negative_zero() {
+ let zero: Decimal = 0.into();
+
+ assert_eq!(zero, zero);
+ assert_eq!(-zero, zero);
+ assert_eq!(zero, -zero);
+}
+
+#[test]
+fn declarative_dec_product() {
+ let vs = (1..5).map(|i| i.into()).collect::<Vec<Decimal>>();
+ let product: Decimal = vs.into_iter().product();
+ assert_eq!(product, Decimal::from(24))
+}
+
+#[test]
+fn declarative_ref_dec_product() {
+ let vs = (1..5).map(|i| i.into()).collect::<Vec<Decimal>>();
+ let product: Decimal = vs.iter().product();
+ assert_eq!(product, Decimal::from(24))
+}
+
+#[test]
+fn declarative_dec_sum() {
+ let vs = (0..10).map(|i| i.into()).collect::<Vec<Decimal>>();
+ let sum: Decimal = vs.into_iter().sum();
+ assert_eq!(sum, Decimal::from(45))
+}
+
+#[test]
+fn declarative_ref_dec_sum() {
+ let vs = (0..10).map(|i| i.into()).collect::<Vec<Decimal>>();
+ let sum: Decimal = vs.iter().sum();
+ assert_eq!(sum, Decimal::from(45))
+}
+
+#[cfg(feature = "postgres")]
+#[test]
+fn to_from_sql() {
+ use bytes::BytesMut;
+ use postgres::types::{FromSql, Kind, ToSql, Type};
+
+ let tests = &[
+ "3950.123456",
+ "3950",
+ "0.1",
+ "0.01",
+ "0.001",
+ "0.0001",
+ "0.00001",
+ "0.000001",
+ "1",
+ "-100",
+ "-123.456",
+ "119996.25",
+ "1000000",
+ "9999999.99999",
+ "12340.56789",
+ "79228162514264337593543950335", // 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF (96 bit)
+ "4951760157141521099596496895", // 0x0FFF_FFFF_FFFF_FFFF_FFFF_FFFF (95 bit)
+ "4951760157141521099596496896", // 0x1000_0000_0000_0000_0000_0000
+ "18446744073709551615",
+ "-18446744073709551615",
+ ];
+
+ let t = Type::new("".into(), 0, Kind::Simple, "".into());
+
+ for test in tests {
+ let input = Decimal::from_str(test).unwrap();
+ let mut 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;
+
+ let mut 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();
+
+ assert_eq!(k1, k2);
+ assert_eq!(k1, k3);
+ assert_ne!(k1, k4);
+
+ let h1 = hash_it(k1);
+ let h2 = hash_it(k2);
+ let h3 = hash_it(k3);
+ let h4 = hash_it(k4);
+
+ assert_eq!(h1, h2);
+ assert_eq!(h1, h3);
+ assert_ne!(h1, h4);
+
+ // Test the application of Hash calculation to a HashMap.
+
+ let mut 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 {
+ let mut value = Decimal::from_str(value_raw).unwrap();
+ value.rescale(new_scale);
+ assert_eq!(expected_value, value.to_string());
+ assert_eq!(expected_scale, value.scale());
+ }
+}
+
+#[test]
+fn test_constants() {
+ assert_eq!("0", Decimal::ZERO.to_string());
+ assert_eq!("1", Decimal::ONE.to_string());
+ assert_eq!("-1", Decimal::NEGATIVE_ONE.to_string());
+ assert_eq!("10", Decimal::TEN.to_string());
+ assert_eq!("100", Decimal::ONE_HUNDRED.to_string());
+ assert_eq!("1000", Decimal::ONE_THOUSAND.to_string());
+ assert_eq!("2", Decimal::TWO.to_string());
+}
+
+#[test]
+fn test_inv() {
+ assert_eq!("0.01", Decimal::ONE_HUNDRED.inv().to_string());
+}
+
+// Mathematical features
+#[cfg(feature = "maths")]
+mod maths {
+ use super::*;
+ use rust_decimal::MathematicalOps;
+
+ use num_traits::One;
+
+ #[test]
+ fn test_constants() {
+ assert_eq!("3.1415926535897932384626433833", Decimal::PI.to_string());
+ assert_eq!("6.2831853071795864769252867666", Decimal::TWO_PI.to_string());
+ assert_eq!("1.5707963267948966192313216916", Decimal::HALF_PI.to_string());
+ assert_eq!("2.7182818284590452353602874714", Decimal::E.to_string());
+ assert_eq!("0.3678794411714423215955237702", Decimal::E_INVERSE.to_string());
+ }
+
+ #[test]
+ fn test_powu() {
+ let test_cases = &[
+ // x, y, expected x ^ y
+ ("4", 3_u64, "64"),
+ ("3.222", 5_u64, "347.238347228449632"),
+ ("0.1", 0_u64, "1"),
+ ("342.4", 1_u64, "342.4"),
+ ("2.0", 16_u64, "65536"),
+ ];
+ for &(x, y, expected) in test_cases {
+ let x = Decimal::from_str(x).unwrap();
+ let pow = x.powu(y);
+ assert_eq!(pow.to_string(), expected, "{} ^ {}", x, y);
+ }
+ }
+
+ #[test]
+ #[should_panic(expected = "Pow overflowed")]
+ fn test_powu_panic() {
+ let two = Decimal::new(2, 0);
+ let _ = two.powu(128);
+ }
+
+ #[test]
+ fn test_checked_powu() {
+ let test_cases = &[
+ (Decimal::new(4, 0), 3_u64, Some(Decimal::new(64, 0))),
+ (
+ Decimal::from_str("3.222").unwrap(),
+ 5_u64,
+ Some(Decimal::from_str("347.238347228449632").unwrap()),
+ ),
+ (
+ Decimal::from_str("0.1").unwrap(),
+ 0_u64,
+ Some(Decimal::from_str("1").unwrap()),
+ ),
+ (
+ Decimal::from_str("342.4").unwrap(),
+ 1_u64,
+ Some(Decimal::from_str("342.4").unwrap()),
+ ),
+ (
+ Decimal::from_str("2.0").unwrap(),
+ 16_u64,
+ Some(Decimal::from_str("65536").unwrap()),
+ ),
+ (Decimal::from_str("2.0").unwrap(), 128_u64, None),
+ ];
+ for case in test_cases {
+ assert_eq!(case.2, case.0.checked_powu(case.1));
+ }
+ }
+
+ #[test]
+ fn test_powi() {
+ let test_cases = &[
+ // x, y, expected x ^ y
+ ("0", 0, "1"),
+ ("1", 0, "1"),
+ ("0", 1, "0"),
+ ("2", 3, "8"),
+ ("-2", 3, "-8"),
+ ("2", -3, "0.125"),
+ ("-2", -3, "-0.125"),
+ (
+ "3",
+ -3,
+ either!("0.037037037037037037037037037", "0.0370370370370370370370370370"),
+ ),
+ ("6", 3, "216"),
+ ("0.5", 2, "0.25"),
+ ];
+ for &(x, y, expected) in test_cases {
+ let x = Decimal::from_str(x).unwrap();
+ let pow = x.powi(y);
+ assert_eq!(pow.to_string(), expected, "{} ^ {}", x, y);
+ }
+ }
+
+ #[test]
+ fn test_powd() {
+ let test_cases = &[
+ // x, y, expected x ^ y
+ ("0", "0", "1"),
+ ("1", "0", "1"),
+ ("0", "1", "0"),
+ ("2", "3", "8"),
+ ("-2", "3", "-8"),
+ ("2", "-3", "0.125"),
+ ("-2", "-3", "-0.125"),
+ ("2.0", "3.0", "8"),
+ ("-2.0", "3.0", "-8"),
+ ("2.0", "-3.0", "0.125"),
+ ("-2.0", "-3.0", "-0.125"),
+ ("2.00", "3.00", "8"),
+ ("-2.00", "3.00", "-8"),
+ ("2.00", "-3.00", "0.125"),
+ ("-2.00", "-3.00", "-0.125"),
+ (
+ "3",
+ "-3",
+ either!("0.037037037037037037037037037", "0.0370370370370370370370370370"),
+ ),
+ ("6", "3", "216"),
+ ("0.5", "2", "0.25"),
+ ("6", "13", "13060694016"),
+ // Exact result: 1 / 6^7
+ ("6", "-7", "0.0000035722450845907636031093"),
+ // ~= 0.8408964152537145
+ (
+ "0.5",
+ "0.25",
+ either!("0.8408964159265360661551317741", "0.8408964159265360661551317742"),
+ ),
+ // ~= 0.999999999999999999999999999790814
+ (
+ "0.1234567890123456789012345678",
+ "0.0000000000000000000000000001",
+ "0.9999999999999999999999999998",
+ ),
+ // ~= 611.0451043224257
+ (
+ "1234.5678",
+ "0.9012",
+ either!("611.04510415448740041442807964", "611.04510415448740041442807964"),
+ ),
+ (
+ "-2",
+ "0.5",
+ either!("-1.4142135570048917090885260834", "-1.4142135570048917090885260835"),
+ ),
+ // ~= -1.1193003023312942
+ (
+ "-2.5",
+ "0.123",
+ either!("-1.1193002994383985239135362086", "-1.1193002994383985239135362086"),
+ ),
+ // ~= 0.0003493091
+ (
+ "0.0000000000000000000000000001",
+ "0.1234567890123456789012345678",
+ either!("0.0003533642875741443321850682", "0.0003305188683169079961720764"),
+ ),
+ ];
+ for &(x, y, expected) in test_cases {
+ let x = Decimal::from_str(x).unwrap();
+ let y = Decimal::from_str(y).unwrap();
+ let pow = x.powd(y);
+ assert_eq!(pow.to_string(), expected, "{} ^ {}", x, y);
+ }
+ }
+
+ #[test]
+ fn test_sqrt() {
+ let test_cases = &[
+ ("4", "2"),
+ ("3.222", "1.7949930361981909371487724124"),
+ ("199.45", "14.122676800097069416754994263"),
+ ("342.4", "18.504053609952604112132102540"),
+ ("2", "1.414213562373095048801688724209698078569671875376948073176"),
+ ("0.0000000000000000000000000001", "0.0000000000000100000000000000"),
+ ];
+ for case in test_cases {
+ let a = Decimal::from_str(case.0).unwrap();
+ let expected = Decimal::from_str(case.1).unwrap();
+ assert_eq!(expected, a.sqrt().unwrap());
+ }
+
+ assert_eq!(Decimal::new(-2, 0).sqrt(), None);
+ }
+
+ #[cfg(not(feature = "legacy-ops"))]
+ #[test]
+ fn test_exp() {
+ // These are approximations
+ let test_cases = &[
+ // e^10 ~= 22026.465794806703
+ ("10", "22026.416157416030662013737698"),
+ // e^11 ~= 59874.14171519778
+ ("11", "59873.388231055804982198781924"),
+ // e^3 ~= 20.085536923187664
+ ("3", "20.085536911963143539758560764"),
+ // e^8 ~= 2980.957987041727
+ ("8", "2980.9578998304103856663509017"),
+ // e^0.1 ~= 1.1051709180756477
+ ("0.1", "1.1051709166666666666666666667"),
+ // e^2.0 ~= 7.3890560989306495
+ ("2.0", "7.3890560703259115957528655940"),
+ // e^-2 ~= 0.1353352832366127
+ ("-2", "0.1353352837605267572029589224"),
+ // e^-1 ~= 0.36787944117144233
+ ("-1", "0.3678794414773748171422559335"),
+ // e^0.123456789 ~= 1.131401115
+ ("0.123456789", "1.1314011144241455834073838005"),
+ // e^0.123456789123456789123456789 ~= 1.131401114651912752617990081
+ ("0.123456789123456789123456789", "1.1314011145638247316063947842"),
+ ];
+ for &(x, expected) in test_cases {
+ let x = Decimal::from_str(x).unwrap();
+ let expected = Decimal::from_str(expected).unwrap();
+ assert_eq!(expected, x.exp());
+ assert_eq!(Some(expected), x.checked_exp());
+ }
+ }
+
+ #[cfg(not(feature = "legacy-ops"))]
+ #[test]
+ fn test_exp_with_tolerance() {
+ let test_cases = &[
+ // e^0 = 1
+ ("0", "0.0002", "1"),
+ // e^1 ~= 2.7182539682539682539682539683
+ ("1", "0.0002", "2.7182539682539682539682539683"),
+ // e^10 ~= 22026.465794806703
+ (
+ "10",
+ "0.02",
+ either!("22026.416157416030662013737698", "22026.416157416030662013737699"),
+ ),
+ // e^11 ~= 59874.14171519778
+ ("11", "0.0002", "59873.388231055804982198781924"),
+ // e^11.7578 ~= 127741.03548949540892948423052
+ ("11.7578", "0.0002", "127741.03548949540892948423052"),
+ // e^3 ~= 20.085536923187664
+ ("3", "0.00002", "20.085534430970814899386327955"),
+ // e^8 ~= 2980.957987041727
+ ("8", "0.0002", "2980.9578998304103856663509017"),
+ // e^0.1 ~= 1.1051709180756477
+ ("0.1", "0.0002", "1.1051666666666666666666666667"),
+ // e^2.0 ~= 7.3890560989306495
+ ("2.0", "0.0002", "7.3890460157126823793490460156"),
+ // e^11.7578+ starts to overflow
+ ("11.7579", "0.0002", ""),
+ // e^11.7578+ starts to overflow
+ ("123", "0.0002", ""),
+ // e^-8+ starts to underflow
+ ("-8", "0.0002", "0.0003354626377168530220952633"),
+ // e^-9 continues to converge towards zero
+ ("-9", "0.0002", "0.0001234098417553083895710102"),
+ // e^-11 continues to converge towards zero
+ ("-11", "0.0002", "0.0000167019109748879838728391"),
+ // e^11.7579 has underflowed (by overflowing)
+ ("-11.7579", "0.0002", ""),
+ // e^-1024 has fully underflowed (by overflowing)
+ ("-1024", "0.0002", ""),
+ ];
+ for &(x, tolerance, expected) in test_cases {
+ let x = Decimal::from_str(x).unwrap();
+ let tolerance = Decimal::from_str(tolerance).unwrap();
+ let expected = if expected.is_empty() {
+ None
+ } else {
+ Some(Decimal::from_str(expected).unwrap())
+ };
+
+ if let Some(expected) = expected {
+ assert_eq!(expected, x.exp_with_tolerance(tolerance));
+ assert_eq!(Some(expected), x.checked_exp_with_tolerance(tolerance));
+ } else {
+ assert_eq!(None, x.checked_exp_with_tolerance(tolerance));
+ }
+ }
+ }
+
+ #[test]
+ #[should_panic(expected = "Exp overflowed")]
+ fn test_exp_expected_panic_from_overflow() {
+ let d = Decimal::from_str("1024").unwrap();
+ let _ = d.exp();
+ }
+
+ #[test]
+ #[should_panic(expected = "Exp underflowed")]
+ fn test_exp_expected_panic_from_underflow() {
+ let d = Decimal::from_str("-1024").unwrap();
+ let _ = d.exp();
+ }
+
+ #[test]
+ fn test_norm_cdf() {
+ let test_cases = &[
+ (
+ Decimal::from_str("-0.4").unwrap(),
+ either!(
+ Decimal::from_str("0.3445781286821245037094401704").unwrap(),
+ Decimal::from_str("0.3445781286821245037094401728").unwrap()
+ ),
+ ),
+ (
+ Decimal::from_str("-0.1").unwrap(),
+ either!(
+ Decimal::from_str("0.4601722899186706579921922696").unwrap(),
+ Decimal::from_str("0.4601722899186706579921922711").unwrap()
+ ),
+ ),
+ (
+ Decimal::from_str("0.1").unwrap(),
+ Decimal::from_str(either!(
+ "0.5398277100813293420078077304",
+ "0.5398277100813293420078077290"
+ ))
+ .unwrap(),
+ ),
+ (
+ Decimal::from_str("0.4").unwrap(),
+ either!(
+ Decimal::from_str("0.6554218713178754962905598296").unwrap(),
+ Decimal::from_str("0.6554218713178754962905598272").unwrap()
+ ),
+ ),
+ (
+ Decimal::from_str("2.0").unwrap(),
+ either!(
+ Decimal::from_str("0.9772497381095865280953380673").unwrap(),
+ Decimal::from_str("0.9772497381095865280953380672").unwrap()
+ ),
+ ),
+ ];
+ for case in test_cases {
+ assert_eq!(case.1, case.0.norm_cdf());
+ }
+ }
+
+ #[test]
+ fn test_norm_pdf() {
+ let test_cases = &[
+ (
+ Decimal::from_str("-2.0").unwrap(),
+ Decimal::from_str("0.0539909667221995238993056051").unwrap(),
+ ),
+ (
+ Decimal::from_str("-0.4").unwrap(),
+ Decimal::from_str("0.3682701404285264134348468378").unwrap(),
+ ),
+ (
+ Decimal::from_str("-0.1").unwrap(),
+ Decimal::from_str("0.3969525474873078082322691394").unwrap(),
+ ),
+ (
+ Decimal::from_str("0.1").unwrap(),
+ Decimal::from_str("0.3969525474873078082322691394").unwrap(),
+ ),
+ (
+ Decimal::from_str("0.4").unwrap(),
+ Decimal::from_str("0.3682701404285264134348468378").unwrap(),
+ ),
+ (
+ Decimal::from_str("2.0").unwrap(),
+ Decimal::from_str("0.0539909667221995238993056051").unwrap(),
+ ),
+ ];
+ for case in test_cases {
+ assert_eq!(case.1, case.0.norm_pdf());
+ }
+ }
+
+ #[test]
+ fn test_ln() {
+ let test_cases = [
+ ("1", "0"),
+ // Wolfram Alpha gives -1.46968
+ (
+ "0.23",
+ either!("-1.4696759700589416772292300779", "-1.4696759700589416772292300777"),
+ ),
+ // Wolfram Alpha gives 0.693147180559945309417232121458176568075500134360255254120
+ ("2", "0.6931471805599453094172321218"),
+ // Wolfram Alpha gives 3.218875824868200749201518666452375279051202708537035443825
+ (
+ "25",
+ either!("3.2188758248682007492015186670", "3.2188758248682007492015186674"),
+ ),
+ // Wolfram Alpha gives 0.210721022
+ (
+ "1.234567890",
+ either!("0.2107210222156525610500017104", "0.2107210222156525610500017106"),
+ ),
+ ];
+
+ 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);
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "maths-nopanic")]
+ fn test_invalid_ln_nopanic() {
+ let test_cases = ["0", "-2.0"];
+
+ 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();
+ }
+
+ #[test]
+ fn test_log10() {
+ let test_cases = [
+ ("1", "0"),
+ // Wolfram Alpha: 0.3010299956639811952137388947
+ (
+ "2",
+ either!("0.3010299956639811952137388949", "0.3010299956639811952137388948"),
+ ),
+ // Wolfram Alpha: 0.0915149772
+ (
+ "1.234567890",
+ either!("0.0915149771692704475183336230", "0.0915149771692704475183336231"),
+ ),
+ ("10", "1"),
+ ("100", "2"),
+ ("1000", "3"),
+ ("1000.00000000", "3"),
+ ("1000.000000000000000000000", "3"),
+ ("10.000000000000000000000000000", "1"),
+ ("100000000000000.0000000000", "14"),
+ ("0.10", "-1"),
+ ("0.1", "-1"),
+ ("0.01", "-2"),
+ ("0.010", "-2"),
+ ("0.0100000000000000000", "-2"),
+ ("0.000001", "-6"),
+ ("0.000001000000000", "-6"),
+ ];
+
+ 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);
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "maths-nopanic")]
+ fn test_invalid_log10_nopanic() {
+ let test_cases = ["0", "-2.0"];
+
+ 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();
+ if let 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();
+ if let 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();
+ if let 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();
+ let mut rdr = csv::Reader::from_reader(
+ std::fs::File::open(format!("{}/tests/generated/{}", path.display(), $csv)).unwrap(),
+ );
+ let mut 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()),
+ }
+ }
+ }
+ };
+ }
+
+ gen_test!(test_add_000_001, "Add_000_001.csv", checked_add);
+ gen_test!(test_add_000_010, "Add_000_010.csv", checked_add);
+ gen_test!(test_add_000_011, "Add_000_011.csv", checked_add);
+ gen_test!(test_add_000_100, "Add_000_100.csv", checked_add);
+ gen_test!(test_add_000_101, "Add_000_101.csv", checked_add);
+ gen_test!(test_add_000_110, "Add_000_110.csv", checked_add);
+ gen_test!(test_add_000_111, "Add_000_111.csv", checked_add);
+ gen_test!(test_add_001_000, "Add_001_000.csv", checked_add);
+ gen_test!(test_add_001_001, "Add_001_001.csv", checked_add);
+ gen_test!(test_add_001_010, "Add_001_010.csv", checked_add);
+ gen_test!(test_add_001_011, "Add_001_011.csv", checked_add);
+ gen_test!(test_add_001_100, "Add_001_100.csv", checked_add);
+ gen_test!(test_add_001_101, "Add_001_101.csv", checked_add);
+ gen_test!(test_add_001_110, "Add_001_110.csv", checked_add);
+ gen_test!(test_add_001_111, "Add_001_111.csv", checked_add);
+ gen_test!(test_add_010_000, "Add_010_000.csv", checked_add);
+ gen_test!(test_add_010_001, "Add_010_001.csv", checked_add);
+ gen_test!(test_add_010_010, "Add_010_010.csv", checked_add);
+ gen_test!(test_add_010_011, "Add_010_011.csv", checked_add);
+ gen_test!(test_add_010_100, "Add_010_100.csv", checked_add);
+ gen_test!(test_add_010_101, "Add_010_101.csv", checked_add);
+ gen_test!(test_add_010_110, "Add_010_110.csv", checked_add);
+ gen_test!(test_add_010_111, "Add_010_111.csv", checked_add);
+ gen_test!(test_add_011_000, "Add_011_000.csv", checked_add);
+ gen_test!(test_add_011_001, "Add_011_001.csv", checked_add);
+ gen_test!(test_add_011_010, "Add_011_010.csv", checked_add);
+ gen_test!(test_add_011_011, "Add_011_011.csv", checked_add);
+ gen_test!(test_add_011_100, "Add_011_100.csv", checked_add);
+ gen_test!(test_add_011_101, "Add_011_101.csv", checked_add);
+ gen_test!(test_add_011_110, "Add_011_110.csv", checked_add);
+ gen_test!(test_add_011_111, "Add_011_111.csv", checked_add);
+ gen_test!(test_add_100_000, "Add_100_000.csv", checked_add);
+ gen_test!(test_add_100_001, "Add_100_001.csv", checked_add);
+ gen_test!(test_add_100_010, "Add_100_010.csv", checked_add);
+ gen_test!(test_add_100_011, "Add_100_011.csv", checked_add);
+ gen_test!(test_add_100_100, "Add_100_100.csv", checked_add);
+ gen_test!(test_add_100_101, "Add_100_101.csv", checked_add);
+ gen_test!(test_add_100_110, "Add_100_110.csv", checked_add);
+ gen_test!(test_add_100_111, "Add_100_111.csv", checked_add);
+ gen_test!(test_add_101_000, "Add_101_000.csv", checked_add);
+ gen_test!(test_add_101_001, "Add_101_001.csv", checked_add);
+ gen_test!(test_add_101_010, "Add_101_010.csv", checked_add);
+ gen_test!(test_add_101_011, "Add_101_011.csv", checked_add);
+ gen_test!(test_add_101_100, "Add_101_100.csv", checked_add);
+ gen_test!(test_add_101_101, "Add_101_101.csv", checked_add);
+ gen_test!(test_add_101_110, "Add_101_110.csv", checked_add);
+ gen_test!(test_add_101_111, "Add_101_111.csv", checked_add);
+ gen_test!(test_add_110_000, "Add_110_000.csv", checked_add);
+ gen_test!(test_add_110_001, "Add_110_001.csv", checked_add);
+ gen_test!(test_add_110_010, "Add_110_010.csv", checked_add);
+ gen_test!(test_add_110_011, "Add_110_011.csv", checked_add);
+ gen_test!(test_add_110_100, "Add_110_100.csv", checked_add);
+ gen_test!(test_add_110_101, "Add_110_101.csv", checked_add);
+ gen_test!(test_add_110_110, "Add_110_110.csv", checked_add);
+ gen_test!(test_add_110_111, "Add_110_111.csv", checked_add);
+ gen_test!(test_add_111_000, "Add_111_000.csv", checked_add);
+ gen_test!(test_add_111_001, "Add_111_001.csv", checked_add);
+ gen_test!(test_add_111_010, "Add_111_010.csv", checked_add);
+ gen_test!(test_add_111_011, "Add_111_011.csv", checked_add);
+ gen_test!(test_add_111_100, "Add_111_100.csv", checked_add);
+ gen_test!(test_add_111_101, "Add_111_101.csv", checked_add);
+ gen_test!(test_add_111_110, "Add_111_110.csv", checked_add);
+ gen_test!(test_add_111_111, "Add_111_111.csv", checked_add);
+
+ gen_test!(test_div_000_001, "Div_000_001.csv", checked_div);
+ gen_test!(test_div_000_010, "Div_000_010.csv", checked_div);
+ gen_test!(test_div_000_011, "Div_000_011.csv", checked_div);
+ gen_test!(test_div_000_100, "Div_000_100.csv", checked_div);
+ gen_test!(test_div_000_101, "Div_000_101.csv", checked_div);
+ gen_test!(test_div_000_110, "Div_000_110.csv", checked_div);
+ gen_test!(test_div_000_111, "Div_000_111.csv", checked_div);
+ gen_test!(test_div_001_000, "Div_001_000.csv", checked_div);
+ gen_test!(test_div_001_001, "Div_001_001.csv", checked_div);
+ gen_test!(test_div_001_010, "Div_001_010.csv", checked_div);
+ gen_test!(test_div_001_011, "Div_001_011.csv", checked_div);
+ gen_test!(test_div_001_100, "Div_001_100.csv", checked_div);
+ gen_test!(test_div_001_101, "Div_001_101.csv", checked_div);
+ gen_test!(test_div_001_110, "Div_001_110.csv", checked_div);
+ gen_test!(test_div_001_111, "Div_001_111.csv", checked_div);
+ gen_test!(test_div_010_000, "Div_010_000.csv", checked_div);
+ gen_test!(test_div_010_001, "Div_010_001.csv", checked_div);
+ gen_test!(test_div_010_010, "Div_010_010.csv", checked_div);
+ gen_test!(test_div_010_011, "Div_010_011.csv", checked_div);
+ gen_test!(test_div_010_100, "Div_010_100.csv", checked_div);
+ gen_test!(test_div_010_101, "Div_010_101.csv", checked_div);
+ gen_test!(test_div_010_110, "Div_010_110.csv", checked_div);
+ gen_test!(test_div_010_111, "Div_010_111.csv", checked_div);
+ gen_test!(test_div_011_000, "Div_011_000.csv", checked_div);
+ gen_test!(test_div_011_001, "Div_011_001.csv", checked_div);
+ gen_test!(test_div_011_010, "Div_011_010.csv", checked_div);
+ gen_test!(test_div_011_011, "Div_011_011.csv", checked_div);
+ gen_test!(test_div_011_100, "Div_011_100.csv", checked_div);
+ gen_test!(test_div_011_101, "Div_011_101.csv", checked_div);
+ gen_test!(test_div_011_110, "Div_011_110.csv", checked_div);
+ gen_test!(test_div_011_111, "Div_011_111.csv", checked_div);
+ gen_test!(test_div_100_000, "Div_100_000.csv", checked_div);
+ gen_test!(test_div_100_001, "Div_100_001.csv", checked_div);
+ gen_test!(test_div_100_010, "Div_100_010.csv", checked_div);
+ gen_test!(test_div_100_011, "Div_100_011.csv", checked_div);
+ gen_test!(test_div_100_100, "Div_100_100.csv", checked_div);
+ gen_test!(test_div_100_101, "Div_100_101.csv", checked_div);
+ gen_test!(test_div_100_110, "Div_100_110.csv", checked_div);
+ gen_test!(test_div_100_111, "Div_100_111.csv", checked_div);
+ gen_test!(test_div_101_000, "Div_101_000.csv", checked_div);
+ gen_test!(test_div_101_001, "Div_101_001.csv", checked_div);
+ gen_test!(test_div_101_010, "Div_101_010.csv", checked_div);
+ gen_test!(test_div_101_011, "Div_101_011.csv", checked_div);
+ gen_test!(test_div_101_100, "Div_101_100.csv", checked_div);
+ gen_test!(test_div_101_101, "Div_101_101.csv", checked_div);
+ gen_test!(test_div_101_110, "Div_101_110.csv", checked_div);
+ gen_test!(test_div_101_111, "Div_101_111.csv", checked_div);
+ gen_test!(test_div_110_000, "Div_110_000.csv", checked_div);
+ gen_test!(test_div_110_001, "Div_110_001.csv", checked_div);
+ gen_test!(test_div_110_010, "Div_110_010.csv", checked_div);
+ gen_test!(test_div_110_011, "Div_110_011.csv", checked_div);
+ gen_test!(test_div_110_100, "Div_110_100.csv", checked_div);
+ gen_test!(test_div_110_101, "Div_110_101.csv", checked_div);
+ gen_test!(test_div_110_110, "Div_110_110.csv", checked_div);
+ gen_test!(test_div_110_111, "Div_110_111.csv", checked_div);
+ gen_test!(test_div_111_000, "Div_111_000.csv", checked_div);
+ gen_test!(test_div_111_001, "Div_111_001.csv", checked_div);
+ gen_test!(test_div_111_010, "Div_111_010.csv", checked_div);
+ gen_test!(test_div_111_011, "Div_111_011.csv", checked_div);
+ gen_test!(test_div_111_100, "Div_111_100.csv", checked_div);
+ gen_test!(test_div_111_101, "Div_111_101.csv", checked_div);
+ gen_test!(test_div_111_110, "Div_111_110.csv", checked_div);
+ gen_test!(test_div_111_111, "Div_111_111.csv", checked_div);
+
+ gen_test!(test_mul_000_001, "Mul_000_001.csv", checked_mul);
+ gen_test!(test_mul_000_010, "Mul_000_010.csv", checked_mul);
+ gen_test!(test_mul_000_011, "Mul_000_011.csv", checked_mul);
+ gen_test!(test_mul_000_100, "Mul_000_100.csv", checked_mul);
+ gen_test!(test_mul_000_101, "Mul_000_101.csv", checked_mul);
+ gen_test!(test_mul_000_110, "Mul_000_110.csv", checked_mul);
+ gen_test!(test_mul_000_111, "Mul_000_111.csv", checked_mul);
+ gen_test!(test_mul_001_000, "Mul_001_000.csv", checked_mul);
+ gen_test!(test_mul_001_001, "Mul_001_001.csv", checked_mul);
+ gen_test!(test_mul_001_010, "Mul_001_010.csv", checked_mul);
+ gen_test!(test_mul_001_011, "Mul_001_011.csv", checked_mul);
+ gen_test!(test_mul_001_100, "Mul_001_100.csv", checked_mul);
+ gen_test!(test_mul_001_101, "Mul_001_101.csv", checked_mul);
+ gen_test!(test_mul_001_110, "Mul_001_110.csv", checked_mul);
+ gen_test!(test_mul_001_111, "Mul_001_111.csv", checked_mul);
+ gen_test!(test_mul_010_000, "Mul_010_000.csv", checked_mul);
+ gen_test!(test_mul_010_001, "Mul_010_001.csv", checked_mul);
+ gen_test!(test_mul_010_010, "Mul_010_010.csv", checked_mul);
+ gen_test!(test_mul_010_011, "Mul_010_011.csv", checked_mul);
+ gen_test!(test_mul_010_100, "Mul_010_100.csv", checked_mul);
+ gen_test!(test_mul_010_101, "Mul_010_101.csv", checked_mul);
+ gen_test!(test_mul_010_110, "Mul_010_110.csv", checked_mul);
+ gen_test!(test_mul_010_111, "Mul_010_111.csv", checked_mul);
+ gen_test!(test_mul_011_000, "Mul_011_000.csv", checked_mul);
+ gen_test!(test_mul_011_001, "Mul_011_001.csv", checked_mul);
+ gen_test!(test_mul_011_010, "Mul_011_010.csv", checked_mul);
+ gen_test!(test_mul_011_011, "Mul_011_011.csv", checked_mul);
+ gen_test!(test_mul_011_100, "Mul_011_100.csv", checked_mul);
+ gen_test!(test_mul_011_101, "Mul_011_101.csv", checked_mul);
+ gen_test!(test_mul_011_110, "Mul_011_110.csv", checked_mul);
+ gen_test!(test_mul_011_111, "Mul_011_111.csv", checked_mul);
+ gen_test!(test_mul_100_000, "Mul_100_000.csv", checked_mul);
+ gen_test!(test_mul_100_001, "Mul_100_001.csv", checked_mul);
+ gen_test!(test_mul_100_010, "Mul_100_010.csv", checked_mul);
+ gen_test!(test_mul_100_011, "Mul_100_011.csv", checked_mul);
+ gen_test!(test_mul_100_100, "Mul_100_100.csv", checked_mul);
+ gen_test!(test_mul_100_101, "Mul_100_101.csv", checked_mul);
+ gen_test!(test_mul_100_110, "Mul_100_110.csv", checked_mul);
+ gen_test!(test_mul_100_111, "Mul_100_111.csv", checked_mul);
+ gen_test!(test_mul_101_000, "Mul_101_000.csv", checked_mul);
+ gen_test!(test_mul_101_001, "Mul_101_001.csv", checked_mul);
+ gen_test!(test_mul_101_010, "Mul_101_010.csv", checked_mul);
+ gen_test!(test_mul_101_011, "Mul_101_011.csv", checked_mul);
+ gen_test!(test_mul_101_100, "Mul_101_100.csv", checked_mul);
+ gen_test!(test_mul_101_101, "Mul_101_101.csv", checked_mul);
+ gen_test!(test_mul_101_110, "Mul_101_110.csv", checked_mul);
+ gen_test!(test_mul_101_111, "Mul_101_111.csv", checked_mul);
+ gen_test!(test_mul_110_000, "Mul_110_000.csv", checked_mul);
+ gen_test!(test_mul_110_001, "Mul_110_001.csv", checked_mul);
+ gen_test!(test_mul_110_010, "Mul_110_010.csv", checked_mul);
+ gen_test!(test_mul_110_011, "Mul_110_011.csv", checked_mul);
+ gen_test!(test_mul_110_100, "Mul_110_100.csv", checked_mul);
+ gen_test!(test_mul_110_101, "Mul_110_101.csv", checked_mul);
+ gen_test!(test_mul_110_110, "Mul_110_110.csv", checked_mul);
+ gen_test!(test_mul_110_111, "Mul_110_111.csv", checked_mul);
+ gen_test!(test_mul_111_000, "Mul_111_000.csv", checked_mul);
+ gen_test!(test_mul_111_001, "Mul_111_001.csv", checked_mul);
+ gen_test!(test_mul_111_010, "Mul_111_010.csv", checked_mul);
+ gen_test!(test_mul_111_011, "Mul_111_011.csv", checked_mul);
+ gen_test!(test_mul_111_100, "Mul_111_100.csv", checked_mul);
+ gen_test!(test_mul_111_101, "Mul_111_101.csv", checked_mul);
+ gen_test!(test_mul_111_110, "Mul_111_110.csv", checked_mul);
+ gen_test!(test_mul_111_111, "Mul_111_111.csv", checked_mul);
+
+ gen_test!(test_rem_000_001, "Rem_000_001.csv", checked_rem);
+ gen_test!(test_rem_000_010, "Rem_000_010.csv", checked_rem);
+ gen_test!(test_rem_000_011, "Rem_000_011.csv", checked_rem);
+ gen_test!(test_rem_000_100, "Rem_000_100.csv", checked_rem);
+ gen_test!(test_rem_000_101, "Rem_000_101.csv", checked_rem);
+ gen_test!(test_rem_000_110, "Rem_000_110.csv", checked_rem);
+ gen_test!(test_rem_000_111, "Rem_000_111.csv", checked_rem);
+ gen_test!(test_rem_001_000, "Rem_001_000.csv", checked_rem);
+ gen_test!(test_rem_001_001, "Rem_001_001.csv", checked_rem);
+ gen_test!(test_rem_001_010, "Rem_001_010.csv", checked_rem);
+ gen_test!(test_rem_001_011, "Rem_001_011.csv", checked_rem);
+ gen_test!(test_rem_001_100, "Rem_001_100.csv", checked_rem);
+ gen_test!(test_rem_001_101, "Rem_001_101.csv", checked_rem);
+ gen_test!(test_rem_001_110, "Rem_001_110.csv", checked_rem);
+ gen_test!(test_rem_001_111, "Rem_001_111.csv", checked_rem);
+ gen_test!(test_rem_010_000, "Rem_010_000.csv", checked_rem);
+ gen_test!(test_rem_010_001, "Rem_010_001.csv", checked_rem);
+ gen_test!(test_rem_010_010, "Rem_010_010.csv", checked_rem);
+ gen_test!(test_rem_010_011, "Rem_010_011.csv", checked_rem);
+ gen_test!(test_rem_010_100, "Rem_010_100.csv", checked_rem);
+ gen_test!(test_rem_010_101, "Rem_010_101.csv", checked_rem);
+ gen_test!(test_rem_010_110, "Rem_010_110.csv", checked_rem);
+ gen_test!(test_rem_010_111, "Rem_010_111.csv", checked_rem);
+ gen_test!(test_rem_011_000, "Rem_011_000.csv", checked_rem);
+ gen_test!(test_rem_011_001, "Rem_011_001.csv", checked_rem);
+ gen_test!(test_rem_011_010, "Rem_011_010.csv", checked_rem);
+ gen_test!(test_rem_011_011, "Rem_011_011.csv", checked_rem);
+ gen_test!(test_rem_011_100, "Rem_011_100.csv", checked_rem);
+ gen_test!(test_rem_011_101, "Rem_011_101.csv", checked_rem);
+ gen_test!(test_rem_011_110, "Rem_011_110.csv", checked_rem);
+ gen_test!(test_rem_011_111, "Rem_011_111.csv", checked_rem);
+ gen_test!(test_rem_100_000, "Rem_100_000.csv", checked_rem);
+ gen_test!(test_rem_100_001, "Rem_100_001.csv", checked_rem);
+ gen_test!(test_rem_100_010, "Rem_100_010.csv", checked_rem);
+ gen_test!(test_rem_100_011, "Rem_100_011.csv", checked_rem);
+ gen_test!(test_rem_100_100, "Rem_100_100.csv", checked_rem);
+ gen_test!(test_rem_100_101, "Rem_100_101.csv", checked_rem);
+ gen_test!(test_rem_100_110, "Rem_100_110.csv", checked_rem);
+ gen_test!(test_rem_100_111, "Rem_100_111.csv", checked_rem);
+ gen_test!(test_rem_101_000, "Rem_101_000.csv", checked_rem);
+ gen_test!(test_rem_101_001, "Rem_101_001.csv", checked_rem);
+ gen_test!(test_rem_101_010, "Rem_101_010.csv", checked_rem);
+ gen_test!(test_rem_101_011, "Rem_101_011.csv", checked_rem);
+ gen_test!(test_rem_101_100, "Rem_101_100.csv", checked_rem);
+ gen_test!(test_rem_101_101, "Rem_101_101.csv", checked_rem);
+ gen_test!(test_rem_101_110, "Rem_101_110.csv", checked_rem);
+ gen_test!(test_rem_101_111, "Rem_101_111.csv", checked_rem);
+ gen_test!(test_rem_110_000, "Rem_110_000.csv", checked_rem);
+ gen_test!(test_rem_110_001, "Rem_110_001.csv", checked_rem);
+ gen_test!(test_rem_110_010, "Rem_110_010.csv", checked_rem);
+ gen_test!(test_rem_110_011, "Rem_110_011.csv", checked_rem);
+ gen_test!(test_rem_110_100, "Rem_110_100.csv", checked_rem);
+ gen_test!(test_rem_110_101, "Rem_110_101.csv", checked_rem);
+ gen_test!(test_rem_110_110, "Rem_110_110.csv", checked_rem);
+ gen_test!(test_rem_110_111, "Rem_110_111.csv", checked_rem);
+ gen_test!(test_rem_111_000, "Rem_111_000.csv", checked_rem);
+ gen_test!(test_rem_111_001, "Rem_111_001.csv", checked_rem);
+ gen_test!(test_rem_111_010, "Rem_111_010.csv", checked_rem);
+ gen_test!(test_rem_111_011, "Rem_111_011.csv", checked_rem);
+ gen_test!(test_rem_111_100, "Rem_111_100.csv", checked_rem);
+ gen_test!(test_rem_111_101, "Rem_111_101.csv", checked_rem);
+ gen_test!(test_rem_111_110, "Rem_111_110.csv", checked_rem);
+ gen_test!(test_rem_111_111, "Rem_111_111.csv", checked_rem);
+
+ gen_test!(test_sub_000_001, "Sub_000_001.csv", checked_sub);
+ gen_test!(test_sub_000_010, "Sub_000_010.csv", checked_sub);
+ gen_test!(test_sub_000_011, "Sub_000_011.csv", checked_sub);
+ gen_test!(test_sub_000_100, "Sub_000_100.csv", checked_sub);
+ gen_test!(test_sub_000_101, "Sub_000_101.csv", checked_sub);
+ gen_test!(test_sub_000_110, "Sub_000_110.csv", checked_sub);
+ gen_test!(test_sub_000_111, "Sub_000_111.csv", checked_sub);
+ gen_test!(test_sub_001_000, "Sub_001_000.csv", checked_sub);
+ gen_test!(test_sub_001_001, "Sub_001_001.csv", checked_sub);
+ gen_test!(test_sub_001_010, "Sub_001_010.csv", checked_sub);
+ gen_test!(test_sub_001_011, "Sub_001_011.csv", checked_sub);
+ gen_test!(test_sub_001_100, "Sub_001_100.csv", checked_sub);
+ gen_test!(test_sub_001_101, "Sub_001_101.csv", checked_sub);
+ gen_test!(test_sub_001_110, "Sub_001_110.csv", checked_sub);
+ gen_test!(test_sub_001_111, "Sub_001_111.csv", checked_sub);
+ gen_test!(test_sub_010_000, "Sub_010_000.csv", checked_sub);
+ gen_test!(test_sub_010_001, "Sub_010_001.csv", checked_sub);
+ gen_test!(test_sub_010_010, "Sub_010_010.csv", checked_sub);
+ gen_test!(test_sub_010_011, "Sub_010_011.csv", checked_sub);
+ gen_test!(test_sub_010_100, "Sub_010_100.csv", checked_sub);
+ gen_test!(test_sub_010_101, "Sub_010_101.csv", checked_sub);
+ gen_test!(test_sub_010_110, "Sub_010_110.csv", checked_sub);
+ gen_test!(test_sub_010_111, "Sub_010_111.csv", checked_sub);
+ gen_test!(test_sub_011_000, "Sub_011_000.csv", checked_sub);
+ gen_test!(test_sub_011_001, "Sub_011_001.csv", checked_sub);
+ gen_test!(test_sub_011_010, "Sub_011_010.csv", checked_sub);
+ gen_test!(test_sub_011_011, "Sub_011_011.csv", checked_sub);
+ gen_test!(test_sub_011_100, "Sub_011_100.csv", checked_sub);
+ gen_test!(test_sub_011_101, "Sub_011_101.csv", checked_sub);
+ gen_test!(test_sub_011_110, "Sub_011_110.csv", checked_sub);
+ gen_test!(test_sub_011_111, "Sub_011_111.csv", checked_sub);
+ gen_test!(test_sub_100_000, "Sub_100_000.csv", checked_sub);
+ gen_test!(test_sub_100_001, "Sub_100_001.csv", checked_sub);
+ gen_test!(test_sub_100_010, "Sub_100_010.csv", checked_sub);
+ gen_test!(test_sub_100_011, "Sub_100_011.csv", checked_sub);
+ gen_test!(test_sub_100_100, "Sub_100_100.csv", checked_sub);
+ gen_test!(test_sub_100_101, "Sub_100_101.csv", checked_sub);
+ gen_test!(test_sub_100_110, "Sub_100_110.csv", checked_sub);
+ gen_test!(test_sub_100_111, "Sub_100_111.csv", checked_sub);
+ gen_test!(test_sub_101_000, "Sub_101_000.csv", checked_sub);
+ gen_test!(test_sub_101_001, "Sub_101_001.csv", checked_sub);
+ gen_test!(test_sub_101_010, "Sub_101_010.csv", checked_sub);
+ gen_test!(test_sub_101_011, "Sub_101_011.csv", checked_sub);
+ gen_test!(test_sub_101_100, "Sub_101_100.csv", checked_sub);
+ gen_test!(test_sub_101_101, "Sub_101_101.csv", checked_sub);
+ gen_test!(test_sub_101_110, "Sub_101_110.csv", checked_sub);
+ gen_test!(test_sub_101_111, "Sub_101_111.csv", checked_sub);
+ gen_test!(test_sub_110_000, "Sub_110_000.csv", checked_sub);
+ gen_test!(test_sub_110_001, "Sub_110_001.csv", checked_sub);
+ gen_test!(test_sub_110_010, "Sub_110_010.csv", checked_sub);
+ gen_test!(test_sub_110_011, "Sub_110_011.csv", checked_sub);
+ gen_test!(test_sub_110_100, "Sub_110_100.csv", checked_sub);
+ gen_test!(test_sub_110_101, "Sub_110_101.csv", checked_sub);
+ gen_test!(test_sub_110_110, "Sub_110_110.csv", checked_sub);
+ gen_test!(test_sub_110_111, "Sub_110_111.csv", checked_sub);
+ gen_test!(test_sub_111_000, "Sub_111_000.csv", checked_sub);
+ gen_test!(test_sub_111_001, "Sub_111_001.csv", checked_sub);
+ gen_test!(test_sub_111_010, "Sub_111_010.csv", checked_sub);
+ gen_test!(test_sub_111_011, "Sub_111_011.csv", checked_sub);
+ gen_test!(test_sub_111_100, "Sub_111_100.csv", checked_sub);
+ gen_test!(test_sub_111_101, "Sub_111_101.csv", checked_sub);
+ gen_test!(test_sub_111_110, "Sub_111_110.csv", checked_sub);
+ gen_test!(test_sub_111_111, "Sub_111_111.csv", checked_sub);
+}
+
+#[cfg(feature = "rocket-traits")]
+mod rocket {
+ use crate::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};
+
+ use super::*;
+
+ #[test]
+ fn it_can_generate_arbitrary_decimals() {
+ let mut 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());
+
+ // 288230376151711744.
+ // - 714606955844629274884780.85120
+ // =
+ // - 714606667614253123173036.85120
+ assert_eq!("-714606667614253123173036.85120", c.unwrap().to_string());
+ }
+
+ #[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())
+ }
+}
diff --git a/third_party/rust/rust_decimal/tests/macros.rs b/third_party/rust/rust_decimal/tests/macros.rs
new file mode 100644
index 0000000000..39cf0edf60
--- /dev/null
+++ b/third_party/rust/rust_decimal/tests/macros.rs
@@ -0,0 +1,49 @@
+#[macro_export]
+macro_rules! assert_approx_eq {
+ ($a:expr, $b:expr, $precision:expr) => {{
+ let (a, b) = (&$a, &$b);
+ let eps = Decimal::new(1, $precision);
+ let abs = (*a - *b).abs();
+ assert!(
+ abs <= eps,
+ "assertion failed: `(left ~= right)` \n \
+ left: `{:?}`,\n \
+ right: `{:?}`,\n \
+ expect: `{:?}`,\n \
+ real: `{:?}`",
+ *a,
+ *b,
+ eps,
+ abs,
+ );
+ }};
+ ($a:expr, $b:expr, $precision:expr, $($arg:tt)+) => {{
+ let (a, b) = (&$a, &$b);
+ let eps = Decimal::new(1, $precision);
+ let abs = (*a - *b).abs();
+ assert!(
+ abs <= eps,
+ "assertion failed: `(left ~= right)` \n \
+ left: `{:?}`,\n \
+ right: `{:?}`,\n \
+ expect: `{:?}`,\n \
+ real: `{:?}`: {}",
+ *a,
+ *b,
+ eps,
+ abs,
+ format_args!($($arg)+),
+ );
+ }};
+}
+
+#[macro_export]
+macro_rules! either {
+ ($result:expr, $legacy_result:expr) => {
+ if cfg!(feature = "legacy-ops") {
+ $legacy_result
+ } else {
+ $result
+ }
+ };
+}
diff --git a/third_party/rust/rust_decimal/tests/version-numbers.rs b/third_party/rust/rust_decimal/tests/version-numbers.rs
new file mode 100644
index 0000000000..288592d02f
--- /dev/null
+++ b/third_party/rust/rust_decimal/tests/version-numbers.rs
@@ -0,0 +1,9 @@
+#[test]
+fn test_readme_deps() {
+ version_sync::assert_markdown_deps_updated!("README.md");
+}
+
+#[test]
+fn test_html_root_url() {
+ version_sync::assert_html_root_url_updated!("src/lib.rs");
+}