2011-10-16 17 views
7

Mam dość prostą funkcję w Delphi, który pobiera ciąg i daje całkowitą hashed podstawie tego napisu:Delphi bitowe proc konwersji do PHP

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; 

jestem przekształcenie go do PHP, ale wyniki nie są to samo. To jest to, co mam w 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; 
} 

jeśli przejdą w teststring ciąg do funkcji Delphi dostać 195831015 jednak PHP zwraca 72559895. zauważyłem różnica staje się widoczna dopiero po 7 znaków. Jeśli ciąg testowy jest tylko testem, wyniki są identyczne.

PHP wydaje się mieć pewne trudności z przesunięcia ujemną liczbę całkowitą w prawo na przykład folowing wiersz:

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

zmieniony na przesunięcie w lewo $ X < < 24 daje te same wartości jak Delphi dla zmiennej X , ale wyniki są nadal różne.

Czy brakuje tu czegoś naprawdę oczywistego?

EDIT: Wyjście z dwoma funkcjami są:

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 

więc nie aż znak "i", że PHP rozpoczyna wysiąść utwór z obliczeniami

EDIT2:

funkcja Dodany PHP zrobić logiczną prawy shift zamiast przesunięcia arytmetycznego:

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

Działa to teraz! Również dzięki Ignacio za pomysł maski :)

Odpowiedz

1

Czy jesteś pewien, że Delphi ma rację, a PHP jest nieprawidłowe?

Delphi shl and shr podobno może zachowywać się nieprzewidywalnie z podpisanych liczb całkowitych. Patrz: http://www.merlyn.demon.co.uk/del-bits.htm#SAR. Dr Stockton wydaje się sugerować, że istnieją dwa rodzaje operacji zmianowych: przesunięcie arytmetyczne (utrzymanie znaku) i przesunięcia logiczne.

Dokumenty (http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/expressions_xml.html) nie są bardzo jasne na temat wpływu shl/shr na liczby całkowite ze znakiem. Wspominają jednak, że shr/shl o jeden jest porównywalny tylko do divions/mnożenia przez 2 dla liczb całkowitych niepodpisanych.

Nie mogłem znaleźć tego, co dr Stockton (z pierwszego linka) nazywa logicznymi operacjami przesunięcia, ale wydaje się to logiczne :-), aby spróbować zmienić implementację delphi tak, aby używała niepodpisanego 8-bajtowego typu (pojawia się DWORD na myśl) i zobacz, jaki to ma efekt.

+0

Dzięki za podpowiedź - sprawdzenie instrukcji PHP ponownie ukazuje, że zmiana bitowa jest tylko arytmetyczna. Miałem to działające w Delphi z dodatkową maską bitową, ale potem pomyślałem, że lepiej byłoby zmusić PHP do zrobienia tego, co chcę - zobacz edycję dla dodatkowego kodu – Rucia

1

Maskuj wybrane kawałki.

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

dziękuję, chociaż liczba bitów, których potrzebuję, to 0x7FFFFFFF.Oznacza to, że wyniki są nadal niespójne między Delphi i PHP. Te dwie procedury będą działać w połączeniu ze sobą, więc muszą za każdym razem generować takie same wyniki. – Rucia

+0

Jeśli masz prawo-przesuwanie 24, a następnie nie, pozostało ci tylko 8 bitów. –