Delphi побитовый процесс преобразования в PHP - PullRequest
7 голосов
/ 16 октября 2011

У меня есть довольно простая функция в 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;
}

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

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

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

изменено на сдвиг влево $ X << 24 выдает те же значения, что и Delphi для переменной X, но результаты все равно другие. </p>

Мне не хватает чего-то действительно очевидного здесь?

EDIT: Вывод двух функций:

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

Так что до тех пор, пока персонаж "i" не начнет сбиваться с вычислений

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);
  }
}

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

Ответы [ 2 ]

1 голос
/ 16 октября 2011

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

Очевидно, что Delphi shl и 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) и посмотреть, какой эффект это имеет.

1 голос
/ 16 октября 2011

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

if ($X<>0){$Result = ($Result ^ ($X>>24)) & 0xFF;}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...