Delphi побитовый процесс преобразования в PHP

У меня есть довольно простая функция в Delphi, которая берет строку и производит хешированное целое число на основе этой строки:

function TfrmMain.HashElf(const Buf;  BufSize : LongInt) : LongInt;
 var
 Bytes : TByteArray absolute Buf;
 I, X  : LongInt;
begin
  Result := 0;
  for I := 0 to BufSize - 1 do begin
    Result := (Result shl 4) + Bytes[I]; 
    X := Result and $F0000000;
    if (X <> 0) then  Result := Result xor (X shr 24);
    Result := Result and (not X);
  end;
end;

Я конвертирую его в PHP, но результаты не совпадают. Вот что я получил в PHP:

function HashElf($Buf, $BufSize){
  $Bytes = str_split($Buf);

  for ($i= 0; $i<$BufSize;$i++){
    $Result = ($Result << 4) + Ord($Bytes[$i]);

    $X = $Result & (0xF0000000);
    if ($X<>0){$Result = $Result ^ ($X>>24);}

    $Result = ($Result & (~ $X));
  }
  return $Result;
}

если вы передадите строку testtring в функцию Delphi, вы получите 195831015, однако PHP вернет 72559895. Я заметил, что разница становится очевидной только после 7 символов. Если тестовая строка является просто тестовой, результаты идентичны.

PHP, похоже, испытывает некоторые трудности с перемещением отрицательного целого числа вправо, например, следующей строки:

 if ($X<>0){$Result = $Result ^ ($X>>24);}

изменено на shift влево $ X << 24 выдает те же значения, что и Delphi для переменной X, но результаты по-прежнему разные.

Я что-то упускаю здесь действительно очевидное?

РЕДАКТИРОВАТЬ: выходные данные двух функций:

Delphi

  Char: t   Result: 116        X: 0
  Char: e   Result: 1957       X: 0
  Char: s   Result: 31427      X: 0
  Char: t   Result: 502948     X: 0
  Char: s   Result: 8047283    X: 0
  Char: t   Result: 128756644  X: 0
  Char: r   Result: 181058242  X: 1879048192
  Char: i   Result: 212577321  X: -1610612736
  Char: n   Result: 180011582  X: -1073741824
  Char: g   Result: 195831015  X: -1610612736

PHP

  Char: t   $Result: 116         $X: 0
  Char: e   $Result: 1957        $X: 0
  Char: s   $Result: 31427       $X: 0
  Char: t   $Result: 502948     $X: 0
  Char: s   $Result: 8047283    $X: 0
  Char: t   $Result: 128756644  $X: 0
  Char: r   $Result: 181058242  $X: 1879048192
  Char: i   $Result: 212577417  $X: -1610612736
  Char: n   $Result: 180013310  $X: -1073741824
  Char: g   $Result: 195858503  $X: -1610612736

Так что нет, пока символ "я", что PHP начинает сбиваться с расчетов

EDIT2:

Добавлена ??функция PHP для логического сдвига вправо вместо арифметического сдвига:

function lshiftright($var,$amt)
{
  $mask = 0x40000000;
  if($var < 0)
  {
    $var &= 0x7FFFFFFF;
    $mask = $mask >> ($amt-1);
    return ($var >> $amt) | $mask;
  }else{
    return ($var >> $amt);
  }
}

Это сейчас работает! Также спасибо Игнасио за идею маски :)

php,delphi,bit-manipulation,

7

Ответов: 2


1 принят

Вы уверены, что Delphi прав, а PHP не прав?

З Delphi и SHR - видимому , могут вести себя непредсказуемо с подписанными целыми числами. Смотрите: http://www.merlyn.demon.co.uk/del-bits.htm#SAR . Доктор Стоктон, кажется, подразумевает, что есть два типа операций сдвига: арифметический сдвиг (сохранение знака) и логические сдвиги.

Документы ( http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/expressions_xml.html ) не очень ясно показывают влияние shl / shr на целые числа со знаком. Однако они упоминают, что shr / shl на единицу сравнимо только с делением / умножением на 2 для целых чисел без знака .

Я не смог найти то, что доктор Стоктон (из первой ссылки) называет операциями логического сдвига, но казалось бы логичным :-) попробовать изменить реализацию delphi для использования 8-байтового типа без знака (приходит на ум DWORD) и посмотрим, какой эффект это имеет.


Маска битов, которые вы хотите.

if ($X<>0){$Result = ($Result ^ ($X>>24)) & 0xFF;}
PHP, Дельфы, бит манипуляции,
Похожие вопросы