PHP с битовым сдвигом влево на 32 пробела и плохие результаты с большими числами арифметических операций - PullRequest
3 голосов
/ 17 марта 2010

У меня есть следующие проблемы:

Во-первых: я пытаюсь сделать 32-разрядный битовый сдвиг влево на большое число, и по какой-то причине число всегда возвращается как есть. Например:

echo(516103988<<32); // echoes 516103988

Поскольку сдвиг битов влево на один пробел эквивалентен умножению на 2, я попытался умножить число на 2 ^ 32, и это работает, он возвращает 2216649749795176448.

Второе: мне нужно добавить 9379 к числу из вышеуказанного пункта:

printf('%0.0f', 2216649749795176448 + 9379); // prints 2216649749795185920 

Следует напечатать: 2216649749795185827

Ответы [ 3 ]

4 голосов
/ 17 марта 2010

Целочисленная точность Php ограничена размером машинного слова (32, 64). Для работы с целыми числами произвольной точности вы должны хранить их как строки и использовать bc или библиотеку gmp:

   echo bcmul('516103988', bcpow(2, 32));  // 2216649749795176448
4 голосов
/ 17 марта 2010

Основываясь на предложениях Паскаля МАРТИНА, я попробовал и BCMath, и расширение GMP и предложил следующие решения:

С BCMath:

$a = 516103988;
$s = bcpow(2, 32);    
$a = bcadd(bcmul($a, $s), 9379);
echo $a; // works, echoes 2216649749795185827

С GMP:

$a = gmp_init(516103988); 
$s = gmp_pow(gmp_init(2), 32); 
$a = gmp_add(gmp_mul($a, $s), gmp_init(9379)); 
echo gmp_strval($a);  // also works

Из того, что я понимаю, гораздо больше шансов установить BCMath на сервере, чем GMP, поэтому я буду использовать первое решение.

Спасибо:)

4 голосов
/ 17 марта 2010

Выполнение 32-битных операций смещения, вероятно, не будет работать так, как вы ожидаете, поскольку целые числа, как правило, хранятся в 32-битных.

Цитирование этой страницы: Битовые операторы

Не сдвиг вправо более 32 биты в 32-битных системах.
Не осталось сдвиг в случае, если это приводит к числу длиннее 32 бит.
Использование функций из расширения gmp для побитового манипулирование числами за пределами PHP_INT_MAX.

...