🧐 Floats and the Mystery of -0.0 PHP Review #5

Yes, really. -0.0 and 0.0 are two different byte representations according to the IEEE 754 standard – but in practice… PHP treats them as the same.

I had this code:

public function getPercentage(): int
{
    // epsilon to avoid division by zero
    if (abs($this->limitPrice) < 1e-8) {
        return 0;
    }

    return min(100, (int) round(($this->totalCartPrice / $this->limitPrice) * 100));
}

And I started wondering:

  • Can I just compare $this->limitPrice == 0.0?
  • What if limitPrice = -0.0? 🤯

🔬 Analysis

1️⃣ IEEE 754 and -0.0

In the floating point standard, there is positive zero (0.0) and negative zero (-0.0).
At the byte level, they are two different values:

  • 0.00x0000000000000000
  • -0.00x8000000000000000

So yes, binary-wise, they are not the same.


2️⃣ How PHP Handles It

Compare this:

var_dump(0.0 == -0.0);   // true
var_dump(0.0 === -0.0);  // true

✅ PHP treats these two values as equal both with loose (==) and strict (===) comparison.

But watch this:

var_dump(1 / 0.0);  // float(INF)
var_dump(1 / -0.0); // float(-INF)

➡️ The difference shows up when dividing – the sign of zero affects the result (+∞ vs -∞).


3️⃣ Does It Matter in My Case?

In my code, limitPrice has at most 4 decimal places, comes from the database or simple operations.
I don’t have strange negative zeros coming from complex math.
So I can safely write:

if ($this->limitPrice == 0.0) {
    return 0;
}

And everything works just fine.
Epsilon (1e-8) is not needed here, because I don’t have rounding errors at the 17th decimal place.


🛠 Bonus: How to Detect -0.0 (For the Nerds)

If for some reason you must know whether it’s -0.0, here’s the trick:

function isNegativeZero(float $x): bool {
    return $x === 0.0 && 1 / $x === -INF;
}

var_dump(isNegativeZero(0.0));  // false
var_dump(isNegativeZero(-0.0)); // true

Yes, you actually divide by zero to detect it. 🧪


✅ Conclusion

  • Yes, -0.0 and 0.0 are different bytes.
  • PHP treats them as equal (==, ===).
  • You can safely write == 0.0 in comparisons.
  • Only division by 0.0 vs -0.0 returns different infinities (INF vs -INF) – so when dividing, you may want to use abs().

🎉 Summary

I managed to simplify my code and instead of epsilons I just have:

public function getPercentage(): int
{
    return $this->limitPrice ?
        : min(100, (int) round(($this->totalCartPrice / $this->limitPrice) * 100)) : 0;
}

Cleaner, simpler, and still safe.
And the fact that -0.0 exists – well, that’s a great trivial fact to impress your fellow developers over coffee. ☕️😎

PS: If you need an epsilon, it’s better to use this constant:

PHP_FLOAT_EPSILON



Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • PhpUnit willReturnMap - PHP Review #4
  • BackedEnum - PHP Review #3
  • Array Functions: Initializing an Array Using [...] or array()? - PHP Review #2
  • Array Functions: ['array_filter', 'array_merge'] - PHP Review #1
  • Testing Error Handling in Godot Using GUT