Comparing Float/Double Values Using == Operator

comparing float/double values using == operator

IBM has a recommendation for comparing two floats, using division rather than subtraction - this makes it easier to select an epsilon that works for all ranges of input.

if (abs(a/b - 1) < epsilon)

As for the value of epsilon, I would use 5.96e-08 as given in this Wikipedia table, or perhaps 2x that value.

Comparing float and double primitives in Java

Take a look at What every computer scientist should know about floating point numbers.

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation....

--- Edit to show what the above quote means ---

You shouldn't ever compare floats or doubles for equality; because, you can't really guarantee that the number you assign to the float or double is exact.

So

 float x = 3.2f;

doesn't result in a float with a value of 3.2. It results in a float with a value of 3.2 plus or minus some very small error. Say 3.19999999997f. Now it should be obvious why the comparison won't work.

To compare floats for equality sanely, you need to check if the value is "close enough" to the same value, like so

float error = 0.000001 * second;
if ((first >= second - error) || (first <= second + error)) {
// close enough that we'll consider the two equal
...
}

Comparing floats and doubles in Java

On the final line, where you compare a==b, the value of a is being implicitly promoted to double before the comparison. So, in effect, what is really being evaluated is (((double)a)==b) which, of course, evaluates true, since b was initialized by casting a as double in the first place.

In other words, the last boolean expression (a==b) asks:

is (some float value converted to a double)==(the same float value converted to a double somewhere else)

and the answer is : yes.

UPDATE: a commenter below made a good point: when a is promoted to double, the stored numeric value does not actually change, even though it appears to because a different value is printed. The issue is with how floating point numbers are stored; without making this answer WAAAY too long and wading in past my depth, what you need to know is that some simple decimal values cannot be perfectly represented in binary floating point form, no matter how many digits you have (just like you can't perfectly represent 1/3 in base 10 without an infinite number of 3s, as in 0.333333...), so when you assign one of these values using float (a 32-bit representation of a floating point number) and then you convert it to a double (a 64-bit representation) and then use println to display the value of that number, you may see more digits.

The println method displays the shortest string of decimal digits that convert to the same float (or double) value the computer sees internally. Although the same numerical value is passed as argument in the first two calls to println in your example, the double type has more precision so println needs to print more digits to show “the shortest string of decimal digits that would convert to (double)99999.99F”. If your example had been 9999.50, both numbers would have printed the same, because binary numbers can represent 1/2 just fine.

NOTE: I am not even close to an expert on floating point numbers; you should check out (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) if you want a deeper understanding of what is going on here.

If operator works properly for floating-point types, why can't we use it for equality testing?

The ==, <, >, <=, >=, and != operators work just fine with floating-point numbers.

You seem to have the premise that some reasonable implementation of < ought to compare (double)0.7f equal to 0.7. This is not the case. If you cast 0.7f to a double, you get 0x1.666666p-1. However, 0.7 is equal to 0x1.6666666666666p-1. These are not numerically equal; in fact, (double)0.7f is considerably smaller than 0.7 --- it would be ridiculous for them to compare equal.

When working with floating-point numbers, it is important to remember that they are floating-point numbers, rather than real numbers or rational numbers or any other such thing. You have to take into account their properties and not the properties everyone wants them to have. Do this and you automatically avoid most of the commonly-cited "pitfalls" of working with floating-point numbers.

Comparison of double and float - Implicit casting

In a C implementation that conforms to the C standard, f == (double) f evaluates to true for all float values of f other than NaNs. (For a NaN, f == f is false.) This is true because, in f == (double) f, the left operand is a float, so it is automatically converted to double, and the expression is then equivalent to (double) f == (double) f, and so is inherently true.

The C standard allows implementations to evaluate floating-point expressions with more precision than the nominal types of the operands. However, excess precision would have no effect on cast operators (which are required to discard excess precision) or the == operator. So (double) f == (double) f is not affected by this, and its computed value is the same as its mathematical value.

You might be interested in the result of f == (float) (double) f. In this, since both operands of == have type float, there is no automatic conversion to double. You could ask whether the cast conversion to double introduces some change, and then converting back to float could produce a different value. It cannot.

To see that it cannot, consider if f is infinity. Then (double) f is infinity, and so is (float) (double) f, so the result is a comparison of infinity to infinity, which evaluates to true. (This also holds for negative infinity.) If f is not infinity or a NaN, it is a finite value.

Per C 2018 6.2.5 10, “The set of values of the type float is a subset of the set of values of the type double;…” Therefore, every value representable in float is representable in double, so the conversion to double does not change the value, and neither does the conversion back to float. Therefore, f == (float) (double) f evaluates to true for all float values of f other than NaN.

Note that while you cannot determine whether two NaNs are identical using ==, you could compare the bytes in their representations using memcmp. In this case, conversion to double and back to float is not required to preserve any information in the NaN object other than that it is a NaN; any payload information may be lost.

What is precision of double/float comparison (relation operator) with integral types?

The precision of a IEEE 754 single-precision floating point is between 6 and 9 significant decimal digits (source).

For double-precision you get between 15 and 17 significant decimal digits.

What's the best way to compare Double and Int?

You really can't compare floating point and integral values in a naive way; particularly, since there's the classic floating point representation challenges. What you can do is subtract one from the other and see if the difference between them is less than some precision you care about, like so:

int iValue = 0;
double dValue = 0.0;

var diff = Math.Abs(dvalue - iValue);
if( diff < 0.0000001 ) // need some min threshold to compare floating points
return true; // items equal

You really have to define for yourself what equality means to you. For example, you may want a floating point value to round towards the nearest integer, so that 3.999999981 will be "equal" to 4. Or you may want to truncate the value, so it would effectively be 3. It all depends on what you're trying to achieve.

EDIT: Note that i chose 0.0000001 as an example threshold value ... you need to decide for yourself what precision is sufficient for comparison. Just realize you need to be within the normal representational bounds of double which I believe is defined as Double.Epsilon.



Related Topics



Leave a reply



Submit