문제

Delphi 2009는 gethashcode 함수를 Tobject에 추가했습니다. gethashcode는 tdictionary에서 해싱에 사용되는 정수를 반환합니다.

tdictionary에서 객체가 잘 작동하기를 원한다면, 다른 객체가 다른 정수 해시 코드를 반환하도록 gethashcode를 적절하게 무시해야합니다.

그러나 이중 필드가 포함 된 물체는 무엇을합니까? 이중 값을 gethashcode의 정수로 어떻게 바꾸나요?

예를 들어 Java에서 일반적으로 수행되는 방식은 Double.doubletolongbits 또는 Float.FloatointBits와 같은 방법을 사용하는 것입니다. 후자는 다음과 같이 설명하는 문서를 가지고 있습니다. 여기에는 부동 소수점 값의 다른 비트에 대해 다른 마스크가있는 약간의 비트 연산이 포함됩니다.

델파이에서 이것을하는 함수가 있습니까?

도움이 되었습니까?

해결책

Gamecat 코드에 비해 다음과 같은 개선을 제안합니다.

type
  TVarRec = record
    case Integer of
      0: ( FInt1, FInt2 : Integer; )
      1: ( FDouble : Double; )
  end;

function Convert(const ADouble: Double): Integer;
var
  arec : TVarRec;
begin
  arec.FDouble := ADouble;
  Result := arec.FInt1 xor arec.FInt2;
end;

이것은 이중 값의 모든 비트를 고려합니다.

(의견은 코드와 잘 작동하지 않습니다)

다른 팁

더블을 정수에 매핑하려면 변형 레코드를 사용할 수 있습니다.

type
  TVarRec = record
    case Integer of
      0: ( FInt : Integer; )
      1: ( FDouble : Double; )
  end;


function Convert(const ADouble: Double): Integer;
var
  arec : TVarRec;
begin
  arec.FDouble := ADouble;
  Result := arec.FInt;
end;

이것이 값을 해석하지 않고 약간의 복사를한다는 것을 조심하십시오.

또 다른 (더러운 트릭의 종류는 절대 변수를 사용하는 것입니다.

function Convert(const ADouble: Double): Integer;
var
  tempDouble : Double;
  tempInt    : Integer absolute tempDouble; // tempInt is at the same memory position as tempDouble.
begin
  tempDouble := ADouble;
  Result := tempInt;
end;

gethashcode의 기본값은 이미 각 객체마다 고유 한 숫자 인 객체의 메모리 주소를 반환하기 때문에 이와 같은 일을 할 필요가 없습니다. 또한 객체에 포함 된 데이터를 변경하면 기본 해시 값이 변경되지 않습니다.

값이 3.5 인 더블이 포함 된 객체가 있고 해시에 사전에 넣으면 12345678의 해시 코드가 있습니다. 필드가 변경되고 이제는 5.21의 값을 얻었습니다. 다음에 해시 값을 계산하려고 할 때 해시 코드는 이제 23456789이며 조회가 실패합니다.

이것이 결코 일어나지 않을 것이라고 보장 할 수없고, 메모리 주소를 사용하지 않는 것이 정말 좋은 이유가 없다면, 가장 좋은 방법은 gethashcode를 그대로 두는 것입니다. (파산하지 않았다면 고치지 마십시오.)

Java는 다음과 같이 델파이에서 구현 될 수 있다고 생각합니다.

type
  TVarRec = record
    case Integer of
      0: ( FInt1: Integer; )
      1: ( FSingle: Single; )
  end;

function GetHashCode(Value: Double): Integer;
var
  arec: TVarRec;
begin
  arec.FSingle := Value;
  Result := arec.FInt1;
end;

뒤에 아이디어는 정수의 이진 크기 (sizeof (single) = sizeof (정수))와 일치하도록 이중 값의 정밀도를 줄이는 것입니다. 충돌없이 단일 정밀도로 값을 표현할 수 있다면 좋은 해시 값을 제공합니다.

편집 : D2009에서 TypeCast가 컴파일되지 않으므로 변형 레코드 솔루션을 조정했습니다.

이중 데이터에서 CRC32를 사용하십시오 xor 악입니다.

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TVarRec = record
    case Integer of
      0: ( FInt1, FInt2 : Integer; );
      1: ( FDouble : Double; );
  end;

function Convert(const ADouble: Double): Integer;
var
  arec : TVarRec;
begin
  arec.FDouble := ADouble;
  Result := arec.FInt1 xor arec.FInt2;
end;

var
  FDoubleVar1, FDoubleVar2: TVarRec;
  HashCode1, HashCode2: Integer;
begin
  // Make a Double
  FDoubleVar1.FInt1 := $DEADC0DE;
  FDoubleVar1.FInt2 := $0C0DEF00;

  // Make another Double
  FDoubleVar2.FInt1 := $0C0DEF00;
  FDoubleVar2.FInt2 := $DEADC0DE;

  WriteLn('1rst Double   : ', FDoubleVar1.FDouble);
  WriteLn('2nd Double    : ', FDoubleVar2.FDouble);

  HashCode1 := Convert(FDoubleVar1.FDouble);
  HashCode2 := Convert(FDoubleVar2.FDouble);

  WriteLn('1rst HashCode : ', HashCode1);
  WriteLn('2nd HashCode  : ', HashCode2);

  if HashCode1 = HashCode2 then
  begin
    WriteLn('Warning: Same HashCode!');
  end;
  ReadLn;
end.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top