Принудительное переполнение целых чисел PHP

У нас есть целочисленная арифметика, которая по историческим причинам должна работать на PHP так же, как на нескольких статически типизированных языках. Начиная с последнего обновления PHP, поведение для переполненных целых чисел изменилось. В основном мы используем следующую формулу:

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

Однако даже при конверсиях:

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

Я все еще получаю совершенно неправильный номер ...

Например, с $ x1 = -1580033017, $ x2 = -2072974554, $ x3 = -1170476976) и $ x4 = -1007518822, в итоге я получаю -30512150 в PHP и 1617621783 в C #.

Просто добавляя вместе $ x1 и $ x2, я не могу получить правильный ответ:

В C # я получаю

(-1580033017 + -2072974554) = 641959725

В PHP:

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

это то же самое, что:

intval(-1580033017 + -2072974554) = -2147483648

Я не против писать функцию IntegerOverflowAdd или что-то в этом роде, но я не могу понять, как (-1580033017 + -2072974554) равно 641959725. (Я действительно признаю, что это -2147483648 + (2 * 2 ^ 31) , но -2147483648 + 2 ^ 31 - -1505523923, что больше, чем Int.Min, так почему вы добавляете 2 * 2 ^ 31, а не 2 ^ 31?)

Любая помощь будет оценена ...

c#,php,integer-overflow,

7

Ответов: 6


13 принят

Поэтому я решил проблему и много узнал о PHP (по крайней мере, так, как он справляется с переполнением Integer).

1) Это полностью зависело от того, на какой платформе работает машина, в какой версии PHP, независимо от того, был ли запущен Suhosin Hardened PHP, и сколько битов было скомпилировано для (32 или 64). 6 велись так, как я ожидал (что было фактически неправильно, по крайней мере, неправильно в соответствии с их документацией), и 3 машины вели себя так, как я все еще не могу объяснить, и 3 машины вели себя в соответствии с тем, что говорит команда intval в документация.

2) Предполагается, что Intval вернет PHP_MAX_INT, когда int> PHP_MAX_INT (не int & 0xffffffff), но это происходит только в некоторых версиях PHP4 и PHP5. Различные версии PHP возвращают разные значения при int> PHP_MAX_INT.

3) Следующий код может возвращать 3 разных результата (см. 1):

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

Он может вернуться (что кажется правильным для Intval, но неверно для & 0xffffff)

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

И он может вернуться (что противоречит документации PHP для intval):

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

И на 64-битных машинах возвращается (что правильно):

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

Решение

Во всяком случае, мне нужно решение, которое будет работать на всех этих платформах, и не будет зависеть от особенностей конкретной версии PHP, скомпилированной с конкретным Max int. Таким образом, я использую следующую кросс-PHP функцию тридцать TwwBitIntval:

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

Комментарий

Я считаю, что разработчики PHP должны сказать, что Int - это 32-битный Int, независимо от того, работает ли он на 32-разрядной или 64-битной машине (например, в среде DOTNet CLR) и не случайно повышал ее до float в зависимости от количества битов, которые PHP является компилятором.


11 ов

Если вы хотите иметь 100% -ное рабочее решение для 32-битного intval как на 32 и 64-битных платформах, я предлагаю вам использовать следующее решение:

function intval32bits($value)
{
    $value = ($value & 0xFFFFFFFF);

    if ($value & 0x80000000)
        $value = -((~$value & 0xFFFFFFFF) + 1);

    return $value;
}

3

Внутри PHP для большинства чисел использует «целочисленный» тип. Тем не менее, они только заходят так далеко: если вы добавите большое целое число в большое целое число, PHP увидит, что результат слишком велик, чтобы вписаться в нормальное целое число и назначит его числу с плавающей запятой. Однако числа с плавающей запятой (float) только поднимаются так высоко, и есть точка вокруг шестнадцатизначной метки, где PHP просто потеряет сюжет целиком.

Существует возможность использовать математику произвольной точности, которая поддерживает числа любого размера и точности, представленные в виде строк . Подробнее см. Здесь: http://us2.php.net/bc


2

Я думаю, что это может быть связано с тем, что целое число в PHP составляет 32 бита без знака, так как в C # они по умолчанию 32 бита.

Вы играете с числами на краю нормального диапазона 31-32 бит.

См. Дополнительную документацию в руководстве по PHP:

http://www.php.net/manual/en/language.types.integer.php

Размер целого зависит от платформы, хотя максимальное значение около двух миллиардов - это обычное значение (это 32 бита). PHP не поддерживает целые числа без знака. Целочисленный размер может быть определен с использованием константы PHP_INT_SIZE и максимального значения с использованием константы PHP_INT_MAX с PHP 4.4.0 и PHP 5.0.5.


2

Будет ли это работать?

echo (-1580033017 + -2072974554) & 0xffffffff

Чтобы обобщить, вы могли бы сделать (простить любые синтаксические ошибки, я не дотрагивался до PHP в течение длительного времени):

function s32add($a, $b) {
    return ($a + $b) & 0xffffffff;
}
C #, PHP, целое число, переполнение,
Похожие вопросы