// Adapted from https://github.com/Alexhuszagh/rust-lexical. use crate::lexical::float::ExtendedFloat; use crate::lexical::num::Float; use crate::lexical::rounding::*; // MASKS #[test] fn lower_n_mask_test() { assert_eq!(lower_n_mask(0u64), 0b0); assert_eq!(lower_n_mask(1u64), 0b1); assert_eq!(lower_n_mask(2u64), 0b11); assert_eq!(lower_n_mask(10u64), 0b1111111111); assert_eq!(lower_n_mask(32u64), 0b11111111111111111111111111111111); } #[test] fn lower_n_halfway_test() { assert_eq!(lower_n_halfway(0u64), 0b0); assert_eq!(lower_n_halfway(1u64), 0b1); assert_eq!(lower_n_halfway(2u64), 0b10); assert_eq!(lower_n_halfway(10u64), 0b1000000000); assert_eq!(lower_n_halfway(32u64), 0b10000000000000000000000000000000); } #[test] fn nth_bit_test() { assert_eq!(nth_bit(0u64), 0b1); assert_eq!(nth_bit(1u64), 0b10); assert_eq!(nth_bit(2u64), 0b100); assert_eq!(nth_bit(10u64), 0b10000000000); assert_eq!(nth_bit(31u64), 0b10000000000000000000000000000000); } #[test] fn internal_n_mask_test() { assert_eq!(internal_n_mask(1u64, 0u64), 0b0); assert_eq!(internal_n_mask(1u64, 1u64), 0b1); assert_eq!(internal_n_mask(2u64, 1u64), 0b10); assert_eq!(internal_n_mask(4u64, 2u64), 0b1100); assert_eq!(internal_n_mask(10u64, 2u64), 0b1100000000); assert_eq!(internal_n_mask(10u64, 4u64), 0b1111000000); assert_eq!( internal_n_mask(32u64, 4u64), 0b11110000000000000000000000000000 ); } // NEAREST ROUNDING #[test] fn round_nearest_test() { // Check exactly halfway (b'1100000') let mut fp = ExtendedFloat { mant: 0x60, exp: 0 }; let (above, halfway) = round_nearest(&mut fp, 6); assert!(!above); assert!(halfway); assert_eq!(fp.mant, 1); // Check above halfway (b'1100001') let mut fp = ExtendedFloat { mant: 0x61, exp: 0 }; let (above, halfway) = round_nearest(&mut fp, 6); assert!(above); assert!(!halfway); assert_eq!(fp.mant, 1); // Check below halfway (b'1011111') let mut fp = ExtendedFloat { mant: 0x5F, exp: 0 }; let (above, halfway) = round_nearest(&mut fp, 6); assert!(!above); assert!(!halfway); assert_eq!(fp.mant, 1); } // DIRECTED ROUNDING #[test] fn round_downward_test() { // b0000000 let mut fp = ExtendedFloat { mant: 0x00, exp: 0 }; round_downward(&mut fp, 6); assert_eq!(fp.mant, 0); // b1000000 let mut fp = ExtendedFloat { mant: 0x40, exp: 0 }; round_downward(&mut fp, 6); assert_eq!(fp.mant, 1); // b1100000 let mut fp = ExtendedFloat { mant: 0x60, exp: 0 }; round_downward(&mut fp, 6); assert_eq!(fp.mant, 1); // b1110000 let mut fp = ExtendedFloat { mant: 0x70, exp: 0 }; round_downward(&mut fp, 6); assert_eq!(fp.mant, 1); } #[test] fn round_nearest_tie_even_test() { // Check round-up, halfway let mut fp = ExtendedFloat { mant: 0x60, exp: 0 }; round_nearest_tie_even(&mut fp, 6); assert_eq!(fp.mant, 2); // Check round-down, halfway let mut fp = ExtendedFloat { mant: 0x20, exp: 0 }; round_nearest_tie_even(&mut fp, 6); assert_eq!(fp.mant, 0); // Check round-up, above halfway let mut fp = ExtendedFloat { mant: 0x61, exp: 0 }; round_nearest_tie_even(&mut fp, 6); assert_eq!(fp.mant, 2); let mut fp = ExtendedFloat { mant: 0x21, exp: 0 }; round_nearest_tie_even(&mut fp, 6); assert_eq!(fp.mant, 1); // Check round-down, below halfway let mut fp = ExtendedFloat { mant: 0x5F, exp: 0 }; round_nearest_tie_even(&mut fp, 6); assert_eq!(fp.mant, 1); let mut fp = ExtendedFloat { mant: 0x1F, exp: 0 }; round_nearest_tie_even(&mut fp, 6); assert_eq!(fp.mant, 0); } // HIGH-LEVEL #[test] fn round_to_float_test() { // Denormal let mut fp = ExtendedFloat { mant: 1 << 63, exp: f64::DENORMAL_EXPONENT - 15, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1 << 48); assert_eq!(fp.exp, f64::DENORMAL_EXPONENT); // Halfway, round-down (b'1000000000000000000000000000000000000000000000000000010000000000') let mut fp = ExtendedFloat { mant: 0x8000000000000400, exp: -63, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1 << 52); assert_eq!(fp.exp, -52); // Halfway, round-up (b'1000000000000000000000000000000000000000000000000000110000000000') let mut fp = ExtendedFloat { mant: 0x8000000000000C00, exp: -63, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 2); assert_eq!(fp.exp, -52); // Above halfway let mut fp = ExtendedFloat { mant: 0x8000000000000401, exp: -63, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 1); assert_eq!(fp.exp, -52); let mut fp = ExtendedFloat { mant: 0x8000000000000C01, exp: -63, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 2); assert_eq!(fp.exp, -52); // Below halfway let mut fp = ExtendedFloat { mant: 0x80000000000003FF, exp: -63, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1 << 52); assert_eq!(fp.exp, -52); let mut fp = ExtendedFloat { mant: 0x8000000000000BFF, exp: -63, }; round_to_float::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 1); assert_eq!(fp.exp, -52); } #[test] fn avoid_overflow_test() { // Avoid overflow, fails by 1 let mut fp = ExtendedFloat { mant: 0xFFFFFFFFFFFF, exp: f64::MAX_EXPONENT + 5, }; avoid_overflow::(&mut fp); assert_eq!(fp.mant, 0xFFFFFFFFFFFF); assert_eq!(fp.exp, f64::MAX_EXPONENT + 5); // Avoid overflow, succeeds let mut fp = ExtendedFloat { mant: 0xFFFFFFFFFFFF, exp: f64::MAX_EXPONENT + 4, }; avoid_overflow::(&mut fp); assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0); assert_eq!(fp.exp, f64::MAX_EXPONENT - 1); } #[test] fn round_to_native_test() { // Overflow let mut fp = ExtendedFloat { mant: 0xFFFFFFFFFFFF, exp: f64::MAX_EXPONENT + 4, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 0x1FFFFFFFFFFFE0); assert_eq!(fp.exp, f64::MAX_EXPONENT - 1); // Need denormal let mut fp = ExtendedFloat { mant: 1, exp: f64::DENORMAL_EXPONENT + 48, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1 << 48); assert_eq!(fp.exp, f64::DENORMAL_EXPONENT); // Halfway, round-down (b'10000000000000000000000000000000000000000000000000000100000') let mut fp = ExtendedFloat { mant: 0x400000000000020, exp: -58, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1 << 52); assert_eq!(fp.exp, -52); // Halfway, round-up (b'10000000000000000000000000000000000000000000000000001100000') let mut fp = ExtendedFloat { mant: 0x400000000000060, exp: -58, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 2); assert_eq!(fp.exp, -52); // Above halfway let mut fp = ExtendedFloat { mant: 0x400000000000021, exp: -58, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 1); assert_eq!(fp.exp, -52); let mut fp = ExtendedFloat { mant: 0x400000000000061, exp: -58, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 2); assert_eq!(fp.exp, -52); // Below halfway let mut fp = ExtendedFloat { mant: 0x40000000000001F, exp: -58, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1 << 52); assert_eq!(fp.exp, -52); let mut fp = ExtendedFloat { mant: 0x40000000000005F, exp: -58, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, (1 << 52) + 1); assert_eq!(fp.exp, -52); // Underflow // Adapted from failures in strtod. let mut fp = ExtendedFloat { exp: -1139, mant: 18446744073709550712, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 0); assert_eq!(fp.exp, 0); let mut fp = ExtendedFloat { exp: -1139, mant: 18446744073709551460, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 0); assert_eq!(fp.exp, 0); let mut fp = ExtendedFloat { exp: -1138, mant: 9223372036854776103, }; round_to_native::(&mut fp, round_nearest_tie_even); assert_eq!(fp.mant, 1); assert_eq!(fp.exp, -1074); }