1

In PHP there is a floating point negative zero, which compares identically to floating point positive zero -0.0 === 0.0, despite printing as different strings. There is no integer negative zero in PHP.

I'm writing an extended version of rounding functions and I'm trying to replicate PHP's native behaviour as much as possible. I'm writing it with TDD methodology, so I need a way to verify my code is in line with the native PHP functions by returning negative zero where PHP returns negative zero.

<?php
var_dump(ceil(-0.5));
double(-0)

Is there any way of testing for -0.0 apart from:

  • converting it to a string (string)-0.0 === '-0'
  • serialising it serialize(-0.0) === 'd:-0;'
CJ Dennis
  • 4,226
  • 2
  • 40
  • 69

3 Answers3

3

@njuffa suggested if (1 / $x === -INF), which works but throws a division by zero warning.

@Manu-sh modified it to do the same thing without the warning by using the new "power of" operator: **

<?php
function is_negative_zero($x) {
  return $x ** -1 === -INF;
}

echo is_negative_zero(0.0)? "Yes": "No";
echo PHP_EOL;

echo is_negative_zero(-0.0)? "Yes": "No";
echo PHP_EOL;

Output:

No
Yes
CJ Dennis
  • 4,226
  • 2
  • 40
  • 69
1

This work only for literals but not for variables:

var_export(0.0 ** 0 == 1);
var_export(-0.0 ** 0 == -1);

But this seems to work also for variables:

// return 1 for positive zero, -1 for negative zero
// otherwise return 0
function zero_sign(float $x): int {

    if (($y = ($x ** -1)) === -INF)
        return -1;

    return $y === INF;
}

var_export(zero_sign(-0.0) === -1);
var_export(zero_sign(0.0)  ===  1);
var_export(zero_sign(-1.0) ===  0);
var_export(zero_sign(1.0)  ===  0);

You can check by yourself that this follow the mathematics rules, here are the Wolframalpha results for -0.0 ** -1 and 0.0 ** -1

Manu-sh
  • 114
  • 4
  • the first output 1, the second -1 – Manu-sh Oct 12 '19 at 07:20
  • @CJDennis are you serius? this return a floating point number, check it by yourself with `var_dump(0.0 ** 0);` and `var_dump(-0.0 ** 0);` – Manu-sh Oct 12 '19 at 07:24
  • and FYI there is no negative zero in two's complement representation – Manu-sh Oct 12 '19 at 07:26
  • have you write "There is no integer negative zero in PHP.", yes it obvious – Manu-sh Oct 12 '19 at 07:30
  • @CJDennis nevermind, i figured out that this work only on literal values.. – Manu-sh Oct 12 '19 at 07:36
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200748/discussion-between-manu-sh-and-cj-dennis). – Manu-sh Oct 12 '19 at 07:43
  • @CJDennis here is a way to do what you want to do – Manu-sh Oct 12 '19 at 07:44
  • There's no need to keep discussing this as you've found a solution that works for me. Clean up your answer by removing the `echo` lines, add a short explanation of why/how it works, maybe how you came to the answer, and delete all your comments, then I'll delete all my comments too and mark this answer as accepted. – CJ Dennis Oct 12 '19 at 08:01
  • @CJDennis i have spent a bunch of time trying to find out a good solution for you, describing it and replying to your comments, be and accept my answer. – Manu-sh Oct 12 '19 at 09:22
  • 1
    If seems to only work for literals because of operator precedence: `-0.0 ** 0 === -(0.0 ** 0) === -1.0`. `(-0.0) ** 0 === 1.0` Change the code to the following and I'll accept it: `if ($x ** -1 === -INF)`. – CJ Dennis Oct 12 '19 at 10:25
0

Floating point numbers have a specific bit that is set in the internal coding if it is negative. This test is also suitable to distinguish between +0.0 and -0.0. The test is also independent of how PHP performs operations with -0.0 and +0.0.

function isNegativFloat($value){
  return is_float($value) AND ord(pack('E',$value)) & 0x80;
}

Examples:

var_dump(isNegativFloat(0.0));  //bool(false)
var_dump(isNegativFloat(-0.0));  //bool(true)
var_dump(isNegativFloat(0.6));  //bool(false)
var_dump(isNegativFloat(-0.6));  //bool(true)

Special test for negative float zero:

function isNegativFloatNull($value){
  return $value === 0.0 AND isNegativFloat($value);
}

Examples:

var_dump(isNegativFloatNull(0.0));  //bool(false)
var_dump(isNegativFloatNull(-0.0));  //bool(true)
var_dump(isNegativFloatNull(0.6));  //bool(false)
var_dump(isNegativFloatNull(-0.6));  //bool(false)
jspit
  • 7,276
  • 1
  • 9
  • 17