When Math.signum(x) == 0.
All other attempts to check whether float x == 0 may fail.
But Math.signum() is so basic, it should never fail.
Answer from JonAar Livernois on Stack OverflowWhen Math.signum(x) == 0.
All other attempts to check whether float x == 0 may fail.
But Math.signum() is so basic, it should never fail.
A simple method can be written to find this value.
public class FloatEqualsZero {
public static void main(String [] args) {
float x = 1;
while(x != 0 && -x != 0) {
x *= 0.1;
System.out.println(x);
}
}
}
This outputs the following:
0.1
0.01
9.999999E-4
9.999999E-5
9.999999E-6
9.999999E-7
...
1.0E-37
1.0E-38
1.0E-39
1.0E-40
1.0E-41
1.0E-42
1.0E-43
9.8E-45
1.4E-45
0.0
This (and similar tests) show that (x == 0) really only is true when x is 0.0f or -0.0f
Because Java uses the IEEE Standard for Floating-Point Arithmetic (IEEE 754) which defines -0.0 and when it should be used.
The smallest number representable has no 1 bit in the subnormal significand and is called the positive or negative zero as determined by the sign. It actually represents a rounding to zero of numbers in the range between zero and the smallest representable non-zero number of the same sign, which is why it has a sign, and why its reciprocal +Inf or -Inf also has a sign.
You can get around your specific problem by adding 0.0
e.g.
Double.toString(value + 0.0);
See: Java Floating-Point Number Intricacies
Operations Involving Negative Zero
...
(-0.0) + 0.0 -> 0.0
-
"-0.0" is produced when a floating-point operation results in a negative floating-point number so close to 0 that it cannot be represented normally.
how come a primitive float value can be -0.0?
floating point numbers are stored in memory using the IEEE 754 standard meaning that there could be rounding errors. You could never be able to store a floating point number of infinite precision with finite resources.
You should never test if a floating point number == to some other, i.e. never write code like this:
if (a == b)
where a and b are floats. Due to rounding errors those two numbers might be stored as different values in memory.
You should define a precision you want to work with:
private final static double EPSILON = 0.00001;
and then test against the precision you need
if (Math.abs(a - b) < epsilon)
So in your case if you want to test that a floating point number equals to zero in the given precision:
if (Math.abs(a) < epsilon)
And if you want to format the numbers when outputting them in the GUI you may take a look at the following article and the NumberFormat class.
System.out.println performs some rounding for floats and doubles. It uses Float.toString(), which itself (in the oraclew JDK) delegates to the FloatingDecimal class - you can have a look at the source of FloatingDecimal#toJavaFormatString() for gory details.
If you try:
BigDecimal bd = new BigDecimal(0.1f);
System.out.println(bd);
You will see the real value of 0.1f: 0.100000001490116119384765625.
From the docs for Float.toString(float) (which will always give the same results as the string you're printing):
How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type float.
As 0.1f is the closest representable float to the exact value 0.1, it makes sense that no more digits are required to uniquely distinguish that from any other value of the float type.