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
How to Read Input Character-By-Character in Java
Spring Autowiring Class VS. Interface
Javac Not Working in Windows Command Prompt
Java - Convert Image to Base64
Getting an Attribute Value in Xml Element
Can Constructor Return a Null Object
Java - Swing Listen an Action in a Text Field of a Form
Gradle to Execute Java Class (Without Modifying Build.Gradle)
How to Enumerate Ip Addresses of All Enabled Nic Cards from Java
Java Date Year Calculation Is Off by Year for Two Days
Log4J: How to Use Socketappender
How to Wait Until an Element Is Present in Selenium
Converting an Int to a Binary String Representation in Java
Problem with Assigning an Array to Other Array in Java
How Can My Java Program Store Files Inside of Its .Jar File
Access Restriction: Is Not Accessible Due to Restriction on Required Library ..\Jre\Lib\Rt.Jar
How to Tell Jackson to Ignore a Property for Which I Don't Have Control Over the Source Code