I read the manual from the php homepage
It writes:
// this doesn't go for
//hexadecimal specified integers above 2^32-1:
var_dump( 0x100000000 );
// output: int(2147483647)
But it has 4.5 bytes which is larger than int(4 bytes), and I test it.
It outputs float.
I don't understand why they contradict?
From the PHP manual page on integers: "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."
Since the integer type is too small to represent that number, PHP is automagically converting it to a float so you don't lose data. This is expected behavior.
However, the specific example that you quoted is clearly wrong in the manual. It looks like someone made an error when writing the manual, or it may be that the behavior of oversize hexadecimal literals was changed since the time that manual page was written.
It outputs a float for me: float(4294967296)
DEMO: http://codepad.org/otsGOiWf
Related
I've got this problem on Windows 10 with both php 7 and 7.1 and also on raspbian with PHP 7.0.33
When I try to cast a large double (a miliseconds timestamp) to int I get a totally wrong result. Example:
$a = 1512298800000.0;
echo intval($a);
The output is: 470311808
Any suggestion on how to troubleshoot this?
Based on intval() Manual, it cleary states:
Return Values
The integer value of var on success, or 0 on failure. Empty arrays return 0, non-empty arrays return 1.
The maximum value depends on the system. 32 bit systems have a maximum signed integer range of -2147483648 to 2147483647. So for example on such a system, intval('1000000000000') will return 2147483647. The maximum signed integer value for 64 bit systems is 9223372036854775807.
Strings will most likely return 0 although this depends on the leftmost characters of the string. The common rules of integer casting apply.
And
Notes
Note:The base parameter has no effect unless the var parameter is a string.
So basically it seems you are using 32-bit system and value got overflowed from the range of integer.
Today I just made an interesting discovery while testing what happens calculating bitwisely in php like INF ^ 0 (^ => Bitwise Operator for Exclusive OR (XOR)) what gave me int(-9223372036854775808) => greatest possible negative value in a 64-Bit system.
But then I was asking myself: "Why is the result going negative in XOR when the "positive infinit" means 9223372036854775807 (63 Bits on 1 with a leading 0) and 0 (64 Bits on 0 => 0 xor 0 = 0) What is PHP's infinit value though and what is the calculation behind it? And why do I get a (correct?) negative value when I use "negative infinit"(A leading 1 against a leading 0 on 0 => 1 xor 0 = 1?".
Another interesting point is that this just happens on PHP Version 5.5.9-1, and not e.g. on 5.3.x. and 5.6.x (where i've tested it)! Maybe someone has an idea what happens there? Tested it on three versions but just mine (5.5.9-1) gives those results:
Just to let you guys know, it's just an abstract playaround i've done for fun but I find it's interesting. Maybe someone can help here or explain me a wrong thought I have? Just tell me if someone needs more informations about anything!
EDIT: Accordingly to jbafford it would be great to get a complete answere, so i'll just quote him: why does 5.5 and 5.6 result in PHP_INT_MIN, and everything else return 0?
First off, ^ itself isn't what's special here. If you XOR anything with zero, or OR anything with zero, you just get back the original answer. What you're seeing here is not part of the operation itself, but rather what happens before the operation: the bitwise operators take integers, so PHP converts the float to an integer. It's in the float-to-integer conversion that the weird behaviour appears, and it's not exclusive to the bitwise operators. It also happens for (int), for example.
Why does it produce these weird results? Simply because that's what the C code PHP is written in produces when converting a float to an integer. In the C standard, C's behaviour for float-to-integer conversions is undefined for the special values of INF, -INF and NAN (or, more accurately, for "integral parts" an integer can't represent: ยง6.3.1.4). This undefined behaviour means the compiler is free to do whatever it wants. It just so happens in this case that the code it generates produces the minimum integer value here, but there's no guarantee that will always happen, and it's not consistent across platforms or compilers.1 Why did the behaviour change between 5.4 and 5.5? Because PHP's code for converting floats to integers changed to always perform a modulo conversion. This fixed the undefined behaviour for very large floating-point numbers,2 but it still didn't check for special values, so for that case it still produced undefined behaviour, just slightly different this time.
In PHP 7, I decided to clean up this part of PHP's behaviour with the Integer Semantics RFC, which makes PHP check for the special values (INF, -INF and NAN) and convert them consistently: they always convert to integer 0. There's no longer undefined behaviour at work here.
1 For example, a test program I wrote in C to try to convert Infinity to an integer (specifically a C long) has different results on 32-bit and 64-bit builds. The 64-bit build always produces -9223372036854775808, the minimum integer value, while the 32-bit build always produces 0. This behaviour is the same for GCC and clang, so I guess they're both producing very similar machine code.
2 If you tried to convert a float to an integer, and that float's value was too big to fit in an integer (e.g. PHP_INT_MAX * 2, or PHP_INT_MIN * 2), the result was undefined. PHP 5.5 makes the result consistent, though unintuitive (it acts if the float was converted to a very large integer, and the most significant bits were discarded).
Your float(INF) gets implicitly casted to an Integer.
and XOR with 0 does not change the first parameter. So basically this is just a cast from float to int which is undefined for values which are not in the integer range. (for all other values it will be truncated towards zero)
https://3v4l.org/52bA5
I have array like:
$array = ['id' => '76561198165327575'];
And I need it to work in JavaScript on client side. So I'm trying to encode it with JSON_NUMERIC_CHECK:
json_encode($array, JSON_NUMERIC_CHECK);
And getting result like:
{"id":7.6561198165328e+16}
But it should be:
{"id":76561198165327575}
What is wrong?
(Azure, Windows, 5.6)
JSON_NUMERIC_CHECK basically tells the encoder "If it looks like a number, encode it as a number":
php > $x = '123456789012234567890';
php > echo json_encode($x, JSON_NUMERIC_CHECK);
1.2345678901223e+20
php > echo json_encode($x);
"123456789012234567890"
And since your number exceeds the representable range for an INT on your platform, you get a float instead.
You are exceeding the bounds of integer on your 32-bit system. The documentation describes that when this occurs, the number is converted to a float.
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.
If you encode in JSON objects with large numbers (greater than PHP_MAX_INT), you will always end up getting a floating point value. The only solution is to store them in the object/array as string (that you already) and not use JSON_NUMERIC_CHECK (but convert the string to a number on the client) or write your own encoding routine.
CLARIFYING: This isn't asking why I'm getting rounding errors. I understand this is a mistake or an oversight. The question asks why it prints as whole in the first var_dump, but casting acts as if it were 57916.9repeating and truncates said .9repeating.
The following occurs:
You take a string (or float -- does not matter) that contains the value 579.17 and multiply it 100. It var_dumps the expected 57917. Not 57916.99999999999999999999999 or similar. var_dump should not be rounding anything as a debugging function in my opinion. It may have to truncate, but rounding is unexpected in a debugging function.
However, if one then casts that to an integer, you get an unexpected 57916 from var_dump.
I'm aware of issues with floating point numbers, but the act of casting a floating point number that prints as exactly 57917 in PHP apparently effectively subtracts 1. This is a very small number.
This only appears to happen for some numbers, such as 579.17. It does not occur for others I've tested. All we're doing is multiplying a number by 100 to send to an API that expects cents. The API library understandably casts to integer since the API doesn't accept fractional cents.
Test case:
php -r '$n = ("579.17" * 100); var_dump($n, (int)$n);'
Output:
float(57917)
int(57916)
Environment:
x86-32,
x86-64 both.
var_dump uses precision from php.ini to display float value. You could raise it to see what happens.
php -r 'ini_set("precision", 20); $n = ("579.17" * 100); var_dump($n, (int)$n);'
// double(57916.999999999992724)
// int(57916)
Also. There is no matter x86 or x64. PHP uses 64 bits for floats.
http://php.net/manual/en/language.types.float.php
Use round() instead of int(). The actual value of 579.17 * 100 is something like 57916.99999. var_dump() shows this as 57917, but when you use int() it truncates the fraction. Using round() will go to the nearest integer, rather than always truncating down.
I believe this is because hardware cannot truly and accurately express floating point numbers. So what appears as 579.17 is actually more like 579.16999999. So when you multiply it and cast it as an int it truncates the decimal leaving you with 57916.
I have a variable $x whose value is read in from an XML file. The value being read from the XML is 1.963788, nothing more, nothing less. When I output $x, I see that the value in $x is in fact 1.963788. All is right with the world.
But then when I use x in an equation such as
$pl = $x*125.0-200.0;
The value of $pl ends up being -75. For whatever reason, PHP seems to be ignoring, or just getting rid of, the digits to the right of the decimal point in $x, which makes $x contain 1. I thought maybe there was a snowball's chance in hell that this occurred in other languages too, so I wrote it up in C++ and, big surprise, I get the right answer of 45.4735.
Anyone ever encountered this before or know what's going on? Thanks.
Have you tried using floatval?
Maybe PHP interprets your number as a string and the standard conversion just casts it to integer.
It probably is due to the fact that $x is being interpreted as a string, and converted to an integer and not a float value.
Try:
$pl = (float) $x * 125.0 - 200.0;
Your number appears to have failed casting as a float. If I use '1,963788' I get your result. If I use '2,963788' I receive a result of 50. According to the PHP docs for intval (and that's what it appears PHP is trying to cast this as, an integer):
Strings will most likely return 0 although this depends on the leftmost characters of the string. The common rules of integer casting apply.
Check the value $x actually has carefully. It may not be what you expect since PHP seems to disagree that it is, in fact, a float or it would have typed it as such.
Just before you compute $pl, do a var_dump on $x to see what is the actual value stored in it. I've tried your code and it is returning the correct value 45.4735, so I might not be PHP's fault.