php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #53934 The negative PHP_INT_MAX is incorrectly converted to float
Submitted: 2011-02-05 14:53 UTC Modified: 2018-05-29 13:41 UTC
Votes:8
Avg. Score:4.1 ± 0.9
Reproduced:6 of 6 (100.0%)
Same Version:1 (16.7%)
Same OS:4 (66.7%)
From: eriksen dot costa at infranology dot com dot br Assigned: cmb (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.3.5 OS: Linux
Private report: No CVE-ID: None
 [2011-02-05 14:53 UTC] eriksen dot costa at infranology dot com dot br
Description:
------------
I found this and seems a bug. Everytime I use the negative PHP_INT_MAX literally (-9223372036854775808) as a function parameter, it is converted to float.

However, if I pass it like an expression -9223372036854775807 - 1, it is correctly identified as an integer.

Test script:
---------------
--TEST--
Checks if the negative PHP_INT_MAX is treated as integer.
--CREDITS--
Eriksen Costa <eriksen.costa@infranology.com.br>
--SKIPIF--
<?php
if (PHP_INT_SIZE < 8) die('64bit platforms only');
?>
--FILE--
<?php
var_dump(-9223372036854775807 - 1);
var_dump((PHP_INT_MAX * -1) - 1);
var_dump(-9223372036854775808);
?>
--EXPECT--
int(-9223372036854775808);
int(-9223372036854775808);
int(-9223372036854775808);

Expected result:
----------------
int(-9223372036854775808);
int(-9223372036854775808);
int(-9223372036854775808);

Actual result:
--------------
int(-9223372036854775808)
int(-9223372036854775808)
float(-9.2233720368548E+18)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-02-05 17:34 UTC] cataphract@php.net
-Status: Open +Status: Verified
 [2011-02-05 18:55 UTC] cataphract@php.net
The problem is that "-9223372036854775808" is not parsed as an integer, instead the minus sign and the rest are parsed individually and 9223372036854775808 is bigger than LONG_MAX.

Probably this is not trivial to fix.
 [2012-08-09 14:05 UTC] ajf at ajf dot me
@catphract:

In that case is it not a tokeniser issue, and "-9223372036854775807" should be 
tokenised to '-9223372036854775807' not '-' '9223372036854775807'?
 [2014-06-05 14:37 UTC] ajf at ajf dot me
This issue still exists in master.
 [2014-06-05 15:12 UTC] ajf at ajf dot me
OK, I found out why this happens. Because the difference between subtraction and negation can't be known at lexing time ($x = 12-3 vs $x = -3), -9223372036854775808 is actually parsed as -(9223372036854775808). Since signed integers are asymettrical (max is 9223372036854775807 but min is -9223372036854775808), 9223372036854775808 overflows and becomes a float. Then the parser sees -(9.2233720368548E+18) and subtracts it, yielding -9.2233720368548E+18.

I'm not sure how this could be fixed short of parsing numbers at the last minute. Maybe that would actually reap performance benefits!
 [2015-12-19 23:27 UTC] ajf at ajf dot me
Since PHP 7 there is PHP_INT_MIN for this purpose, by the way.
 [2018-05-29 11:41 UTC] cmb@php.net
In my opinion, this is not a bug, but rather a documentation
issue. PHP (as many other languages, I believe) does not support
signed literals, but rather only unsigned literals plus the
identity and negation operators.

If we would introduce the notion of signed integer literals, there
would be a difference between `-9223372036854775808` and
`0-9223372036854775808` – that's even more confusing.
 [2018-05-29 12:16 UTC] spam2 at rhsoft dot net
hell, there are a ton of problems - when a constant named with INT on a x86_64 fails is_int() something is seriously broken - @cmb: as you can see with -100 the minus sign is not problem

PHP_INT_MIN and PHP_INT_MAX a *both float* which is wrong - period

php > $x = -100;
php > echo is_int($x);
1

php > $x = 9223372036854775808;
php > echo is_float($x);
1
php > echo is_int($x);
php >

php > echo PHP_INT_MAX;
9223372036854775807
php > echo PHP_INT_MIN;
-9223372036854775808

php > $x = -9223372036854775808;
php > echo is_int($x);
php > $x = 9223372036854775808;
php > echo is_int($x);
php > echo is_int(1);
1
php > $x = 1000;
php > echo is_int($x);
1
php >
 [2018-05-29 12:18 UTC] spam2 at rhsoft dot net
come on, explain me why the large number becomes a float when we all known from hundrets of bugrports that float values are making nothing than trouble swhen you touch or even echo them in doubt

php > $x = 9223372036854775808;
php > echo is_float($x);
1

php > $x = 922337203685477;
php > echo is_float($x);
php > echo is_int($x);
1
 [2018-05-29 12:20 UTC] ajf@php.net
-Status: Verified +Status: Not a bug
 [2018-05-29 12:20 UTC] ajf@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php


 [2018-05-29 12:30 UTC] spam2 at rhsoft dot net
how the f**k is that not a bug and how does http://www.php.net/manual/ justify that gambling machine behavior?

php > $x = 9223372036854775808;
php > echo is_int($x);

php > $x = (int)9223372036854775808;
php > echo is_int($x);
1

-----

php > $x = 9223372036854775808;
php > echo is_int($x);
php > $x = (int)9223372036854775808;
php > echo is_int($x);
1
 [2018-05-29 12:52 UTC] spam2 at rhsoft dot net
this is unaccepatble because "$class->property = -9223372036854775808" while even don't know that the value *is* PHP_INT_MIN must not end as float in a strict-typed application

php > echo PHP_INT_MIN;
-9223372036854775808
php > echo is_int(PHP_INT_MIN);
1

php > $x = -9223372036854775808;
php > echo is_float($x);
1
 [2018-05-29 12:53 UTC] ajf@php.net
PHP has for the longest time automatically converted to float if an integer becomes too big to represent with the native machine size (64-bit or 32-bit).

php > var_dump(PHP_INT_MAX);
int(9223372036854775807)
php > var_dump(PHP_INT_MAX + 1);
float(9.2233720368548E+18)

Whether this is good or not depends on your perspective. It looses some accuracy (the least significant digits), but you at least know the most significant digits and the exponent of the number. Overflow (when an integer becomes too big) is a problem that inevitably must be solved somehow. Other options would be to throw an error or exception, or to convert to a (slow, software) arbitrary-precision integer type. Those have their own disadvantages.

Overflow creates trouble here because `-` in PHP is not a negative sign, it is a negation operator. PHP does not have negative number literals; in PHP, `-123` is actually `-(123)` — you create a positive number (123) then immediately negate it (-). This is fine for every case bar one: two's complement integers are unfortunately asymmetrical, so you can't get the minimum integer value (-9223372036854775808 for 64-bit) just by negating 9223372036854775808, since 9223372036854775808 is greater than PHP_INT_MAX (9223372036854775807):

php > var_dump(PHP_INT_MIN);
int(-9223372036854775808)
php > var_dump(9223372036854775808);
float(9.2233720368548E+18)
php > var_dump(-9223372036854775808);
float(-9.2233720368548E+18)

You can, however, negate PHP_INT_MAX and then subtract one (-PHP_INT_MAX - 1), since no overflow happens there:

php > var_dump(-PHP_INT_MAX - 1);
int(-9223372036854775808)

Similarly you can do a bitwise NOT:

php > var_dump(~PHP_INT_MAX);
int(-9223372036854775808)

But these days the best option is to use the new PHP_INT_MIN constant that was added in PHP 7.0:

php > var_dump(PHP_INT_MIN);
int(-9223372036854775808)

Overflow resulting in a float is a deliberate feature, and `-` negating instead of marking a negative number is also deliberate, so this is expected behaviour and therefore not a bug. It's not great, for sure, but there's not a nice clean way to “fix” it since it's a consequence of several features working as intended. Incidentally, overflow here is a problem common to other C-like languages that lack negative number literals. Whether PHP handles it better than those other languages is an interesting question.
 [2018-05-29 12:53 UTC] nikic@php.net
@spam2 at rhsoft dot net: 9223372036854775808 is not INT_MAX, you were probably thinking about 9223372036854775807? Under signed compliment, INT_MAX and INT_MIN are off by one.

Just as a heads up, once rights have propagated, I will be removing any comments by you that I perceive to be rude (hint: "how the f**k" is rude).

There are good arguments in favor of giving -9223372036854775808 special treatment and some languages do so (I think Java does). There are also good reasons to not give it special treatment and some languages do so (C and C++ definitely do). You argue none of that and instead post disrespectful and inflammatory comments -- and keep doing that across many different bug reports.

If you wish your comments to remain in the future, please temper the manner in which you express your concerns or feedback.
 [2018-05-29 13:07 UTC] cmb@php.net
-Status: Not a bug +Status: Re-Opened -Assigned To: +Assigned To: cmb
 [2018-05-29 13:07 UTC] cmb@php.net
Re-opening and changing to documentation problem, since[1]

| Integers can be specified in decimal (base 10), hexadecimal
| (base 16), octal (base 8) or binary (base 2) notation, optionally
| preceded by a sign (- or +).

is misleading at best.

[1] <http://php.net/manual/en/language.types.integer.php#language.types.integer.syntax>
 [2018-05-29 13:07 UTC] cmb@php.net
-Type: Bug +Type: Documentation Problem
 [2018-05-29 13:41 UTC] cmb@php.net
Automatic comment from SVN on behalf of cmb
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=345073
Log: Fix #53934: The negative PHP_INT_MAX is incorrectly converted to float

Actually, PHP does not support integer literals with explicit signs;
instead these are regarded as identity and negation operators, respectively.
 [2018-05-29 13:41 UTC] cmb@php.net
-Status: Re-Opened +Status: Closed
 [2018-05-29 13:41 UTC] cmb@php.net
This bug has been fixed in the documentation's XML sources. Since the
online and downloadable versions of the documentation need some time
to get updated, we would like to ask you to be a bit patient.

Thank you for the report, and for helping us make our documentation better.
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Mon Oct 22 22:01:25 2018 UTC