FloatingPointAssertionWithinEpsilon
This fuzzy equality check is using a tolerance less than the gap to the next number. You may want a less restrictive tolerance, or to assert equality.
Severity WARNING
Tags Simplification
Has Fix? REQUIRES_HUMAN_ATTENTION
The problem
Both JUnit and Truth allow for asserting equality of floating point numbers with
an absolute tolerance. For example, the following statements are equivalent,

double EPSILON = 1 e - 20 ;
assertThat ( actualValue ). isWithin ( EPSILON ). of ( Math . PI );
assertEquals ( Math . PI , actualValue , EPSILON );

Whatâ€™s not immediately obvious is that both of these assertions are checking
exact equality between `Math.PI`

and `actualValue`

, because the next `double`

after `Math.PI`

is `Math.PI + 4.44e-16`

.

This means that using the same tolerance to compare several floating point
values with different magnitude can be prone to error,

float TOLERANCE = 1 e - 5 f ;
assertThat ( pressure ). isWithin ( TOLERANCE ). of ( 1 f ); // GOOD
assertThat ( pressure ). isWithin ( TOLERANCE ). of ( 10 f ); // GOOD
assertThat ( pressure ). isWithin ( TOLERANCE ). of ( 100 f ); // BAD -- misleading equals check

A larger tolerance should be used if the goal of the test is to allow for some
floating point errors, or, if not, `isEqualTo`

makes the intention more clear.

Suppression
Suppress false positives by adding the suppression annotation `@SuppressWarnings("FloatingPointAssertionWithinEpsilon")`

to the enclosing element.

Positive examples
FloatingPointAssertionWithinEpsilonPositiveCases.java

/*
* Copyright 2018 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com . google . errorprone . bugpatterns . testdata ;
import static com . google . common . truth . Truth . assertThat ;
import static org . junit . Assert . assertEquals ;
/**
* Positive test cases for FloatingPointAssertionWithinEpsilon check.
*
* @author ghm@google.com (Graeme Morgan)
*/
final class FloatingPointAssertionWithinEpsilonPositiveCases {
private static final float TOLERANCE = 1 e - 10 f ;
private static final double TOLERANCE2 = 1 e - 20 f ;
private static final float VALUE = 1 ;
public void testFloat () {
// BUG: Diagnostic contains: 6.0e-08
assertThat ( 1.0f ). isWithin ( 1 e - 20 f ). of ( 1.0f );
// BUG: Diagnostic contains: 6.0e-08
assertThat ( 1 f ). isWithin ( TOLERANCE ). of ( VALUE );
// BUG: Diagnostic contains: 1.0e+03
assertThat ( 1 e10f ). isWithin ( 1 ). of ( 1 e10f );
// BUG: Diagnostic contains: 1.2e-07
assertThat ( 1 f ). isNotWithin ( 1 e - 10 f ). of ( 2 );
// BUG: Diagnostic contains: 6.0e-08
assertEquals ( 1 f , 1 f , TOLERANCE );
// BUG: Diagnostic contains: 6.0e-08
assertEquals ( "equal!" , 1 f , 1 f , TOLERANCE );
}
public void testDouble () {
// BUG: Diagnostic contains: 1.1e-16
assertThat ( 1.0 ). isWithin ( 1 e - 20 ). of ( 1.0 );
// BUG: Diagnostic contains: 1.1e-16
assertThat ( 1.0 ). isWithin ( TOLERANCE2 ). of ( 1.0f );
// BUG: Diagnostic contains: 1.1e-16
assertThat ( 1.0 ). isWithin ( TOLERANCE2 ). of ( 1 );
// BUG: Diagnostic contains: 1.6e+04
assertThat ( 1 e20 ). isWithin ( 1 ). of ( 1 e20 );
// BUG: Diagnostic contains: 1.4e-17
assertThat ( 0.1 ). isNotWithin ( TOLERANCE2 ). of ( 0.1f );
// BUG: Diagnostic contains: 1.1e-16
assertEquals ( 1.0 , 1.0 , TOLERANCE2 );
// BUG: Diagnostic contains: 1.1e-16
assertEquals ( "equal!" , 1.0 , 1.0 , TOLERANCE2 );
}
}

FloatingPointAssertionWithinEpsilonPositiveCases_expected.java

/*
* Copyright 2018 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com . google . errorprone . bugpatterns . testdata ;
import static com . google . common . truth . Truth . assertThat ;
import static org . junit . Assert . assertEquals ;
/**
* Expected refactoring output for FloatingPointAssertionWithinEpsilon bugpattern.
*
* @author ghm@google.com (Graeme Morgan)
*/
final class FloatingPointAssertionWithinEpsilonPositiveCases {
private static final float TOLERANCE = 1 e - 10 f ;
private static final double TOLERANCE2 = 1 e - 20 f ;
private static final float VALUE = 1 ;
public void testFloat () {
assertThat ( 1.0f ). isEqualTo ( 1.0f );
assertThat ( 1 f ). isEqualTo ( VALUE );
assertThat ( 1 e10f ). isEqualTo ( 1 e10f );
assertThat ( 1 f ). isNotEqualTo ( 2 f );
assertEquals ( 1 f , 1 f , 0 );
assertEquals ( "equal!" , 1 f , 1 f , 0 );
}
public void testDouble () {
assertThat ( 1.0 ). isEqualTo ( 1.0 );
assertThat ( 1.0 ). isEqualTo ( 1.0 );
assertThat ( 1.0 ). isEqualTo ( 1 d );
assertThat ( 1 e20 ). isEqualTo ( 1 e20 );
assertThat ( 0.1 ). isNotEqualTo (( double ) 0.1f );
assertEquals ( 1.0 , 1.0 , 0 );
assertEquals ( "equal!" , 1.0 , 1.0 , 0 );
}
}

Negative examples
FloatingPointAssertionWithinEpsilonNegativeCases.java

/*
* Copyright 2018 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com . google . errorprone . bugpatterns . testdata ;
import static com . google . common . truth . Truth . assertThat ;
import static org . junit . Assert . assertEquals ;
/**
* Negative test cases for FloatingPointAssertionWithinEpsilon check.
*
* @author ghm@google.com (Graeme Morgan)
*/
final class FloatingPointAssertionWithinEpsilonNegativeCases {
private static final float TOLERANCE = 1 e - 5 f ;
private static final double TOLERANCE2 = 1 e - 10 f ;
private static final float VALUE = 1 ;
public void testFloat () {
String test = Boolean . TRUE . toString ();
assertThat ( 1.0f ). isWithin ( 1 e - 5 f ). of ( 1.0f );
assertThat ( 1 f ). isWithin ( TOLERANCE ). of ( VALUE );
assertThat ( 1 f ). isWithin ( 1 ). of ( 1 );
assertThat ( 1 f ). isNotWithin ( 0 ). of ( 2 f );
assertThat ( 1 f ). isNotWithin (. 5 f ). of ( 2 f );
assertEquals ( 1 f , 1 f , TOLERANCE );
}
public void testDouble () {
String test = Boolean . TRUE . toString ();
assertThat ( 1.0 ). isWithin ( 1 e - 10 ). of ( 1.0 );
assertThat ( 1.0 ). isWithin ( TOLERANCE2 ). of ( 1 f );
assertThat ( 1.0 ). isWithin ( TOLERANCE2 ). of ( 1 );
assertEquals ( 1.0 , 1.0 , TOLERANCE );
}
public void testZeroCases () {
assertThat ( 1.0 ). isWithin ( 0.0 ). of ( 1.0 );
assertThat ( 1 f ). isWithin ( 0 f ). of ( 1 f );
assertThat ( 1 f ). isWithin ( 0 ). of ( 1 f );
assertEquals ( 1 f , 1 f , 0 f );
}
}