Проблема побитовых операторов (32-bit vs. 64-bit)
16.01.2009, 18:31Рубрика: php
Хостинг сделал апгрейт, и в связи с этим появились неправильные решения “исключающего или” (^, xor) и “сдвига влево/вправо” (>>/<<, shl/shr). Кроме этого, перевод чисел из одной системы исчисления в другую, тоже некорректное. Неправильные они, если сравнивать результаты 32-х c 64-х битной системами, плюс некорректное преобразование отрицательных чисел:
32-bit: -540315700
64-bit: -2147432291
-4835268783 << 12 (shl)
32-bit: -1166733312
64-bit: 0
В голове идеи по созданию пользовательских функций, которые будут "исключать" и "сдвигать" двоичные числа. Но не все так просто! Есть несколько функций по преобразованию из десятичной системы в двоичную: decbin, base_convert и sprint_f:
32-bit: 11011111110010111010011101010001 (правильное решение)
64-bit: 10000000000000000000000000000000 (ну это жесть!)
base_convert(-4835268783,10,2)
32-bit: 100100000001101000101100010101111
64-bit: 100100000001101000101100010101111
Ооо.. Результат base_convert одинаков, но выдал он ерунду, преобразовав "4835268783" вместо "-4835268783". А нам нужны отрицательные числа тоже. Все функции подвели, и пришлось изобретать велосипед. Пишем свою функцию dec2bin, а потом уже приступим и к xor, и к shl.
{
$result = '';
$shift = 0;
if ($dec<0)
{
$minus=true; // отрицательное
$dec=-1*($dec+1); // делаем NOT, чтоб делить положительное число, но ставим флаг что отрицательное
} else {
$minus=false;
}
while ( pow(2, $shift) < $dec ) // стандартные наработки
{
++$shift;
}
while ( 0 <= $shift )
{
$pow = pow(2, $shift);
if ( $pow <= $dec )
{
$dec-= $pow;
$result = $result . ($minus?'0':'1'); // если отрицательное число у нас, то NOT
} else {
$result = $result . ($minus?'1':'0');
}
--$shift;
}
$result=str_pad($result, 64, ($minus?"1":"0"), STR_PAD_LEFT);
// заполняем результат слева, чтобы было 64 символа (дальше поймете почему)
return $result;
}
В результате получаем адекватные результаты:
32-bit: 1111111111111111111111111111111011011111110010111010011101010001
64-bit: 1111111111111111111111111111111011011111110010111010011101010001
Теперь xor (^) и shl (<<):
{
$c='0000000000000000000000000000000000000000000000000000000000000000';
$a=dec2bin($a);
$b=dec2bin($b);
for ($i=63;$i>=0;$i--)
{
$c[$i]=((int)$a[$i]^(int)$b[$i]); // обычный xor, только у нас по побитам
}
$c=bin2dec($c); // !!! описано ниже!
return $c;
}
function shl($a, $bit) // shr делается так же, только нули добавляются справа
{
$a=dec2bin($a);
$a=str_pad($a, 64+$bit, "0", STR_PAD_RIGHT); // добавляем справа "0" количество $bit
$c=substr($a,$bit); // а теперь отрезаем, тоесть сдвинули влево на $bit
$c=bin2dec($c); // !!! описано ниже!
return $c;
}
Добавлена функция bin2dec:
{
if ($c>'0000000000000000000000000000000001111111111111111111111111111111')
{
for ($i=63;$i>=0;$i--)
{
$c[$i]=((int)$c[$i]^1); //^1;
}
$c=base_convert(substr($c,32), 2, 10);
$c=-1*($c+1);
} else {
$c=bindec($c);
}
return $c;
}
И вот почему: стандартная функция bindec (так же как и decbin) не может нормально возвратить отрицательное число. Потому и было сделана обработка 64 битов.
Подразумевается, что больше 0000000000000000000000000000000001111111111111111111111111111111 числа, это в десятичной форме уже отрицательное. И почему же мы 64 бита используем, если можно и в 32 понять?? Пример:
32-bit: 00000000000000000000000000000011
Видно, что в 32-bit, если перевести в десятичную форму, то мы получим "3", но в итоге, ответ "-4294967293", что правильнее :) В этом и есть основа некорректных вычислений.
p.s. естественно везде можно некоторым образом оптимизировать код, все в ваших руках! ;)
Ссылки по теме:
Нет
- 32
- 64 bit vs 32 bit
- php function xor
- что такое 32
- что такое 32 bit
- 32 bit vs 64 bit
- 32 bit или 64 bit
- что лучше 32 bit или 64 bit
- 32 vs 64 bit
- php 64 bit
- что такое 64
- побитовый сдвиг c++
- что такое 32bit
- 32bit vs 64 bit
- C# побитовое сравнение
- побитовое сравнение c#
- php 64
- 32 vs 64
- перевод из двоичной системы в 32 х битную
- Побитовые операторы php
- побитовые операции с++ перевод
- shl оператор
- побитовый сдвиг c#
- c++ побитовый сдвиг
- 64 bit vs 32
- оператор shl
- побитовый сдвиг php
- что такое 64 bit
- c++ bin2dec
- php dec2bin
- C# операторы сдвига
- php 64 bit integer
- C# побитовые операции
- php shl
- php bin2dec
- побитовое сравнение в C#
- php побитовый сдвиг
- оператор побитового сдвига
- 64 vs 32
- побитовое xor php
- 32 бит
- побитовое и c#
- c# двоичные числа
- Побитовые операторы
- 64 bit integer
- 32 bit или 64 bit что лучше
- 64 vs 32 bit
- php 64 bit int
- shl shr в php
- перевод чисел в двоичную систему c++ sprintf