Test for Floating Point Equality. (Fe_Floating_Point_Equality)

Test for floating point equality. (FE_FLOATING_POINT_EQUALITY)

Problem 1:

For the FE_FLOATING_POINT_EQUALITY issue, you should not be comparing two float values directly with the == operator, since due to tiny rounding errors, the values might be semantically "equal" for your application even if the condition value1 == value2 does not hold true.

In order to fix this, modify your code as follows:

private boolean equals(final Quantity other) {
return (Math.abs(this.mAmount - convertedAmount(other)) < EPSILON);
}

Where EPSILON is a constant that you should define in your code, and represents small differences that are acceptable to your application, e.g. .0000001.

Problem 2:

For the EQ_COMPARETO_USE_OBJECT_EQUALS issue: It is strongly recommended that wherever x.compareTo(y) returns zero, x.equals(y) should be true. In your code you have implemented compareTo, but you have not overriden equals, so you are inheriting the implementation of equals from Object, and the above condition is not met.

In order to fix this, override equals (and perhaps hashCode) in your class, so that when x.compareTo(y) returns 0, then x.equals(y) will return true.

Java equality of floats and doubles

When you write 4.4f, that results in the closest value representable as a float to the true value 4.4.

When you write 4.4, that results in the closest value representable as a double to the value 4.4.

When you write 4.4f == 4.4, that tests if the closest value representable as a float is still the closest value representable as a double to 4.4, which is false; double has more precision, and neither float nor double can represent 4.4 exactly.

Both float and double can represent 4.5 exactly, however; since they're using binary fractions, and 4.5 is an exact binary fraction, that works fine.

Floating point comparison without any tolerance

Please note that there is no such thing as exactness in floating points due to the fundamental limitation of the binary code. You cannot express decimal in binary exactly, instead halves, quarters (and other ratios with denominator being a power of two) are used to express values that are 'close enough' within some acceptable tolerance. You cannot remove this tolerance and compare exact values, because otherwise you cannot express decimals in binary.

Useful link.

UPDATE:
Just found on the stackoverflow this great response, so that I don't have to write it all over. Read this and maybe you will consider using BigDecimal for the task at hand.

oh no not again - comparing two bowls of petunias - sorry - floats, for equality

There is no universal standard for epsilon because it strongly depends on what you are comparing and for what purpose. Every time you test for near equality of two floating-point numbers you need to consider two things:

  • the absolute value of those numbers
  • the kind of quantity they represent

For example PI is widely known to be "around 3.14", and that's good enough for most engineering applications but in Mathematics, or in spectral analysis (Astronomy) you need much higher precision.

Even withing the same domain the absolute values of numbers you compare will influence your choice of epsilon. Comparing circumference of Earth in kilometers to 40_000.00 vs distance to the Moon in meters to 384_400_000.00 have completely different tolerance of errors.

Does the .equals() method of the double wrapper class work for finding equality of floating point numbers?

You need to fully understand the reason for why == comparison is a bad idea. Without understanding, you're just fumbling in the dark.

Let's talk about how computers (and doubles) work.

Imagine you enter a room; it has 3 lightswitches, otherwise it is bare. You will enter the room, you can fiddle with the switches, but then you have to leave. I enter the room later and can look at the switches.

How much information can you convey?

The answer is: You can convey 8 different states: DDD, DDU, DUD, DUU, UDD, UDU, UUD, and UUU. That's it.

Computers work exactly like this when they store a double. Except instead of 3 switches, you get 64 switches. That means 2^64 different states you can convey with a single double, and that's a ton of states: That's a 19 digit number.

But it's still a finite amount of states, and that's problematic: There are an infinite amount of numbers between 0 and 1. Let alone between -infinity and +infinity, which double dares to cover. How do you store one of an infinite infinity of choices when you only get to represent 2^64 states? That 19-digit number starts to look pretty small when it's tasked to differentiate from an infinite infinity of possibilities, doesn't it?

The answer, of course, is that this is completely impossible.

So doubles don't actually work like that. Instead, someone took some effort and hung up a gigantic numerline, from minus infinite to plus infinite, in a big room, and threw 2^64 darts at this line. The numbers they landed on are the 'blessed numbers' - these are representable by a double value. That does mean there are an infinite amount of numbers between any 2 darts that therefore are not representable. The darts aren't quite random: The closer you are to 0, the denser the darts. Once you get beyond about 2^52 or so, the distance between 2 darts exceeds 1.0 even.

Here's a trivial example of a non-representable number: 0.3. Amazing, isn't it? Something that simple. It means a computer literally cannot calculate 0.1 + 0.2 using double. So what happens when you try? The rules state that the result of any calculation is always silently rounded to the nearest blessed number.

And therein lies the rub: You can run the math:

double x = 0.1 + 0.2;

and later do:

double y = 0.9 - 0.8 + 0.15 + 0.05;

and us humans would immediately notice that x and y are naturally identical. But not so for computers - because of that silent rounding to the nearest blessed number, it's possible that x is 0.29999999999999999785, and y is 0.300000000000000000012.

Thus we get to four crucial aspects when using double (or float which is just about worse in every fashion, don't ever use those):

  • If you need absolute precision, don't use them at all.
  • When printing them, always round them down. System.out.println does this out of the box, but you should really use .printf("%.5f") or similar: Pick the # of digits you need.
  • Be aware that the errors will compound, and it gets worse as you are further away from 1.0.
  • Do not ever compare with ==, instead always use a delta-compare: The notion of "lets consider the 2 numbers equal if they are within 0.0000000001 of each other".

There is no universal magic delta value; it depends on your precision needs, how far you away from 1.0, etc. Therefore, just asking the computer: Hey, just figure this stuff out I just wanna know if these 2 doubles are equal is impossible. The only definition available that doesn't require your input as to 'how close' they can be, is the notion of sheer perfection: They are equal only if they are precisely identical. This definition would fail you in that trivial example above. It makes not one iota of difference if you use Double.equals instead of double == double, or any other utility class for that matter.

So, no, Double.equals is not suitable. You will have to compare Math.abs(d1 - d2) < epsilon, where epsilon is your choice. Mostly, if equality matters at all you're already doing it wrong and shouldn't be using double in the first place.

NB: When representing money, you don't want unpredictable rounding, so never use doubles for these. Instead figure out what the atomic banking unit is (dollarcents, eurocents, yen, satoshis for bitcoin, etc), and store that as a long. You store $4.52 and long x = 452;, not as double x = 4.52;.

create equal method for Java class to compare double or int values

As your lecturer said, comparing double does not simply use equals operator. For example, you can try that 1 doesn't equal with 1.000.

Instead we often compare double by using delta between two values. If delta is relatively small so those value will equal.

public static final double EPSILON = 0.0000000001;
public boolean compare(double a, double b) {
return Math.abs(a-b) < EPSILON;
}

What is wrong with my equals method?

You're not performing a like-for-like comparison on the real and imaginary components of your complex number.

This would be my implementation:

public boolean equals(Object o) {
if (o instanceof ComplexNum) {
ComplexNum other = (ComplexNum)o;
return (this.real == other.real) && (this.imag == other.imag);
} else {
return false;
}
}

For those arguing that floating point comparison should never use precise tests, IMHO that should be in another method. Java requires that objects that are .equal() have the same .hashCode(), and that would be very hard to arrange with an epsilon comparison.

Because of the above, you will need this, too (other implementations are possible, and the below assumes that your components are double)

int hashCode() {
return Double(this.real).hashCode() ^ Double(this.imag).hashCode();
}

NB: A test for o == null is not necessary in .equals(), because null is not an instanceof ComplexNum.

EDIT for completely strict conformance with the way that .equals() works on Float or Double types (particularly for NaN values) you might want to use this line instead which replaces == with a per-component application of .equals()

return Double(this.real).equals(other.real) &&
Double(this.imag).equals(other.imag);


Related Topics



Leave a reply



Submit