diff --git a/src/decimal.rs b/src/decimal.rs index 3a80431b..4da98680 100644 --- a/src/decimal.rs +++ b/src/decimal.rs @@ -1403,140 +1403,46 @@ impl Decimal { [self.lo, self.mid, self.hi, 0] } - fn base2_to_decimal(bits: &mut [u32; 3], exponent2: i32, positive: bool, is64: bool) -> Option { - // 2^exponent2 = (10^exponent2)/(5^exponent2) - // = (5^-exponent2)*(10^exponent2) - let mut exponent5 = -exponent2; - let mut exponent10 = exponent2; // Ultimately, we want this for the scale - - while exponent5 > 0 { - // Check to see if the mantissa is divisible by 2 - if bits[0] & 0x1 == 0 { - exponent10 += 1; - exponent5 -= 1; - - // We can divide by 2 without losing precision - let hi_carry = bits[2] & 0x1 == 1; - bits[2] >>= 1; - let mid_carry = bits[1] & 0x1 == 1; - bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 }; - bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 }; - } else { - // The mantissa is NOT divisible by 2. Therefore the mantissa should - // be multiplied by 5, unless the multiplication overflows. - exponent5 -= 1; - - let mut temp = [bits[0], bits[1], bits[2]]; - if ops::array::mul_by_u32(&mut temp, 5) == 0 { - // Multiplication succeeded without overflow, so copy result back - bits[0] = temp[0]; - bits[1] = temp[1]; - bits[2] = temp[2]; - } else { - // Multiplication by 5 overflows. The mantissa should be divided - // by 2, and therefore will lose significant digits. - exponent10 += 1; - - // Shift right - let hi_carry = bits[2] & 0x1 == 1; - bits[2] >>= 1; - let mid_carry = bits[1] & 0x1 == 1; - bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 }; - bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 }; - } - } - } - - // In order to divide the value by 5, it is best to multiply by 2/10. - // Therefore, exponent10 is decremented, and the mantissa should be multiplied by 2 - while exponent5 < 0 { - if bits[2] & SIGN_MASK == 0 { - // No far left bit, the mantissa can withstand a shift-left without overflowing - exponent10 -= 1; - exponent5 += 1; - ops::array::shl1_internal(bits, 0); - } else { - // The mantissa would overflow if shifted. Therefore it should be - // directly divided by 5. This will lose significant digits, unless - // by chance the mantissa happens to be divisible by 5. - exponent5 += 1; - ops::array::div_by_u32(bits, 5); - } - } - - // At this point, the mantissa has assimilated the exponent5, but - // exponent10 might not be suitable for assignment. exponent10 must be - // in the range [-MAX_PRECISION..0], so the mantissa must be scaled up or - // down appropriately. - while exponent10 > 0 { - // In order to bring exponent10 down to 0, the mantissa should be - // multiplied by 10 to compensate. If the exponent10 is too big, this - // will cause the mantissa to overflow. - if ops::array::mul_by_u32(bits, 10) == 0 { - exponent10 -= 1; - } else { - // Overflowed - return? - return None; - } - } - - // In order to bring exponent up to -MAX_PRECISION, the mantissa should - // be divided by 10 to compensate. If the exponent10 is too small, this - // will cause the mantissa to underflow and become 0. - while exponent10 < -(MAX_PRECISION_U32 as i32) { - let rem10 = ops::array::div_by_u32(bits, 10); - exponent10 += 1; - if ops::array::is_all_zero(bits) { - // Underflow, unable to keep dividing - exponent10 = 0; - } else if rem10 >= 5 { - ops::array::add_one_internal(bits); - } - } - - // This step is required in order to remove excess bits of precision from the - // end of the bit representation, down to the precision guaranteed by the - // floating point number - if is64 { - // Guaranteed to about 16 dp - while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFF0_0000) != 0) { - let rem10 = ops::array::div_by_u32(bits, 10); - exponent10 += 1; - if rem10 >= 5 { - ops::array::add_one_internal(bits); - } - } - } else { - // Guaranteed to about 7 dp - while exponent10 < 0 && ((bits[0] & 0xFF00_0000) != 0 || bits[1] != 0 || bits[2] != 0) { - let rem10 = ops::array::div_by_u32(bits, 10); - exponent10 += 1; - if rem10 >= 5 { - ops::array::add_one_internal(bits); - } - } - } - - // Remove multiples of 10 from the representation - while exponent10 < 0 { - let mut temp = [bits[0], bits[1], bits[2]]; - let remainder = ops::array::div_by_u32(&mut temp, 10); - if remainder == 0 { - exponent10 += 1; - bits[0] = temp[0]; - bits[1] = temp[1]; - bits[2] = temp[2]; - } else { - break; - } - } + /// Parses a 32-bit float into a Decimal number whilst retaining any non-guaranteed precision. + /// + /// Typically when a float is parsed in Rust Decimal, any excess bits (after ~7.22 decimal points for + /// f32 as per IEEE-754) are removed due to any digits following this are considered an approximation + /// at best. This function bypasses this additional step and retains these excess bits. + /// + /// # Example + /// + /// ``` + /// use rust_decimal::prelude::*; + /// + /// // Usually floats are parsed leveraging float guarantees. i.e. 0.1_f32 => 0.1 + /// assert_eq!("0.1", Decimal::from_f32(0.1_f32).unwrap().to_string()); + /// + /// // Sometimes, we may want to represent the approximation exactly. + /// assert_eq!("0.100000001490116119384765625", Decimal::from_f32_retain(0.1_f32).unwrap().to_string()); + /// ``` + pub fn from_f32_retain(n: f32) -> Option { + from_f32(n, false) + } - Some(Decimal { - lo: bits[0], - mid: bits[1], - hi: bits[2], - flags: flags(!positive, -exponent10 as u32), - }) + /// Parses a 64-bit float into a Decimal number whilst retaining any non-guaranteed precision. + /// + /// Typically when a float is parsed in Rust Decimal, any excess bits (after ~15.95 decimal points for + /// f64 as per IEEE-754) are removed due to any digits following this are considered an approximation + /// at best. This function bypasses this additional step and retains these excess bits. + /// + /// # Example + /// + /// ``` + /// use rust_decimal::prelude::*; + /// + /// // Usually floats are parsed leveraging float guarantees. i.e. 0.1_f64 => 0.1 + /// assert_eq!("0.1", Decimal::from_f64(0.1_f64).unwrap().to_string()); + /// + /// // Sometimes, we may want to represent the approximation exactly. + /// assert_eq!("0.1000000000000000055511151231", Decimal::from_f64_retain(0.1_f64).unwrap().to_string()); + /// ``` + pub fn from_f64_retain(n: f64) -> Option { + from_f64(n, false) } /// Checked addition. Computes `self + other`, returning `None` if overflow occurred. @@ -1884,96 +1790,252 @@ impl FromPrimitive for Decimal { } fn from_f32(n: f32) -> Option { - // Handle the case if it is NaN, Infinity or -Infinity - if !n.is_finite() { - return None; - } + // By default, we remove excess bits. This allows 0.1_f64 == dec!(0.1). + from_f32(n, true) + } - // It's a shame we can't use a union for this due to it being broken up by bits - // i.e. 1/8/23 (sign, exponent, mantissa) - // See https://en.wikipedia.org/wiki/IEEE_754-1985 - // n = (sign*-1) * 2^exp * mantissa - // Decimal of course stores this differently... 10^-exp * significand - let raw = n.to_bits(); - let positive = (raw >> 31) == 0; - let biased_exponent = ((raw >> 23) & 0xFF) as i32; - let mantissa = raw & 0x007F_FFFF; - - // Handle the special zero case - if biased_exponent == 0 && mantissa == 0 { - let mut zero = ZERO; - if !positive { - zero.set_sign_negative(true); - } - return Some(zero); - } + fn from_f64(n: f64) -> Option { + // By default, we remove excess bits. This allows 0.1_f64 == dec!(0.1). + from_f64(n, true) + } +} + +#[inline] +fn from_f64(n: f64, remove_excess_bits: bool) -> Option { + // Handle the case if it is NaN, Infinity or -Infinity + if !n.is_finite() { + return None; + } + + // It's a shame we can't use a union for this due to it being broken up by bits + // i.e. 1/11/52 (sign, exponent, mantissa) + // See https://en.wikipedia.org/wiki/IEEE_754-1985 + // n = (sign*-1) * 2^exp * mantissa + // Decimal of course stores this differently... 10^-exp * significand + let raw = n.to_bits(); + let positive = (raw >> 63) == 0; + let biased_exponent = ((raw >> 52) & 0x7FF) as i32; + let mantissa = raw & 0x000F_FFFF_FFFF_FFFF; + + // Handle the special zero case + if biased_exponent == 0 && mantissa == 0 { + let mut zero = ZERO; + if !positive { + zero.set_sign_negative(true); + } + return Some(zero); + } + + // Get the bits and exponent2 + let mut exponent2 = biased_exponent - 1023; + let mut bits = [ + (mantissa & 0xFFFF_FFFF) as u32, + ((mantissa >> 32) & 0xFFFF_FFFF) as u32, + 0u32, + ]; + if biased_exponent == 0 { + // Denormalized number - correct the exponent + exponent2 += 1; + } else { + // Add extra hidden bit to mantissa + bits[1] |= 0x0010_0000; + } + + // The act of copying a mantissa as integer bits is equivalent to shifting + // left the mantissa 52 bits. The exponent is reduced to compensate. + exponent2 -= 52; + + // Convert to decimal + base2_to_decimal(&mut bits, exponent2, positive, true, remove_excess_bits) +} - // Get the bits and exponent2 - let mut exponent2 = biased_exponent - 127; - let mut bits = [mantissa, 0u32, 0u32]; - if biased_exponent == 0 { - // Denormalized number - correct the exponent - exponent2 += 1; +#[inline] +fn from_f32(n: f32, remove_excess_bits: bool) -> Option { + // Handle the case if it is NaN, Infinity or -Infinity + if !n.is_finite() { + return None; + } + + // It's a shame we can't use a union for this due to it being broken up by bits + // i.e. 1/8/23 (sign, exponent, mantissa) + // See https://en.wikipedia.org/wiki/IEEE_754-1985 + // n = (sign*-1) * 2^exp * mantissa + // Decimal of course stores this differently... 10^-exp * significand + let raw = n.to_bits(); + let positive = (raw >> 31) == 0; + let biased_exponent = ((raw >> 23) & 0xFF) as i32; + let mantissa = raw & 0x007F_FFFF; + + // Handle the special zero case + if biased_exponent == 0 && mantissa == 0 { + let mut zero = ZERO; + if !positive { + zero.set_sign_negative(true); + } + return Some(zero); + } + + // Get the bits and exponent2 + let mut exponent2 = biased_exponent - 127; + let mut bits = [mantissa, 0u32, 0u32]; + if biased_exponent == 0 { + // Denormalized number - correct the exponent + exponent2 += 1; + } else { + // Add extra hidden bit to mantissa + bits[0] |= 0x0080_0000; + } + + // The act of copying a mantissa as integer bits is equivalent to shifting + // left the mantissa 23 bits. The exponent is reduced to compensate. + exponent2 -= 23; + + // Convert to decimal + base2_to_decimal(&mut bits, exponent2, positive, false, remove_excess_bits) +} + +fn base2_to_decimal( + bits: &mut [u32; 3], + exponent2: i32, + positive: bool, + is64: bool, + remove_excess_bits: bool, +) -> Option { + // 2^exponent2 = (10^exponent2)/(5^exponent2) + // = (5^-exponent2)*(10^exponent2) + let mut exponent5 = -exponent2; + let mut exponent10 = exponent2; // Ultimately, we want this for the scale + + while exponent5 > 0 { + // Check to see if the mantissa is divisible by 2 + if bits[0] & 0x1 == 0 { + exponent10 += 1; + exponent5 -= 1; + + // We can divide by 2 without losing precision + let hi_carry = bits[2] & 0x1 == 1; + bits[2] >>= 1; + let mid_carry = bits[1] & 0x1 == 1; + bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 }; + bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 }; } else { - // Add extra hidden bit to mantissa - bits[0] |= 0x0080_0000; - } + // The mantissa is NOT divisible by 2. Therefore the mantissa should + // be multiplied by 5, unless the multiplication overflows. + exponent5 -= 1; - // The act of copying a mantissa as integer bits is equivalent to shifting - // left the mantissa 23 bits. The exponent is reduced to compensate. - exponent2 -= 23; + let mut temp = [bits[0], bits[1], bits[2]]; + if ops::array::mul_by_u32(&mut temp, 5) == 0 { + // Multiplication succeeded without overflow, so copy result back + bits[0] = temp[0]; + bits[1] = temp[1]; + bits[2] = temp[2]; + } else { + // Multiplication by 5 overflows. The mantissa should be divided + // by 2, and therefore will lose significant digits. + exponent10 += 1; - // Convert to decimal - Decimal::base2_to_decimal(&mut bits, exponent2, positive, false) + // Shift right + let hi_carry = bits[2] & 0x1 == 1; + bits[2] >>= 1; + let mid_carry = bits[1] & 0x1 == 1; + bits[1] = (bits[1] >> 1) | if hi_carry { SIGN_MASK } else { 0 }; + bits[0] = (bits[0] >> 1) | if mid_carry { SIGN_MASK } else { 0 }; + } + } } - fn from_f64(n: f64) -> Option { - // Handle the case if it is NaN, Infinity or -Infinity - if !n.is_finite() { + // In order to divide the value by 5, it is best to multiply by 2/10. + // Therefore, exponent10 is decremented, and the mantissa should be multiplied by 2 + while exponent5 < 0 { + if bits[2] & SIGN_MASK == 0 { + // No far left bit, the mantissa can withstand a shift-left without overflowing + exponent10 -= 1; + exponent5 += 1; + ops::array::shl1_internal(bits, 0); + } else { + // The mantissa would overflow if shifted. Therefore it should be + // directly divided by 5. This will lose significant digits, unless + // by chance the mantissa happens to be divisible by 5. + exponent5 += 1; + ops::array::div_by_u32(bits, 5); + } + } + + // At this point, the mantissa has assimilated the exponent5, but + // exponent10 might not be suitable for assignment. exponent10 must be + // in the range [-MAX_PRECISION..0], so the mantissa must be scaled up or + // down appropriately. + while exponent10 > 0 { + // In order to bring exponent10 down to 0, the mantissa should be + // multiplied by 10 to compensate. If the exponent10 is too big, this + // will cause the mantissa to overflow. + if ops::array::mul_by_u32(bits, 10) == 0 { + exponent10 -= 1; + } else { + // Overflowed - return? return None; } + } + + // In order to bring exponent up to -MAX_PRECISION, the mantissa should + // be divided by 10 to compensate. If the exponent10 is too small, this + // will cause the mantissa to underflow and become 0. + while exponent10 < -(MAX_PRECISION_U32 as i32) { + let rem10 = ops::array::div_by_u32(bits, 10); + exponent10 += 1; + if ops::array::is_all_zero(bits) { + // Underflow, unable to keep dividing + exponent10 = 0; + } else if rem10 >= 5 { + ops::array::add_one_internal(bits); + } + } - // It's a shame we can't use a union for this due to it being broken up by bits - // i.e. 1/11/52 (sign, exponent, mantissa) - // See https://en.wikipedia.org/wiki/IEEE_754-1985 - // n = (sign*-1) * 2^exp * mantissa - // Decimal of course stores this differently... 10^-exp * significand - let raw = n.to_bits(); - let positive = (raw >> 63) == 0; - let biased_exponent = ((raw >> 52) & 0x7FF) as i32; - let mantissa = raw & 0x000F_FFFF_FFFF_FFFF; - - // Handle the special zero case - if biased_exponent == 0 && mantissa == 0 { - let mut zero = ZERO; - if !positive { - zero.set_sign_negative(true); + if remove_excess_bits { + // This step is required in order to remove excess bits of precision from the + // end of the bit representation, down to the precision guaranteed by the + // floating point number (see IEEE-754). + if is64 { + // Guaranteed to approx 15/16 dp + while exponent10 < 0 && (bits[2] != 0 || (bits[1] & 0xFFF0_0000) != 0) { + let rem10 = ops::array::div_by_u32(bits, 10); + exponent10 += 1; + if rem10 >= 5 { + ops::array::add_one_internal(bits); + } } - return Some(zero); - } - - // Get the bits and exponent2 - let mut exponent2 = biased_exponent - 1023; - let mut bits = [ - (mantissa & 0xFFFF_FFFF) as u32, - ((mantissa >> 32) & 0xFFFF_FFFF) as u32, - 0u32, - ]; - if biased_exponent == 0 { - // Denormalized number - correct the exponent - exponent2 += 1; } else { - // Add extra hidden bit to mantissa - bits[1] |= 0x0010_0000; + // Guaranteed to about 7/8 dp + while exponent10 < 0 && ((bits[0] & 0xFF00_0000) != 0 || bits[1] != 0 || bits[2] != 0) { + let rem10 = ops::array::div_by_u32(bits, 10); + exponent10 += 1; + if rem10 >= 5 { + ops::array::add_one_internal(bits); + } + } } - // The act of copying a mantissa as integer bits is equivalent to shifting - // left the mantissa 52 bits. The exponent is reduced to compensate. - exponent2 -= 52; - - // Convert to decimal - Decimal::base2_to_decimal(&mut bits, exponent2, positive, true) + // Remove multiples of 10 from the representation + while exponent10 < 0 { + let mut temp = [bits[0], bits[1], bits[2]]; + let remainder = ops::array::div_by_u32(&mut temp, 10); + if remainder == 0 { + exponent10 += 1; + bits[0] = temp[0]; + bits[1] = temp[1]; + bits[2] = temp[2]; + } else { + break; + } + } } + + Some(Decimal { + lo: bits[0], + mid: bits[1], + hi: bits[2], + flags: flags(!positive, -exponent10 as u32), + }) } impl ToPrimitive for Decimal { diff --git a/tests/decimal_tests.rs b/tests/decimal_tests.rs index 5315d50b..84d44a82 100644 --- a/tests/decimal_tests.rs +++ b/tests/decimal_tests.rs @@ -2712,129 +2712,137 @@ fn it_converts_from_u128() { #[test] fn it_converts_from_f32() { - fn from_f32(f: f32) -> Option { - num_traits::FromPrimitive::from_f32(f) + 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 + ); } +} - assert_eq!("1", from_f32(1f32).unwrap().to_string()); - assert_eq!("0", from_f32(0f32).unwrap().to_string()); - assert_eq!("0.12345", from_f32(0.12345f32).unwrap().to_string()); - assert_eq!( - "0.12345678", - from_f32(0.1234567800123456789012345678f32).unwrap().to_string() - ); - assert_eq!( - "0.12345679", - from_f32(0.12345678901234567890123456789f32).unwrap().to_string() - ); - assert_eq!("0", from_f32(0.00000000000000000000000000001f32).unwrap().to_string()); +#[test] +fn it_converts_from_f32_limits() { + use num_traits::FromPrimitive; - assert!(from_f32(f32::NAN).is_none()); - assert!(from_f32(f32::INFINITY).is_none()); + 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 both overflow - assert!(from_f32(f32::MAX).is_none()); - assert!(from_f32(f32::MIN).is_none()); + // 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_try() { - assert_eq!("1", Decimal::try_from(1f32).unwrap().to_string()); - assert_eq!("0", Decimal::try_from(0f32).unwrap().to_string()); - assert_eq!("0.12345", Decimal::try_from(0.12345f32).unwrap().to_string()); - assert_eq!( - "0.12345678", - Decimal::try_from(0.1234567800123456789012345678f32) - .unwrap() - .to_string() - ); - assert_eq!( - "0.12345679", - Decimal::try_from(0.12345678901234567890123456789f32) - .unwrap() - .to_string() - ); - assert_eq!( - "0", - Decimal::try_from(0.00000000000000000000000000001f32) - .unwrap() - .to_string() - ); - - assert!(Decimal::try_from(f32::NAN).is_err()); - assert!(Decimal::try_from(f32::INFINITY).is_err()); +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"), + ]; - // These both overflow - assert!(Decimal::try_from(f32::MAX).is_err()); - assert!(Decimal::try_from(f32::MIN).is_err()); + 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() { - fn from_f64(f: f64) -> Option { - num_traits::FromPrimitive::from_f64(f) + 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 + ); } +} - assert_eq!("1", from_f64(1f64).unwrap().to_string()); - assert_eq!("0", from_f64(0f64).unwrap().to_string()); - assert_eq!("0.12345", from_f64(0.12345f64).unwrap().to_string()); - assert_eq!( - "0.1234567890123456", - from_f64(0.1234567890123456089012345678f64).unwrap().to_string() - ); - assert_eq!( - "0.1234567890123457", - from_f64(0.12345678901234567890123456789f64).unwrap().to_string() - ); - assert_eq!("0", from_f64(0.00000000000000000000000000001f64).unwrap().to_string()); - assert_eq!("0.6927", from_f64(0.6927f64).unwrap().to_string()); - assert_eq!("0.00006927", from_f64(0.00006927f64).unwrap().to_string()); - assert_eq!("0.000000006927", from_f64(0.000000006927f64).unwrap().to_string()); +#[test] +fn it_converts_from_f64_limits() { + use num_traits::FromPrimitive; - assert!(from_f64(f64::NAN).is_none()); - assert!(from_f64(f64::INFINITY).is_none()); + 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 both overflow - assert!(from_f64(f64::MAX).is_none()); - assert!(from_f64(f64::MIN).is_none()); + // 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_try() { - assert_eq!("1", Decimal::try_from(1f64).unwrap().to_string()); - assert_eq!("0", Decimal::try_from(0f64).unwrap().to_string()); - assert_eq!("0.12345", Decimal::try_from(0.12345f64).unwrap().to_string()); - assert_eq!( - "0.1234567890123456", - Decimal::try_from(0.1234567890123456089012345678f64) - .unwrap() - .to_string() - ); - assert_eq!( - "0.1234567890123457", - Decimal::try_from(0.12345678901234567890123456789f64) - .unwrap() - .to_string() - ); - assert_eq!( - "0", - Decimal::try_from(0.00000000000000000000000000001f64) - .unwrap() - .to_string() - ); - assert_eq!("0.6927", Decimal::try_from(0.6927f64).unwrap().to_string()); - assert_eq!("0.00006927", Decimal::try_from(0.00006927f64).unwrap().to_string()); - assert_eq!( - "0.000000006927", - Decimal::try_from(0.000000006927f64).unwrap().to_string() - ); - - assert!(Decimal::try_from(f64::NAN).is_err()); - assert!(Decimal::try_from(f64::INFINITY).is_err()); +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"), + ]; - // These both overflow - assert!(Decimal::try_from(f64::MAX).is_err()); - assert!(Decimal::try_from(f64::MIN).is_err()); + for &(input, expected) in &tests { + assert_eq!( + expected, + Decimal::from_f64_retain(input).unwrap().to_string(), + "from_f64_retain({})", + input + ); + } } #[test]