MightyPork
MightyPork

Reputation: 18861

Why php thinks large ints are floats (but only sometimes)?

Sorry for the bad title, but I dunno how to call this.

echo rand(0,10e20) . "\n"; // bad
echo rand(0,10e19) . "\n"; // bad
echo rand(0,10e18) . "\n"; // bad
echo rand(0,10e17) . "\n"; // OK
echo rand(0,10e16) . "\n";
echo rand(0,10e15) . "\n\n";

var_dump(10e20); // float
var_dump(10e15); // float

Output:

Warning: rand() expects parameter 2 to be integer, float given in /srv/webroot-sandbox/index.php(73) : eval()'d code on line 1

Warning: rand() expects parameter 2 to be integer, float given in /srv/webroot-sandbox/index.php(73) : eval()'d code on line 2

Warning: rand() expects parameter 2 to be integer, float given in /srv/webroot-sandbox/index.php(73) : eval()'d code on line 3

578009006101638016
69608699344098568
7596902768127620

float(1.0E+21)
float(1.0E+16)

Can someone explain what's going on? This is PHP 7, it worked fine in PHP 5 (well, at least I didn't get any warnings).

Upvotes: 9

Views: 3188

Answers (2)

Xorifelse
Xorifelse

Reputation: 7911

Your question can be platform dependent as the integer range of a:

  • 32 bit platform is -2,147,483,648 to 2,147,483,647
  • 64 bit platform is -9,223,372,036,854,775,808 to 9,223,372,036,854,775,808

For me, running a 64 bit system it gives the following result.

var_dump(10e20 > PHP_INT_MAX); // true
var_dump(10e19 > PHP_INT_MAX); // true
var_dump(10e18 > PHP_INT_MAX); // true
var_dump(10e17 > PHP_INT_MAX); // false
var_dump(10e16 > PHP_INT_MAX); // false
var_dump(10e15 > PHP_INT_MAX); // false

This output directly correlates with your results and might explain a fiddle or your webhost to show different results.

The reason it behave differently on PHP 7 is explained here:

Previously, internal functions would silently truncate numbers produced from float-to-integer coercions when the float was too large to represent as an integer. Now, an E_WARNING will be emitted and NULL will be returned.

Upvotes: 9

Marc B
Marc B

Reputation: 360602

PHP ints are signed 64bit values (unless you're on a 32bit install), so they go (roughly)

-9,223,372,036,854,775,808 -> +9,223,372,036,854,775,808

In scientific notation, -9.2e18 -> +9.2e18

So your "bad" values are simply integers that are too large to store as integers, and PHP is converting to float to try and preserve as much of the value as is possible.

And since you have 10e18, that's actually 1e19, and outside the max_int range.

Upvotes: 11

Related Questions