У нас есть целочисленная арифметика, которая по историческим причинам должна работать на 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?)
Любая помощь будет оценена …
Поэтому я решил проблему и много узнал о 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."\n"; echo "The Val: ".(-1580033017 + -2072974554)."\n"; echo "Intval of the val: ".intval(-3653007571)."\n"; echo "And 0xffffffff of the val: ".(-3653007571 & 0xffffffff)."\n"; ?>
Он может вернуться (что кажется правильным для 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 является компилятором.
Если вы хотите иметь 100% -ное рабочее решение для 32-битного intval как на 32 и 64-битных платформах, я предлагаю вам использовать следующее решение:
function intval32bits($value) { $value = ($value & 0xFFFFFFFF); if ($value & 0x80000000) $value = -((~$value & 0xFFFFFFFF) + 1); return $value; }
Внутри PHP для большинства чисел использует «целочисленный» тип. Тем не менее, они только заходят так далеко: если вы добавите большое целое число в большое целое число, PHP увидит, что результат слишком велик, чтобы вписаться в нормальное целое число и назначит его числу с плавающей запятой. Однако числа с плавающей запятой (float) только поднимаются так высоко, и есть точка вокруг шестнадцатизначной метки, где PHP просто потеряет сюжет целиком.
Существует возможность использовать математику произвольной точности, которая поддерживает числа любого размера и точности, представленные в виде строк . Подробнее см. Здесь: http://us2.php.net/bc
Я думаю, что это может быть связано с тем, что целое число в 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.
Будет ли это работать?
echo (-1580033017 + -2072974554) & 0xffffffff
Чтобы обобщить, вы могли бы сделать (простить любые синтаксические ошибки, я не дотрагивался до PHP в течение длительного времени):
function s32add($a, $b) { return ($a + $b) & 0xffffffff; }
Проверьте свой номер версии PHP – я полагаю, вы можете получить разные результаты с разными версиями PHP, которые могут иметь разную поддержку для длинных целых чисел. Я считаю, что была ошибка с длинными целыми числами, наконец, в одной из версий PHP 5.
В версии PHP 5.2.0 – ответ ТОЧНО так же, как вы получили в C #
1617621783,
используя точную функцию, которую вы имеете выше.
Вы можете использовать команду phpinfo (), чтобы легко найти номер своей версии.
$x1 = -1580033017; $x2 = -2072974554; $x3 = -1170476976 ; $x4 = -1007518822; echo f($x1, $x2, $x3, $x4); function f($x1, $x2, $x3, $x4) { return intval(intval(intval($x1 + $x2) ^ $x3) + $x4); }