developing.name Решение проблем разработки сайтов. uncat php javascript jquery ajax html other C#

Проблема побитовых операторов (32-bit vs. 64-bit)

16.01.2009, 18:31
Рубрика: php

Хостинг сделал апгрейт, и в связи с этим появились неправильные решения “исключающего или” (^, xor) и “сдвига влево/вправо” (>>/<<, shl/shr). Кроме этого, перевод чисел из одной системы исчисления в другую, тоже некорректное. Неправильные они, если сравнивать результаты 32-х c 64-х битной системами, плюс некорректное преобразование отрицательных чисел:

-4835268783 ^ 51357 (xor)

32-bit: -540315700
64-bit: -2147432291


-4835268783 << 12 (shl)

32-bit: -1166733312
64-bit: 0

В голове идеи по созданию пользовательских функций, которые будут "исключать" и "сдвигать" двоичные числа. Но не все так просто! Есть несколько функций по преобразованию из десятичной системы в двоичную: decbin, base_convert и sprint_f:

sprintf("%032b",-4835268783) и decbin(-4835268783) одинаковый результат:

32-bit: 11011111110010111010011101010001 (правильное решение)
64-bit: 10000000000000000000000000000000 (ну это жесть!)

base_convert(-4835268783,10,2)

32-bit: 100100000001101000101100010101111
64-bit: 100100000001101000101100010101111

Ооо.. Результат base_convert одинаков, но выдал он ерунду, преобразовав "4835268783" вместо "-4835268783". А нам нужны отрицательные числа тоже. Все функции подвели, и пришлось изобретать велосипед. Пишем свою функцию dec2bin, а потом уже приступим и к xor, и к shl.

function dec2bin($dec)
{
    $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;
}

В результате получаем адекватные результаты:

dec2bin(-4835268783);

32-bit: 1111111111111111111111111111111011011111110010111010011101010001
64-bit: 1111111111111111111111111111111011011111110010111010011101010001

Теперь xor (^) и shl (<<):

function xor ($a, $b)   // переменные передаются в десятичной форме
{
    $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:

function bin2dec($c)
{
 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 понять?? Пример:

64-bit: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000011
32-bit:                                 00000000000000000000000000000011

Видно, что в 32-bit, если перевести в десятичную форму, то мы получим "3", но в итоге, ответ "-4294967293", что правильнее :) В этом и есть основа некорректных вычислений.

p.s. естественно везде можно некоторым образом оптимизировать код, все в ваших руках! ;)

Ссылки по теме:

  • 16.01.2009 - Проблема побитовых операторов (32-bit vs. 64-bit)
  •  

    Комментарии

    Нет

     

    Имя*:
    e-mail*:
    URL:
    captcha*
    Текст*:
    • 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

    jQuery plugins:
    • pro.scroll v0.3 - графический скролл для div
    • pro.sres v0.1 - подсказки при поиске
    • pro.tips v0.2 - всплывающие подсказки
    • pro.tube v0.1 - работа с YouTube ссылками
    Powered by PRO