I'm porting a Java app to C# that makes use of
double x;
if (x == null) blah blah
doubles in .Net aren't nullable so this needs to be changed. No big deal.
It is poor practice to test floating point numbers for equality. So if I initialize a variable
double d = double.MaxValue;
and later want to test it
if (d == double.MaxValue) blah blah
is this valid? Am I guaranteed that the test will always return true, assuming d has not been given a new value?
Double in Java is nullable, since it's a class and therefore a reference type, which boxes a double. You should use Nullable<double> or double? in C# (both are technically the same). Nullable<T> is a generic "box wrapper" for .NET value types.
There's nothing wrong with checking floating point values against some constant that you assigned before.
The smelly part about floats and equality comparison is trying to compare computed values or a computed value and a constant - that will likely fail due to rounding errors.
Related
I am confused on a few things regarding using double.
If i were to initialize 2 doubles with the same literal, would == always evaluate to true? for example, if following outputs true but i don't know if this is by chance:
double a = .1d;
double b = .1d;
System.out.println(a==b);
I get the same result when using Double instead of double:
Double a = .1d;
Double b = .1d;
System.out.println(a.equals(b));
According to Double documentation, equals() return true if doubleValue() are equal.
So the question is, is "==" for double and "equals()" for Double guaranteed to evaluate to true for 2 variables initialized using the same literal?
When would they evaluate to false? Is this when arithmetic operations are involved?
Thanks
In general == is an operator which checks for equality. Object variables are references so it checks for reference or address equality. In the case of primitive data types representing values in the memory that also means that it checks for value equality.
The method equals(~) checks for value or content equality. You do not use it for primitive data types but for Objects.
That is also the case for double and Double. The problem which is arising with doubles is the mismatch of the values induced by rounding errors.
Some arithmetic operations may handle rounding differently so you might get false for value equality even if you think it should be equal.
It should be stated that even if the rounding rules are a bit inconsistent arithmetic operations are deterministic so that inconsistency can be handled.
I am an experienced php developer just starting to learn Java. I am following some Lynda courses at the moment and I'm still really early stages. I'm writing sample programs that ask for user input and do simple calculation and stuff.
Yesterday I came across this situation:
double result = 1 / 2;
With my caveman brain I would think result == 0.5, but no, not in Java. Apparantly 1 / 2 == 0.0. Yes, I know that if I change one of the operands to a double the result would also be a double.
This scares me actually. I can't help but think that this is very broken. It is very naive to think that an integer division results in an integer. I think it is even rarely the case.
But, as Java is very widely used and searching for 'why is java's division broken?' doesn't yield any results, I am probably wrong.
My questions are:
Why does division behave like this?
Where else can I expect to find such magic/voodoo/unexpected behaviour?
Java is a strongly typed language so you should be aware of the types of the values in expressions. If not...
1 is an int (as 2), so 1/2 is the integer division of 1 and 2, so the result is 0 as an int. Then the result is converted to a corresponding double value, so 0.0.
Integer division is different than float division, as in math (natural numbers division is different than real numbers division).
You are thinking like a PHP developer; PHP is dynamically typed language. This means that types are deduced at run-time, so a fraction cannot logically produce a whole number, thus a double (or float) is implied from the division operation.
Java, C, C++, C# and many other languages are strongly typed languages, so when an integer is divided by an integer you get an integer back, 100/50 gives me back 2, just like 100/45 gives me 2, because 100/45 is actually 2.2222..., truncate the decimal to get a whole number (integer division) and you get 2.
In a strongly typed language, if you want a result to be what you expect, you need to be explicit (or implicit), which is why having one of your parameters in your division operation be a double or float will result in floating point division (which gives back fractions).
So in Java, you could do one of the following to get a fractional number:
double result = 1.0 / 2;
double result = 1f / 2;
double result = (float)1 / 2;
Going from a loosely typed, dynamic language to a strongly typed, static language can be jarring, but there's no need to be scared. Just understand that you have to take extra care with validation beyond input, you also have to validate types.
Going from PHP to Java, you should know you can not do something like this:
$result = "2.0";
$result = "1.0" / $result;
echo $result * 3;
In PHP, this would produce the output 1.5 (since (1/2)*3 == 1.5), but in Java,
String result = "2.0";
result = "1.0" / result;
System.out.println(result * 1.5);
This will result in an error because you cannot divide a string (it's not a number).
Hope that can help.
I'm by no means a professional on this, but I think it's because of how the operators are defined to do integer arithmetic. Java uses integer division in order to compute the result because it sees that both are integers. It takes as inputs to this "division" method two ints, and the division operator is overloaded, and performs this integer division. If this were not the case, then Java would have to perform a cast in the overloaded method to a double each time, which is in essence useless if you can perform the cast prior anyways.
If you try it with c++, you will see the result is the same.
The reason is that before assigning the value to the variable, you should calculate it. The numbers you typed (1 and 2) are integers, so their memory allocation should be as integers. Then, the division should done according to integers. After that it will cast it to double, which gives 0.0.
Why does division behave like this?
Because the language specification defines it that way.
Where else can I expect to find such magic/voodoo/unexpected behaviour?
Since you're basically calling "magic/voodoo" something which is perfectly defined in the language specification, the answer is "everywhere".
So the question is actually why there was this design decision in Java. From my point of view, int division resulting in int is a perfectly sound design decision for a strongly typed language. Pure int arithmetic is used very often, so would an int division result in float or double, you'd need a lot of rounding which would not be good.
package demo;
public class ChocolatesPurchased
{
public static void main(String args[])
{
float p = 3;
float cost = 2.5f;
p *= cost;
System.out.println(p);
}
}
I have this question,
vectors in java only accept objects right? but this piece of code compiles just fine
Vector myv=new Vector();
myv.addElement(1);
myv.addElement(1);
does it encapsulate it as an object of Integer? and if it does, why do this statement
System.out.println(myv.elementAt(0)==myv.elementAt(1));
gives true ?!!! they're supposed to be two distinct objects...?
at the same time this statement throws an error, which ensures that the element is an object.
int x=myv.elementAt(0);
can someone explain this for me? thank you.
The 1 is auto-boxed into an Integer.
To learn more about Autoboxing and -unboxing, see Oracle's Docu: https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
On why they are the same: Autoboxing ints to Integers uses a cache. For numbers < 128 (I think) the same Integer-Object will be returned each time instead of a new one being created. So your code essentially inserts the same object twice into the Vector, and for this reason the identity comparison using == returns true.
As you don't use generics with your Vector, myv.elementAt(0) will return an Object, which cannot be cast to an int. If you used generics, i.e. Vector<Integer> myv = new Vector<>(), then elementAt would return an Integer which would be auto-unboxed to an int.
That works because java auto boxes and auto unboxes these type for you.
But note that this doesn't work for sure in every scenario.
Let's take this example:
Integer i = 1234;
Integer z = 1234;
System.out.println("i: "+i);
System.out.println("z: "+z);
System.out.println("== : "+(i == z));
System.out.println("equals: "+i.equals(z));
It will produce the following output:
i: 1234
z: 1234
== : false
equals: true
DEMO
In fact, from this answer you can see that it works only for integers between -128 and +127
In fact, this behaves as expected:
Integer i = 123;
Integer z = 123;
System.out.println("i: "+i);
System.out.println("z: "+z);
System.out.println("== : "+(i == z));
System.out.println("equals: "+i.equals(z));
and produces:
i: 123
z: 123
== : true
equals: true
DEMO
Here is something pretty funny about Java, it caches integers between -128 and 127 (for auto-/un-boxing) and any reference to integers in that range all refer to the same object (since == here is comparing Objects). This can cause quite a few bugs when people don't thing through the == method comparing Objects, rather than values.
So you will get true for comparing "integers" (autoboxed) between -128 - 127. If you do the same thing with 128, it'll say false.
Check it out:
import java.util.Vector;
public class Vect {
public static void main(String[] args) {
Vector v = new Vector();
v.addElement(127);
v.addElement(127);
v.addElement(128);
v.addElement(128);
System.out.println(v.elementAt(0) == v.elementAt(1));
System.out.println(v.elementAt(2) == v.elementAt(3));
}
}
Will give you:
$ java Vect
true
false
This is called autoboxing. When the Java compiler encounters an integer, float or double value in a place where an object is expected, it automatically creates a wrapper object.
The code generated by the compiler for your code is equivalent to
Vector myv=new Vector();
myv.addElement(Integer.valueOf(1));
myv.addElement(Integer.valueOf(1));
The valueOf() method caches Integer instances for the values from -128 to 127 (IIRC), with the result that both values will be replaced by the same object.
Try the same with a lager value, like 1000. Then the objects will be different.
This is a feature of compiled code and auto-boxing.
Generics in Java are a compile-time issue. javac uses them to check that you use the types correctly, but the compiled byte code that's produced doesn't know anything about the generic types. Generics are implemented with type erasure in Java was mainly for backward compatibility. (That's also why raw types still exist in Java.)
It means that an Vector<E> will look like a plain, raw Vector at runtime - it's just a plain Vector that contains objects. Since primitives are not objects, you can't store primitive types in such an Vector.
There are wrapper classes for each of the primitive types (int -> Integer, long -> Long, short -> Short, boolean --> Boolean, etc.) so is possible to make it such that a Vector<int> would use auto-boxing to store ints in Integer objects, which could be stored in a Vector. ...but the designers of the Java language didn't decide to take auto-boxing that far.
Java's Vector is a generics, it means it can accept any kind of data to store. You have to specify the type of data to hold with a syntax like Vector<String>. Replace String for the kind of object you want the Vector to hold.
The reason that it gives true is because it is autoboxed into the Integer class automatically; when compares two Integers, it does the same way as the built-in type int.
EDIT: The autoboxing comparation works with the int values in the range [-128;+127].
What is the most performant way to check double values for equality.
I understand that
double a = 0.00023d;
double b = 0.00029d;
boolean eq = (a == b);
is slow.
So I'm using
double epsilon = 0.00000001d;
eq = Math.abs(a - b) < epsilon;
The problem is that Infinitest is complaning about tests taking too much time. It's not a big deal (1 sec top), but it made me curious.
Additional info
a is hard coded since it's the expected value, b is computed by
// fyi: current = int, max = int
public double getStatus()
{
double value = 0.0;
if (current != 0 && max != 0)
value = ((double) current) / max;
return value;
}
Update
java.lang.Double does it that way
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
so one could assume that is the best practice.
JUnit has a method of checking a Double for 'equality' with a given delta:
Assert.assertEquals(0.00023d, 0.00029d, 0.0001d);
See this API documentation.
As noted in the comments, JUnit actually most likely is slower than comparing manually with a given delta. JUnit first does a Double.compare(expected, actual) followed (if not equal) by a Math.abs(expected - actual) <= delta.
Hopefully this answer still is useful for people not aware that JUnit actually provides a way for inexact Double equality testing.
Actually, comparing two float/double values for equality is a bad practice in itself, because floating point numbers suffer from rounding errors.
Two numbers which would be equal in symbolic maths may be different to the computer, depending on how they are computed.
The best practice is the second option you used: Math.abs(a - b) < epsilon.
I understand it may be slower than you'd like, but it's the right way to do it. Bitwise comparison may result in two numbers being considered as different even though they're the same, from the point of view of the application (they would be equal if you had computed them by hand, but they are bitwise different due to rounding errors).
java.lang.Double
As shown in the question java.lang.Double.equals() calls public static long doubleToLongBits(double value), which
/**
* Returns a representation of the specified floating-point value
* according to the IEEE 754 floating-point "double
* format" bit layout.
and then checks for equality with ==.
(doubleToLongBits internally calls public static native long doubleToRawLongBits(double value), so it is platform dependent).
Here the way the primitive type works.
primitive type double
The floating-point types are float and double, which are conceptually associated with the single-precision 32-bit and double-precision 64-bit format IEEE 754 values and operations as specified in IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Standard 754-1985 (IEEE, New York).JLS-4.2.3
Operators on floating-point numbers behave as specified by IEEE 754 (with the exception of the remainder operator (ยง15.17.3)).
JLS-4.2.4
So the fastest way would be using primitive types and possibly performing a 'delta check' depending on the needed accuracy. If that's not possible using the methods provided by Double.
One should not use the JUnit assert method, since it performs more checks, one would be better off doing sth like:
boolean eq = Double.valueOf(5.0d).equals(Double.valueOf(2.0d));
Assert.assertTrue(eq);
What is an elegant, readable and non-verbose way of comparing two floating point value for exact equality?
As simple as it may sound, its a wicked problem. The == operator doesn't get the job done for NaN and also has special treatment for zero:
(+0.0 == -0.0) -> true
Double.NaN == Double.NaN -> false
But I want to determine if two values are exactly the same (but I do not care for different NaN patterns, so any NaN == any other NaN -> true).
I can do this with this ugly Monster piece of code:
Double.doubleToLongBits(a) == Double.doubleToLongBits(b)
Is there a better way to write this (and make the intent obvious)?
You can use
Double.compare(a, b) == 0
From the javadoc for compareTo
Double.NaN is considered by this method to be equal to itself and greater than all other double values (including Double.POSITIVE_INFINITY).
0.0d is considered by this method to be greater than -0.0d.
What you've got is already the best way of doing it, I'd say. It makes it clear that you're interested in the bitwise representation of the value. You happen to be converting those bits to long as a convenient 64-bit type which doesn't have any funky behaviour.
If you don't want it appearing frequently in your codebase, just add a method to wrap it:
public static boolean bitwiseEqualsWithCanonicalNaN(double x, double y) {
return Double.doubleToLongBits(x) == Double.doubleToLongBits(y);
}
Note that as per your question, this does not differentiate between different NaN values. If you wanted to do this at a later date, you'd need to use Double.toRawLongBits.