تحويل مزدوج إلى عدد صحيح للحصول على Gethashcode في دلفي

StackOverflow https://stackoverflow.com/questions/1288176

سؤال

أضاف دلفي 2009 وظيفة gethashcode إلى tobject. إرجاع Gethashcode عددا صحيحا يستخدم للتجزئة في التباهي.

إذا كنت تريد كائن يعمل بشكل جيد في التباهي، فأنت بحاجة إلى تجاوز Gethashcode بشكل مناسب بحيث، بشكل عام، عودة الكائنات المختلفة رموز التجزئة العدد الصحيحة المختلفة.

ولكن ماذا تفعل لكائنات تحتوي على حقول مزدوجة؟ كيف يمكنك تحويل هذه القيم المزدوجة إلى أعداد صحيحة من أجل Gethashcode؟

الطريقة التي تحدث بها عادة في جافا، على سبيل المثال، هي استخدام طريقة مثل double.doubletoLongbits أو float.floattoolbits. يحتوي الأخير على وثائق تصفها على النحو التالي: "إرجاع تمثيل للقيمة العائمة المحددة وفقا لتخطيط بت IEEE 754 الفترة العائمة" تنسيق "بتنسيق واحد". " ينطوي هذا على بعض العمليات Bitwise مع أقنعة مختلفة لمقطعات مختلفة من قيمة النقطة العائمة.

هل هناك وظيفة تفعل هذا في دلفي؟

هل كانت مفيدة؟

المحلول

أقترح التحسين التالي على رمز 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 (SizeOf (SOFE) = Sizeof (عدد صحيح)). إذا كانت قيمك ممثلة في دقة واحدة دون تصادم، فسيحدم ذلك قيمة تجزئة جيدة.

تحرير: كما لن يترجم Typecast في D2009 الخاص بي، قمت بتكييف محلول سجل المتغير.

استخدم CRC32 على البيانات المزدوجة ل زور هو الشر.

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