1 // Copyright 2014 Steve Klabnik, Valerii Hiora, Oliver Mader
2 // Copyright 2015 Carl Lerche, Oliver Mader, Alex Crichton, Graham Dennis,
3 // Tamir Duberstein, Robin Gloster
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use num
::{Float, Zero}
;
12 use std
::fmt
::{self, Display, Debug, Formatter}
;
13 use {success, Matcher, MatchResult}
;
15 /// Compares two floating point values for equality.
17 /// The comparison is based on a relative error metric and uses special
18 /// fallbacks for certain edge cases like very small numbers. The exact
19 /// algorithm is described [here](http://floating-point-gui.de/errors/comparison/).
20 pub struct CloseTo
<T
> {
25 impl<T
: Debug
> Display
for CloseTo
<T
> {
26 fn fmt(&self, f
: &mut Formatter
) -> fmt
::Result
{
31 impl<T
: Float
+ Zero
+ Debug
> Matcher
<T
> for CloseTo
<T
> {
32 fn matches(&self, actual
: T
) -> MatchResult
{
33 let a
= self.expected
.abs();
36 let d
= (a
- b
).abs();
39 // shortcut, handles infinities
41 // a or b is zero or both are extremely close to it
42 // relative error is less meaningful here
43 || ((a
== Zero
::zero() || b
== Zero
::zero() || d
< Float
::min_positive_value()) &&
44 d
< (self.epsilon
* Float
::min_positive_value()))
46 || d
/ (a
+ b
).min(Float
::max_value()) < self.epsilon
;
51 Err(format
!("was {:?}", actual
))
56 pub fn close_to
<T
>(expected
: T
, epsilon
: T
) -> CloseTo
<T
> {
66 use {assert_that,is,not,close_to}
;
69 fn equality_of_floats() {
70 assert_that(1.0f64, is(close_to(1.0, 0.00001)));
71 assert_that(1e
-40f32, is(close_to(0.0, 0.01)));
72 assert_that(1e
-40f32, is(not(close_to(0.0, 0.000001))));
73 assert_that(2.0, is(not(close_to(1.0f64, 0.00001))));
77 fn it_can_handle_infinity() {
78 assert_that(f64::INFINITY
, is(close_to(f64::INFINITY
, 0.00001)));
82 fn it_can_handle_nan() {
83 assert_that(f64::NAN
, is(not(close_to(f64::NAN
, 0.00001))));