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 Overflow
Discussions

c++ - Comparing floating point number to zero - Stack Overflow
Someone pointed out "Comparing Floating Point Numbers", which I want to share more prominently. ... I've a sentence in my head which says, never test a double to equal. Only greater or smaller. ... @user743414 in some scenarios, it is totally fine to test a double to equal. E.g. if(counter > 10.0) ... More on stackoverflow.com
🌐 stackoverflow.com
floating point - Double equals 0 problem in C - Stack Overflow
Just because a number displays ... than a double can store. It's possible that your algorithm is getting to a point where it is very close to 0, but the next step moves so little that it rounds to the same thing it was at before, and hence it never gets any closer to 0 (just goes into an infinite loop). In general, you should not compare floating-point ... More on stackoverflow.com
🌐 stackoverflow.com
Java doubles and 0.0 - GameDev.net Forums
There are often many ways to represent things that are functionally equivalent. Perhaps as a parallel, 1000 is the same value as 10^3, while the representations are different the number they represent is the same. There are many things in the language and the libraries where equality does not mean bitwise equivalence. mike74 said: Does it do two checks if you do a zero comparison with a double... More on gamedev.net
🌐 gamedev.net
January 14, 2024
c++ - Fastest way to compare a double to exact 0 while both +0.0 or -0.0 are accepted - Stack Overflow
The OP want to know if a double ... fabs(x) == +0.0, is not the most direct. ... @SergeRogatch Because the C++ compiler maps == on double to IEEE 754 equality, which has this property by definition. en.wikipedia.org/wiki/Signed_zero#Comparisons .... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Ars OpenForum
arstechnica.com › forums › operating systems & software › programmer's symposium
C programming: comparing double with 0.0 | Ars OpenForum
July 8, 2005 - If you start messing with the number and it ends up supposed to be 0.0, it could come to within ~10^-15 of zero instead, in which case comparisons won't do what you want. Why not just use something like ((x > 0 && x < 1e-15) || (x < 0 && x > -1e-15)) for comparison?
🌐
Cprogramming
cboard.cprogramming.com › c-programming › 63929-compare-double-value-0-unreliable-comparisons-warning.html
compare double value to 0 - unreliable comparisons warning
double alpha; ... if ((m == 0) || (n == 0) || (((alpha == 0) || (k == 0)) && (beta == 1))) Elementary stuff no doubt but in my defence it's getting late.... Thanks, Colly. ... When you use floats and doubles, because of the way they work, the variable does not store the exact value. So 3 / 2 may not be exactly 1.5, it might be 1.50000001 or something. This is why inequality and equality comparisons are unreliable with them. I'm afraid an alternative doesn't come to mind.
🌐
Medium
medium.com › @AlexanderObregon › javas-double-compare-method-explained-6159db37e326
Java’s Double.compare() Method Explained | Medium
December 23, 2024 - The Double.compare() method includes ... such as dividing zero by zero. When comparing two NaN values, Double.compare() returns 0, treating them as equal....
Find elsewhere
🌐
Tutorialspoint
tutorialspoint.com › java › lang › double_compare.htm
Java - Double compare() method
The sign of the integer value returned is the same as that of the integer that would be returned by the call − ... This method returns the value 0 if d1 is numerically equal to d2; a value less than 0 if d1 is numerically less than d2; and ...
🌐
Oreate AI
oreateai.com › blog › the-tricky-dance-comparing-doubles-to-zero-in-c › 086e1ddbb9fab5d29930b2d7f0c587dc
The Tricky Dance: Comparing Doubles to Zero in C++ - Oreate AI Blog
January 27, 2026 - So, how do we navigate this minefield? The universally accepted solution is to stop looking for exact equality and instead check if the number is close enough to zero. We introduce a small tolerance, often called an 'epsilon' (ε). If the absolute ...
🌐
Fitzgibbon
fitzgibbon.ie › floating-point-equality
Is my floating point number equal to zero? - Andrew Fitzgibbon
Quite interesting how large the threshold is for these cases: 0.04 is certainly not something I would have guessed, or even obtained from considerations around sqrt(eps). ... 1. If you are going to compare the result of any calculation to zero, make sure to cast to double first, like so:
🌐
Microsoft Learn
learn.microsoft.com › en-us › dotnet › fundamentals › runtime-libraries › system-double-equals
System.Double.Equals method - .NET | Microsoft Learn
June 6, 2024 - The Microsoft C# compiler generates instructions to represent the value of the parameter as a Double object, then generates a Double.Equals(Double) method that compares the values of the instance and the widened representation of the parameter.
🌐
GameDev.net
gamedev.net › home › forums › for beginners › java doubles and 0.0
Java doubles and 0.0 - GameDev.net Forums
January 14, 2024 - You can read the basis of it for Java 21 here, but this specific behavior has been the same since the beginning of the language. Look down a few paragraphs to read “Positive zero and negative zero compare equal, so the result of the expression 0.0==-0.0 is true and the result of 0.0>-0.0 is false.
🌐
GeeksforGeeks
geeksforgeeks.org › java › double-compare-method-in-java-with-examples
Double compare() Method in Java with Examples - GeeksforGeeks
July 11, 2025 - // Java Program to illustrate // the Double.compare() method import java.lang.Double; public class GFG { public static void main(String[] args) { // Get the two double values // to be compared Double d1 = 1023d; Double d2 = 1023d; // function ...
Top answer
1 of 3
5

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.

2 of 3
2

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

🌐
Scaler
scaler.com › home › topics › java double compare()
Java Double compare() - Scaler Topics
May 4, 2023 - Then depending on the result we are checking if both the values are equal, or which one is greater or lesser with three conditions : If the result value is zero (compare = 0), that means both the Double type values are equal and we are also printing the difference between the two values, and ...
Top answer
1 of 12
206

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...

2 of 12
20

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.

🌐
Reddit
reddit.com › r/c_programming › comparing doubles in c
r/C_Programming on Reddit: Comparing doubles in C
July 18, 2016 -

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?

🌐
Baeldung
baeldung.com › home › java › java numbers › comparing doubles in java
Comparing Doubles in Java | Baeldung
December 11, 2025 - Since d1 and d2 are close enough (their difference is within the epsilon), the comparator returns 0 to indicate equality. In some cases, we may need to determine whether two double values are equal up to a specified number of decimal places.