Delphi: определить const double из двоичного представления

Фон

Я хочу создать модульный тест для проверки некоторых аспектов rtl Delphi, и для этого я хочу использовать очень специфические значения с плавающей запятой IEEE, которые я хочу создать непосредственно из их двоичного представления.

Я до сих пор придумал эту рутину, и она действительно работает.

function TestIEEEDouble.BuildDoubleFromRawInt64(const aBinData:UInt64):double;
begin
  CheckEquals(sizeof(aBinData),sizeof(Result),'sizeof(aBinData),Sizeof(Result)'); // ensures we dont mess up with wrong types
  Move(aBinData,Result,sizeof(Result));
end;

Он используется следующим образом (бинданные могут быть ошибочными, но вопрос не в этом):

procedure TestIEEEDouble.Setup;
begin
  inherited;
  FSmallestPositiveDouble:=BuildDoubleFromRawInt64($0000000000000001);
  FSmallestNegativeDouble:=BuildDoubleFromRawInt64($8000000000000001);
  FLargestPositiveDouble :=BuildDoubleFromRawInt64($7FEFFFFFFFFFFFFF);
  FLargestNegativeDouble :=BuildDoubleFromRawInt64($8FEFFFFFFFFFFFFF);
end;

Вопрос

Есть ли синтаксис, который позволил бы создать const double непосредственно из двоичного (шестнадцатеричного) представления, выглядящего примерно так:

const
  cSmallestPositiveDouble:double=double($0000000000000001);

Где результат явно НЕ должен быть 1.0 (именно с таким синтаксисом), а (близко к) 4.94065645841247e-324


person H.Hasenack    schedule 16.01.2021    source источник
comment
Вы можете использовать функции только во время выполнения во встроенных объявлениях констант: begin const cSmallestPositiveDouble: Double = BuildDoubleFromRawInt64($0000000000000001);   -  person Andreas Rejbrand    schedule 17.01.2021


Ответы (2)


Это можно сделать напрямую через союзы:

type  // In a union all variables share the same address
  TAll= packed record
    case Integer of
    1:( d: Double );
    2:( i: Int64 );
    3:( f: TFileTime );
  end;

const  // Define the constant just like you would define an array
  ALL: TAll= ( i: 43 );

Остальное очевидно: либо вы теперь получаете доступ к ALL.d, чтобы увидеть, как 43 как Int64 интерпретируется как Double. Или сделать наоборот. Точно так же вы даже можете проверить, как выглядит интерпретация TFileTime, обратившись к ALL.f.

При работе с двоичным файлом или его проверке помните, что порядок байтов также важен (LE по сравнению с BE). - особенно при чтении из разных типов памяти (FS или RAM).

person AmigoJack    schedule 16.01.2021
comment
Круто, я придумал что-то подобное, но добавил неявный оператор для сокращения строк исходного кода. - person H.Hasenack; 17.01.2021
comment
См. соответствующую проблему quality.embarcadero.com/browse/RSP-32213. - person H.Hasenack; 21.01.2021

Чтобы ответить моим собственным первоначальным решением, синтаксис немного шире, чем мне нравится, но, похоже, это помогает, используя запись варианта и неявное приведение типов.

Хорошая функция/побочный эффект заключается в том, что вы можете быстро увидеть двоичное представление и двойное представление вместе в инспекторе/окне просмотра.

type
  RDoubleHelperRec=record
    class operator Implicit(aRec:RDoubleHelperRec):double;
    case Bin:boolean of
      True:
        (BinData:UINT64);
      False:
        (DoubleData:double);
  end;
...
class operator RDoubleHelperRec.Implicit(aRec: RDoubleHelperRec): double;
begin
  Result:=aRec.DoubleData;
end;

затем при его использовании объявите как const:

procedure TestIEEEDouble.TestCompareValueBoundary;
const
  cSmallestPositiveDouble:RDoubleHelperRec=(BinData:$0000000000000001);
begin
  CheckEquals(0,CompareValue(FSmallestPositiveDouble,cSmallestPositiveDouble),'CompareValue(FSmallestPositiveDouble,cSmallestPositiveDouble)');
end;
person H.Hasenack    schedule 16.01.2021
comment
Вы можете удалить (бесполезное) дополнительное поле Bin и просто использовать case Boolean of - person Ondrej Kelle; 18.01.2021
comment
@OndrejKelle: я сделал, изменил его на целое число и добавил ByteData:array[0..sizeof(Double)-1], чтобы маленький / большой порядок байтов тоже был виден. Я создал тестовые наборы для Single, Double и Extended. - person H.Hasenack; 19.01.2021
comment
См. соответствующую проблему quality.embarcadero.com/browse/RSP-32213. - person H.Hasenack; 21.01.2021