Asked  8 Months ago    Answers:  4   Viewed   35 times

We have some integer arithmetic which for historical reasons has to work the same on PHP as it does in a few statically typed languages. Since we last upgraded PHP the behavior for overflowing integers has changed. Basically we are using following formula:

function f($x1, $x2, $x3, $x4)
{
   return (($x1 + $x2) ^ $x3) + $x4;
}

However, even with conversions:

function f($x1, $x2, $x3, $x4)
{
   return intval(intval(intval($x1 + $x2) ^ $x3) + $x4);
}

I am still ending up with the completely wrong number...

For example, with $x1 = -1580033017, $x2 = -2072974554, $x3 = -1170476976) and $x4 = -1007518822, I end up with -30512150 in PHP and 1617621783 in C#.

Just adding together $x1 and $x2 I cannot get the right answer:

In C# I get

(-1580033017 + -2072974554) = 641959725

In PHP:

intval(intval(-1580033017) + intval(-2072974554)) = -2147483648

which is the same as:

intval(-1580033017 + -2072974554) = -2147483648

I don't mind writing a "IntegerOverflowAdd" function or something, but I can't quite figure out how (-1580033017 + -2072974554) equals 641959725. (I do recognize that it is -2147483648 + (2 * 2^31), but -2147483648 + 2^31 is -1505523923 which is greater than Int.Min so why is do you add 2*2^31 and not 2^31?)

Any help would be appreciated...

 Answers

76

So I solved the problem, and discovered a lot about PHP (at least in the way it handles Integer overflow).

1) It completely depended on a cross between which platform the machine was running on, which version of PHP, whether or not it had Suhosin Hardened PHP running, and how many bits it was compiled for (32 or 64). 6 machines behaved the way I expected (which was actually wrong, at least wrong according to their documentation) and 3 machines behaved in a way I still can't explain, and 3 machines behaved according to what the intval command says it does in the documentation.

2) Intval is supposed to return PHP_INT_MAX when int > PHP_INT_MAX (not int & 0xffffffff), but this only happens on some versions of PHP4 and PHP5. Different versions of PHP return different values when int > PHP_INT_MAX.

3) The following code can return 3 different results (see 1):

<?php
echo "Php max int: ".PHP_INT_MAX."n";
echo "The Val: ".(-1580033017 + -2072974554)."n";
echo "Intval of the val: ".intval(-3653007571)."n";
echo "And 0xffffffff of the val: ".(-3653007571 & 0xffffffff)."n";
?>

It can return (which appears to be right for Intval but wrong for & 0xffffff)

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -2147483648
And of the val: -2147483648

And it can return (which contradicts the PHP documentation for intval):

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -641959725
And of the val: -641959725

And on 64 Bit machines it returns (which is correct):

Php max int: 2147483647
The Val: -3653007571
Intval of the val: -3653007571
And of the val: -641959725

Solution

Anyhow, I needed a solution that would work on all these platforms, and not be dependent upon quirks of a particular version of PHP compiled with a particular Max int. Thus I cam up with the following cross-PHP thirtyTwoBitIntval function:

function thirtyTwoBitIntval($value)
{
    if ($value < -2147483648)
    {
        return -(-($value) & 0xffffffff);
    }
    elseif ($value > 2147483647)
    {
        return ($value & 0xffffffff);
    }
    return $value;
}

Comment

I do think the designers of PHP should have said an Int is a 32 Bit Int no matter whether it is running on a 32 or 64 or 128 bit machine (like the DotNet CLR for example), and didn't randomly upconvert it to a float depending on the number of Bits that PHP is compiler under.

Wednesday, March 31, 2021
 
samayo
answered 8 Months ago
62

unsigned numbers can't overflow, but instead wrap around using the properties of modulo.

For instance, when unsigned int is 32 bits, the result would be: (a * b) mod 2^32.


As CharlesBailey pointed out, 253473829*13482018273 may use signed multiplication before being converted, and so you should be explicit about unsigned before the multiplication:

unsigned int someint = 253473829U * 13482018273U;
Thursday, June 3, 2021
 
Shobit
answered 5 Months ago
70

Python3

Only floats have a hard limit in python. Integers are are implemented as “long” integer objects of arbitrary size in python3 and do not normally overflow.

You can test that behavior with the following code

import sys

i = sys.maxsize
print(i)
# 9223372036854775807
print(i == i + 1)
# False
i += 1
print(i)
# 9223372036854775808

f = sys.float_info.max
print(f)
# 1.7976931348623157e+308
print(f == f + 1)
# True
f += 1
print(f)
# 1.7976931348623157e+308

You may also want to take a look at sys.float_info and sys.maxsize

Python2

In python2 integers are automatically casted to long integers if too large as described in the documentation for numeric types

import sys

i = sys.maxsize
print type(i)
# <type 'int'>

i += 1
print type(i)
# <type 'long'>

Could result *= factor fail for the same reason?

Why not try it?

import sys

i = 2
i *= sys.float_info.max
print i
# inf

Python has a special float value for infinity (and negative infinity too) as described in the docs for float

Sunday, August 22, 2021
 
Extrakun
answered 2 Months ago
82

Try logging the intValue of the NSNumber instead:

NSLog(@"  %dn", [(NSNumber *)[factorList objectAtIndex:j] intValue]);
Wednesday, September 1, 2021
 
Vaishak Suresh
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :