的Delphi 2009添加的GetHashCode函数TObject的。 GetHashCode返回其用于在TDictionary散列一个整数。

如果您希望对象在TDictionary很好地工作,则需要重写GetHashCode适当,使得在一般情况下,不同的对象返回不同的整数的散列码。

但你怎么包含双字段的对象呢?你如何把这些双值转换为整数的GetHashCode的?

它通常是用Java做的方式,比方说,就是用像Double.doubleToLongBits或Float.floatToIntBits的方法。后者的优点是它描述文档如下:“返回根据IEEE 754浮点一个指定的浮点值的表示‘单一格式’位布局”。这涉及到一些位操作与用于浮点值的不同位不同的掩模。

是否有这是否在Delphi一个功能?

有帮助吗?

解决方案

我建议在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的东西可以在Delphi中实现这样的:

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(单)= SIZEOF(整数))。如果你的值可以在单精度无碰撞来表示,这将提供一个良好的哈希值。

编辑:由于类型转换不会在我D2009编译,我适于所述变体记录溶液

使用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