In interactive mode on PHP 7 (64 bit Ubuntu),
php > echo true;
1
php > echo false; # no output for false
php > echo PHP_INT_MIN == -9223372036854775808;
1
php > echo is_int(PHP_INT_MIN);
1
php > echo is_int(-9223372036854775808);
Why doesn't the last line output 1?
var_dump() is your friend.
var_dump(
PHP_INT_MIN,
is_int(PHP_INT_MIN),
-9223372036854775808,
is_int(-9223372036854775808)
);
/* Output:
int(-9223372036854775808)
bool(true)
float(-9.2233720368548E+18)
bool(false)
*/
Because is_int :
perates in signed fashion, not unsigned, and is limited to the word size of the environment php is running in.
and so -9223372036854775808 it's smaller than your system word bound
First PHP parses your integer value as float, because of an integer overflow. Then it uses is_int() to determine if what PHP has parsed is an integer. See example #3 for 64-bit systems.
Please note that is_int() does work with unsigned integers as well.
Using 32-bit PHP 7:
echo PHP_INT_MIN; // -2147483648
echo var_dump(is_int(-2147483648)); // bool(false)
echo var_dump(is_int(-2147483647)); // bool(true)
To make sure PHP_INT_MIN is off by one, please try this on your 64-bit PHP 7:
echo var_dump(is_int(-9223372036854775807)); // bool(true)?
If you need more integer precision, you could use the GMP extension.
Related
This is the example code I'm running.
<?php
//$maxval = (2**64)-1;
$maxval = (2**64);
$maxval = $maxval-10000;
echo number_format($maxval,0,".","") . "\n";
echo "18446744073709551615\n";
?>
The code if for checking a number that will come as a string and I need to make sure it is an unsigned 64 bit integer. So once I check that the string is composed ONLY of numbers I need to make sure that the range is correct.
But I'm getting some weird behaviour.
This line (2**64)-1; printed 18446744073709551616. It seemed it ignored the -1. So I started changing -1 to -10, -100, -1000 and they all printed the same value. It only changed when I changed it to -10000 and this is what it printed:
18446744073709541376
18446744073709551615
But to my understanding the first line should be
18446744073709541615
So what am I doing wrong?
Integer in PHP is a signed integer. There are constants PHP_INT_MIN and PHP_INT_MAX for the smallest and largest value.
//64 Bit PHP Version !
var_dump(PHP_INT_MAX); //int(9223372036854775807) = 2**63-1
If the values are greater than the integer range, PHP automatically converts to float. Float, however, is far less precise than 63 bits. This is where the inaccuracies come from.
The bcmath functions can be used to calculate with almost any precision. This code is for checking a number that will come as a string and is an unsigned 64 bit integer.
$val = "18446744073709551614";
$maxUnsign64Bit ="18446744073709551615";
if(ctype_digit($val) AND bccomp($val,$maxUnsign64Bit) !== 1){
echo 'is a 64 Bit number';
};
PHP documentation here states that:
If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.
But what about an operation which results in a number less than PHP_INT_MAX ?
See this code snippet as an example:
$max_int = 2**31-1 ; // 2147483647
var_dump(PHP_INT_MAX === $max_int); // false
As you can see, even when an operation results in a valid int value PHP seems to cast the result into float
var_dump(PHP_INT_MAX === (int) $max_int) // true
My questions:
Does PHP interpreter cast the result into float before making any calculations?
Shouldn't PHP calculate the result and then sets the type accordingly? (Makes sense right?)
Edit:
PHP version: 7.2.1 32-bit
OS: Windows: 10 x64
I'm using XAMPP
When calculating $max_int = 2**31-1 the engine does this in steps:
$tmp = 2**31;
$max_int = $tmp-1
Here $tmp is bigger than maximum integer value and converted to a floatng point number. In consequence there is an float subtraction, resulting in a float. Since it had been float it has to stay float.
I am trying to validate integer by using FILTER_VALIDATE_INT. it is working fine on ubuntu server but return false on my local win 10 xampp system.
here is the code
case 1:
$d = "sdaf";
var_dump(filter_var($d, FILTER_VALIDATE_INT));
OP : bool(false)
case 2 :
$d = "9876543210";
var_dump(filter_var($d, FILTER_VALIDATE_INT));
OP : bool(false)
case 3 :
var_dump(filter_var(9876543210, FILTER_VALIDATE_INT));
OP : bool(false)
On server:
var_dump(filter_var(9876543210, FILTER_VALIDATE_INT));
OP : int(9876543210)
Are you running a 32 bit Windows, or a 32bit PHP on a 64bit windows, and a 64bit Server?
I think you probably are. If you run this you will get the correct results. Your numbers were greater than the PHP_INT_MAX for a 32bit system
echo PHP_INT_MAX;
$d = "sdaf";
var_dump(filter_var($d, FILTER_VALIDATE_INT));
$d = PHP_INT_MAX;
var_dump(filter_var($d, FILTER_VALIDATE_INT));
var_dump(filter_var(PHP_INT_MAX, FILTER_VALIDATE_INT));
RESULTS:
2147483647
bool(false)
int(2147483647)
int(2147483647)
In PHP you can have 32 bits and 64 bits integers.
The maximum 32 bits integer you can have, it 2147483647, which is less then yours 9876543210.
If you have a number that is larger then this, it is converted to a float, so the int validation fails.
If you don't want this, you need to have a 64 bits version of PHP.
AND if you have windows, this needs to be PHP 7 or higher.
Why? 64 bits versions of PHP 5.* have a bug that integers are always 32 bits.
More info: https://secure.php.net/manual/en/language.types.integer.php
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).
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.
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.
Previously I have been developing an app using PHP 5.6.7 in Linux, however recently I've switched to a Windows environment using WAMP 64 bit and upgraded PHP to 5.6.12 and been running into a few issues. One issue is in the backend PHP I have an array of integers. When I print to return to the front which prints the return array to the console I get a different format. That is:
$permission->fk_org_id = [24053826281537536,24051529749102626,111];
print json_encode($permission->fk_org_id);
Returns the following to the console:
0:24053826281538000
1:24051529749103000
2:111
Why is this happening?
Those numbers are too large to fit in a (32-bit) integer. They will be interpreted as a float, see the documentation:
If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. Also, an operation which results in a number beyond the bounds of the integer type will return a float instead.
A float has a precision of about 14 significant digits, so that's why you see the zeroes.
Unfortunately, PHP on Windows does not support 64 bit integers, according to this answer:
On windows x86_64, PHP_INT_MAX is 2147483647. This is because in the underlying c-code, a long is 32 bit.
However, linux on x86_64 uses a 64bit long so PHP_INT_MAX is going to be 9223372036854775807.
You probably run your script on 32-bit machine where max int is 2147483647, so integer overflow occurres. According to documentation:
If PHP encounters a number beyond the bounds of the integer type, it
will be interpreted as a float instead. Also, an operation which
results in a number beyond the bounds of the integer type will return
a float instead.
<?php
$large_number = 2147483647;
var_dump($large_number); // int(2147483647)
$large_number = 2147483648;
var_dump($large_number); // float(2147483648)
$million = 1000000;
$large_number = 50000 * $million;
var_dump($large_number); // float(50000000000)
?>
More about integers you can find in documentation.