9

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

AbraCadaver
  • 78,200
  • 7
  • 66
  • 87
MightyPork
  • 18,270
  • 10
  • 79
  • 133
  • 2
    Still searching but MIGHT be that it exceeds the size of the int... – FirstOne Mar 02 '16 at 19:12
  • hmm maybe it tries to cast and fails at certain magnitude? But funny that it worked OK in PHP 5 – MightyPork Mar 02 '16 at 19:12
  • according to the manual: http://php.net/manual/en/language.types.integer.php Once you go outside the limit, you get in error. And this is specific to php7. – durbnpoisn Mar 02 '16 at 19:16
  • hm yea just found it myself on google. Still worth an answer, I won't be the only one to stumble upon this. – MightyPork Mar 02 '16 at 19:17
  • `var_dump` doesn't care if you provide float or int, but `rand` does. Did you try to set [the precision](http://stackoverflow.com/questions/13800456/php-getting-a-float-variable-internal-value) in php7? – Fabian Horlacher Mar 02 '16 at 19:27
  • @FabianH. tried now, doesn't really change anything regarding the errors – MightyPork Mar 02 '16 at 19:30

2 Answers2

11

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.

Marc B
  • 356,200
  • 43
  • 426
  • 500
  • Would be interesting to also compare this to PHP 5's behaviour, regrettably I have upgraded already... – MightyPork Mar 02 '16 at 19:36
  • 1
    @MightyPork, the behavior is the same with any system, 32-bit integers max is 2^32/2-1 and 64-bit integer max is 2^64/2-1. (Unsigned would be 2^32-1, 2^64-1 but PHP doesn't allow unsigned integers if IIRC) – Devon Bessemer Mar 02 '16 at 19:38
  • 1
    my 5.5.9 matches above. But note that in Windows, php5 treated all ints as 32bit, regardless of what the underlying platform is. e.g. phpwin 64bit was still using 32bit ints. – Marc B Mar 02 '16 at 19:38
  • why I wanted to try php5 is the rand() warning didn't occur before. Kinda curious how it managed to fit the large number to int back then. – MightyPork Mar 02 '16 at 19:48
  • it would've done the same thing, since rand() expects ints. it may just have been a silent error before, and PHP7 upgraded it to a fullblown warning. I don't get any warnings at all on 5.5.9 with an over-sized int. – Marc B Mar 02 '16 at 20:28
9

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.

Xorifelse
  • 7,878
  • 1
  • 27
  • 38