If I do this in PHP:
echo (int)9223372036854775808;
The output is -9223372036854775808, which makes perfect since since 9223372036854775807 in binary is:
0111 ... 1
i.e., 0 followed by 63 ones. And obviously 1 in binary is just 1, so when I add them I get 1000...0 (1 with 63 0s after it) which is -9223372036854775808 in 2s complement notation.
So I would expect if I did something like add -1 to -9223372036854775808, I would get back 9223372036854775807. An analogy in 4 bit binary would be like:
1000 (-8)
1111 (-1)
----
0111 (7)
I understand that I can't simply assign -9223372036854775809 to a variable because there is no representation of that in 64 bit signed integers, but why doesn't this work:
$smallest_int = (int)-9223372036854775808;
echo (int)($smallest_int-1); //similar to 1000+1111 in 4 bit
When I run this the output is still -9223372036854775808. Why does that happen? Is it something to do with PHP's weak typing? Does this happen in other languages (I know it definitely doesn't happen in C)?
It's true that 9223372036854775808 becomes -9223372036854775808, but it's not so simple as just "integers wrap around". Here are a few more mappings (found by experimentation):
So you might think that numbers outside the int
range all get mapped to -9223372036854775808 — but wait! :
All of which seems quite arbitrary to me. I think what's happening is that values that are over 18 digits long (and hence easily recognized as being outside the integer range) get essentially discarded and replaced with zero, whereas values that are 18 digits long get parsed just in case they are in range, but using logic that's not designed for, and not intended to be coherent for, values that are out of range.