Nope it's perfectly legal if you are only going to compare against 0 as the right side of comparison will automatically casted to double. On the other hand, it would yield all the round-off errors if you where to compare against == 0.10000001
You are better or reading the discussion about float to 0 comparison here: Is it safe to check floating point values for equality to 0?
Also this discussion is very informative about weird precision problems on floats: Why the result is different for this problem?
i.e. below will yield false:
double d1 = 1.000001; double d2 =0.000001;
Console.WriteLine((d1-d2)==1.0);
Answer from Teoman Soygul on Stack OverflowNope it's perfectly legal if you are only going to compare against 0 as the right side of comparison will automatically casted to double. On the other hand, it would yield all the round-off errors if you where to compare against == 0.10000001
You are better or reading the discussion about float to 0 comparison here: Is it safe to check floating point values for equality to 0?
Also this discussion is very informative about weird precision problems on floats: Why the result is different for this problem?
i.e. below will yield false:
double d1 = 1.000001; double d2 =0.000001;
Console.WriteLine((d1-d2)==1.0);
What you have there is 0, which is an integer literal. It is implicitly converted to a double which you could represent with the double literal 0.0 (implicit conversion). Then there is a comparison between the two doubles. A rounding error could cause doubleVariable to not be equal to 0.0 (by some other math you might do, not just setting it), but there could never be a rounding error when converting the integer 0 to double. The code you have there is totally safe, but I would favor == 0.0 instead.
Well, how close do you need the value to be to 0? If you go through a lot of floating point operations which in "infinite precision" might result in 0, you could end up with a result "very close" to 0.
Typically in this situation you want to provide some sort of epsilon, and check that the result is just within that epsilon:
if (Math.Abs(something) < 0.001)
The epsilon you should use is application-specific - it depends on what you're doing.
Of course, if the result should be exactly zero, then a simple equality check is fine.
If something has been assigned from the result of an operation other than something = 0 then you better use:
if(Math.Abs(something) < Double.Epsilon)
{
//do something
}
Edit: This code is wrong. Epsilon is the smallest number, but not quite zero. When you wish to compare a number to another number, you need to think of what is the acceptable tolerance. Let's say that anything beyond .00001 you don't care about. That's the number you'd use. The value depends on the domain. However, it's mostly certainly never Double.Epsilon.
c++ - Comparing floating point number to zero - Stack Overflow
floating point - Double equals 0 problem in C - Stack Overflow
Java doubles and 0.0 - GameDev.net Forums
c++ - Fastest way to compare a double to exact 0 while both +0.0 or -0.0 are accepted - Stack Overflow
You are correct with your observation.
If x == 0.0, then abs(x) * epsilon is zero and you're testing whether abs(y) <= 0.0.
If y == 0.0 then you're testing abs(x) <= abs(x) * epsilon which means either epsilon >= 1 (it isn't) or x == 0.0.
So either is_equal(val, 0.0) or is_equal(0.0, val) would be pointless, and you could just say val == 0.0. If you want to only accept exactly +0.0 and -0.0.
The FAQ's recommendation in this case is of limited utility. There is no "one size fits all" floating-point comparison. You have to think about the semantics of your variables, the acceptable range of values, and the magnitude of error introduced by your computations. Even the FAQ mentions a caveat, saying this function is not usually a problem "when the magnitudes of x and y are significantly larger than epsilon, but your mileage may vary".
If you are only interested in +0.0 and -0.0, you can use fpclassify from <cmath>. For instance:
if( FP_ZERO == fpclassify(x) ) do_something;
The floating point comparison is exact, so 10^-10 is not the same as 0.0.
Basically, you should be comparing against some tolerable difference, say 10^-7 based on the number of decimals you're writing out, that can be accomplished as:
while(fabs(tmp) > 10e-7)
Don't use exact equality operations when dealing with floating point numbers. Although your number may look like 0, it likely to be something like 0.00000000000000000000001.
You'll see this if you use %.50f instead of %f in your format strings. The latter uses a sensible default for decimal places (6 in your case) but the former explicitly states you want a lot.
For safety, use a delta to check if it's close enough, such as:
if (fabs (val) < 0.0001) {
// close enough.
}
Obviously, the delta depends entirely on your needs. If you're talking money, 10-5 may be plenty. If you're a physicist, you should probably choose a smaller value.
Of course, if you're a mathematician, no inaccuracy is small enough :-)
Since you said you want the fastest possible code, I'm going to make some important simplifying assumptions throughout this answer. These are legal, per the question. In particular, I'm assuming x86 and IEEE-754 representations of floating-point values. I'll also mention MSVC-specific quirks, where applicable, although the general discussion would apply to any compiler targeting this architecture.
The way you test whether a floating-point value is equal to zero is by testing all of its bits. If all of the bits are 0, then the value is zero. Actually, the value is +0.0. The sign bit can be either 0 or 1, since the representation allows such thing as positive and negative 0.0, as you mention in the question. But this difference doesn't actually exist (there's not really any such thing as +0.0 and −0.0), so what you really need is to test all bits except the sign bit.
This can be done quickly and efficiently with some bit-twiddling. On little-endian architectures like x86, the sign bit is the leading bit, so you simply shift it out and then test the remaining bits.
This trick is described by Agner Fog in his Optimizing Subroutines in Assembly Language. Specifically, example 17.4b (on page 156 in the current version).
For a single-precision floating-point value (i.e., float), which is 32-bits wide:
mov eax, DWORD PTR [floatingPointValue]
add eax, eax ; shift out the sign bit to ignore -0.0
sete al ; set AL if the remaining bits were 0
Translating this into C code, you'd do something like:
const uint32_t bits = *(reinterpret_cast<uint32_t*>(&value));
return ((bits + bits) == 0);
Of course, this is formally unsafe because of the type punning. MSVC lets you get away with it, no problem. In fact, if you try to actually conform to the standard and play it safe, MSVC will tend to generate less efficient code, decreasing the effectiveness of this trick. If you want to do this safely, you'll need to verify the output of your compiler and make sure it's doing what you want. Some assertions are also recommended.
If you're okay with the unsafe nature of this approach, you will find that it is faster than a poorly-predicted conditional branch, so when you're dealing with random input values, it might be a performance win. For comparison purposes, here is what you'll see from MSVC if you just do a naive test for equality against 0.0:
;; assuming /arch:IA32, which is *not* the default in modern versions of MSVC
;; but necessary if you cannot assume SSE2 support
fld DWORD PTR [floatingPointValue]
fldz
fucompp
fnstsw ax
test ah, 44h
jp IsNonZero
mov al, 1
ret
IsNonZero:
xor al, al
ret
;; assuming /arch:SSE2, which *is* the default in modern versions of MSVC
movss xmm0, DWORD PTR [floatingPointValue]
ucomiss xmm0, DWORD PTR [constantZero]
lahf
test ah, 44h
jp IsNonZero
mov al, 1
ret
IsNonZero:
xor al, al
ret
Ugly, and potentially slow. There are branchless ways of doing this, but MSVC won't use them.
An obvious drawback to the "optimized" implementation described above is that it requires the floating-point value be loaded from memory in order to access its bits. There are no x87 instructions that can access the bits directly, and there's no way go directly from an x87 register to a GP register without going through memory. Since memory access is slow, this does incur a performance penalty, but in my tests, it's still faster than a mispredicted branch.
If you're using any of the standard calling conventions on 32-bit x86 (__cdecl, __stdcall, etc.), then all floating-point values are passed and returned in the x87 registers, so there's no difference in moving from an x87 register to a GP register versus moving from an x87 register to an SSE register.
The story is a bit different if you're targeting x86-64 or if you are using __vectorcall on x86-32. Then, you actually have floating-point values stored and passed in SSE registers, so you can take advantage of branchless SSE instructions. At least, theoretically. MSVC won't, unless you hold its hand. It would normally do the same branching comparison shown above, just without the extra memory load:
;; MSVC output for a __vectorcall function, targeting x86-32 with /arch:SSE2
;; and/or for x86-64 (which always uses a vector calling convention and SSE2)
;; The floating point value being compared is passed directly in XMM0
ucomiss xmm0, DWORD PTR [constantZero]
lahf
test ah, 44h
jp IsNonZero
mov al, 1
ret
IsNonZero:
xor al, al
ret
I've demonstrated the compiler output for a very simple bool IsZero(float val) function, but in my observations, MSVC always emits a UCOMISS+JP sequence for this type of comparison, no matter how the comparison is incorporated into the input code. Again, fine if the zero-ness of the input is predictable, but relatively lousy if branch prediction fails.
If you want to ensure you get branchless code, avoiding the possibility of branch-misprediction stalls, then you need to use intrinsics to do the comparison. These intrinsics will force MSVC to emit code closer to what you would expect:
return (_mm_ucomieq_ss(_mm_set_ss(floatingPointValue), _mm_setzero_ps()) != 0);
Unfortunately, the output is still not perfect. You suffer from general optimization deficiencies surrounding the use of intrinsics—namely, some redundant shuffling of the input value between various SSE registers—but that is (A) unavoidable, and (B) not a measurable performance problem.
I'll note here that other compilers, like Clang and GCC, don't need their hands held. You can just do value == 0.0. The exact sequence of code that they emit varies, depending on your optimization settings, but you'll see either COMISS+SETE, UCOMISS+SETNP+CMOVNE or CMPEQSS+MOVD+NEG (the latter is used exclusively by ICC). Your attempting to hold their hands with intrinsics would almost certainly result in less efficient output, so this probably needs to be #ifdef'ed to limit it to MSVC.
That's single-precision values, which have a width of 32 bits. What about double-precision values, which are twice as long? You'd think these would have 63 bits to test (since the sign bit is still ignored), but there's a twist. If you can rule out the possibility of denormal numbers, then you can get away with testing only the upper bits (again, assuming little-endian).
Agner Fog discusses this as well (example 17.4d). If you exclude the possibility of denormal numbers, then a value of 0 corresponds to the case where the exponent bits are all 0. The upper bits are the sign bit and the exponent bits, so you can just test these exactly as you did for single-precision values:
mov eax, DWORD PTR [floatingPointValue+4] ; load upper bits only
add eax, eax ; shift out sign bit to ignore -0.0
sete al ; set AL if the remaining bits were 0
In unsafe C:
const uint64_t bits = *(reinterpret_cast<uint64_t*>(&value);
const uint32_t upperBits = (bits & 0xFFFFFFFF00000000) >> 32;
return ((upperBits + upperBits) == 0);
If you do need to account for denormal values, then you aren't saving yourself anything. I haven't tested this, but you're probably no worse letting the compiler generate the code for a naive comparison. At least, not for x86-32. You might still gain on x86-64, where you have 64-bit-wide GP registers.
If you can assume SSE2 support (which would be all x86-64 systems, and all modern x86-32 builds as well), then you just use intrinsics, and you get denormal support for free (well, not really free; there are internal penalties in the CPU, I believe, but we'll ignore those):
return (_mm_ucomieq_sd(_mm_set_sd(floatingPointValue), _mm_setzero_pd()) != 0);
Again, as with single-precision values, the use of intrinsics is not necessary on compilers other than MSVC to get optimal code, and indeed may result in sub-optimal code, so should be avoided.
In plain and simple words, if you want to accept exactly +0.0 and -0.0, you just have to use:
x == 0.0
OR
From the cmath library you can use:
int fpclassify( double arg ) which will return "zero" for -0.0 or +0.0
Assuming 64-bit IEEE double, there is a 52-bit mantissa and 11-bit exponent. Let's break it to bits:
1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^0 = 1
The smallest representable number greater than 1:
1.0000 00000000 00000000 00000000 00000000 00000000 00000001 × 2^0 = 1 + 2^-52
Therefore:
epsilon = (1 + 2^-52) - 1 = 2^-52
Are there any numbers between 0 and epsilon? Plenty... E.g. the minimal positive representable (normal) number is:
1.0000 00000000 00000000 00000000 00000000 00000000 00000000 × 2^-1022 = 2^-1022
In fact there are (1022 - 52 + 1)×2^52 = 4372995238176751616 numbers between 0 and epsilon, which is 47% of all the positive representable numbers...
The test certainly is not the same as someValue == 0. The whole idea of floating-point numbers is that they store an exponent and a significand. They therefore represent a value with a certain number of binary significant figures of precision (53 in the case of an IEEE double). The representable values are much more densely packed near 0 than they are near 1.
To use a more familiar decimal system, suppose you store a decimal value "to 4 significant figures" with exponent. Then the next representable value greater than 1 is 1.001 * 10^0, and epsilon is 1.000 * 10^-3. But 1.000 * 10^-4 is also representable, assuming that the exponent can store -4. You can take my word for it that an IEEE double can store exponents less than the exponent of epsilon.
You can't tell from this code alone whether it makes sense or not to use epsilon specifically as the bound, you need to look at the context. It may be that epsilon is a reasonable estimate of the error in the calculation that produced someValue, and it may be that it isn't.
Is it OK to compare doubles in C? Like a == b. Will it give me correct results everytime? If not, workarounds?
What happens when doubles overflow? Does the C state machine go into an undefined state and then your program behavior is undefined/non deterministic? Or does something else happen? How does one prevent this from happening?
Numeric primitives in class scope are initialized to zero when not explicitly initialized.
Numeric primitives in local scope (variables in methods) must be explicitly initialized.
If you are only worried about division by zero exceptions, checking that your double is not exactly zero works great.
if(value != 0)
//divide by value is safe when value is not exactly zero.
Otherwise when checking if a floating point value like double or float is 0, an error threshold is used to detect if the value is near 0, but not quite 0.
public boolean isZero(double value, double threshold){
return value >= -threshold && value <= threshold;
}
Yes; all primitive numeric types default to 0.
However, calculations involving floating-point types (double and float) can be imprecise, so it's usually better to check whether it's close to 0:
if (Math.abs(foo.x) < 2 * Double.MIN_VALUE)
You need to pick a margin of error, which is not simple.