### Use ApproxEq again in ApproxEqCairo. This lets us compare big numbers, too.

```Those big numbers won't be very useful since Cairo can't represent
them, but it lets our comparisons of f64 be "correct" even for large
numbers.```
parent 28a457b5
 use float_cmp::ApproxEq; // The following are copied from cairo/src/{cairo-fixed-private.h, cairo-fixed-type-private.h} // The following are copied from cairo/src/{cairo-fixed-private.h, cairo-fixed-type-private.h} const CAIRO_FIXED_FRAC_BITS: u64 = 8; const CAIRO_FIXED_FRAC_BITS: u64 = 8; ... @@ -46,16 +48,17 @@ impl FixedEqCairo for f64 { ... @@ -46,16 +48,17 @@ impl FixedEqCairo for f64 { /// /// /// Note that this trait is reliable even if the given numbers are /// Note that this trait is reliable even if the given numbers are /// outside of the range that Cairo's fixed-point numbers can /// outside of the range that Cairo's fixed-point numbers can /// represent. /// represent. In that case, we check for the absolute difference, pub trait ApproxEqCairo { /// and finally allow a difference of 1 unit-in-the-last-place (ULP) /// for very large f64 values. pub trait ApproxEqCairo: ApproxEq { fn approx_eq_cairo(&self, other: &Self) -> bool; fn approx_eq_cairo(&self, other: &Self) -> bool; } } impl ApproxEqCairo for f64 { impl ApproxEqCairo for f64 { fn approx_eq_cairo(&self, other: &f64) -> bool { fn approx_eq_cairo(&self, other: &f64) -> bool { let abs_diff = (self - other).abs(); let cairo_smallest_fraction = 1.0 / f64::from(1 << CAIRO_FIXED_FRAC_BITS); let cairo_smallest_fraction = 1.0 / f64::from(1 << CAIRO_FIXED_FRAC_BITS); abs_diff < cairo_smallest_fraction self.approx_eq(other, cairo_smallest_fraction, 1) } } } } ... @@ -74,7 +77,45 @@ mod tests { ... @@ -74,7 +77,45 @@ mod tests { #[test] #[test] fn numbers_approx_equal() { fn numbers_approx_equal() { assert!(0.0_f64.approx_eq_cairo(&0.001953125_f64)); // 1/512 // 0 == 1/256 - cairo can represent it, so not equal assert!(1.0_f64.approx_eq_cairo(&1.001953125_f64)); // 1 + 1/512 assert!(!0.0_f64.approx_eq_cairo(&0.00390635_f64)); // 1 == 1 + 1/256 - cairo can represent it, so not equal assert!(!1.0_f64.approx_eq_cairo(&1.00390635_f64)); // 0 == 1/256 - cairo can represent it, so not equal assert!(!0.0_f64.approx_eq_cairo(&-0.00390635_f64)); // 1 == 1 - 1/256 - cairo can represent it, so not equal assert!(!1.0_f64.approx_eq_cairo(&0.99609365_f64)); // 0 == 1/512 - cairo approximates to 0, so equal assert!(0.0_f64.approx_eq_cairo(&0.001953125_f64)); // 1 == 1 + 1/512 - cairo approximates to 1, so equal assert!(1.0_f64.approx_eq_cairo(&1.001953125_f64)); // 0 == -1/512 - cairo approximates to 0, so equal assert!(0.0_f64.approx_eq_cairo(&-0.001953125_f64)); // 1 == 1 - 1/512 - cairo approximates to 1, so equal assert!(1.0_f64.approx_eq_cairo(&0.998046875_f64)); // This is 2^53 compared to (2^53 + 2). When represented as // f64, they are 1 unit-in-the-last-place (ULP) away from each // other, since the mantissa has 53 bits (52 bits plus 1 // "hidden" bit). The first number is an exact double, and // the second one is the next biggest double. We consider a // difference of 1 ULP to mean that numbers are "equal", to // account for slight imprecision in floating-point // calculations. Most of the time, for small values, we will // be using the cairo_smallest_fraction from the // implementation of approx_eq_cairo() above. For large // values, we want the ULPs. // // In the second assertion, we compare 2^53 with (2^53 + 4). Those are // 2 ULPs away, and we don't consider them equal. assert!(9_007_199_254_740_992.0.approx_eq_cairo(&9_007_199_254_740_994.0)); assert!(!9_007_199_254_740_992.0.approx_eq_cairo(&9_007_199_254_740_996.0)); } } } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment