Search code examples
delphitype-conversionieee-754rad-studio

Delphi: define const double from binary representation


Background

I want to create a unit test to test some rtl aspects of Delphi, and in order to do this I want to use very specific IEEE floating point values that I want to create directly from their binary representation.

I have come up so far with this routine, and it actually does the job.

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;

It is used as follows (bindata may still be wrong, but thats not the question):

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

Question

Is there syntax that would allow creating a const double directly from a binary (hex) representation looking something like this:

const
  cSmallestPositiveDouble:double=double($0000000000000001);

Where the result obviously should NOT be 1.0 (it is with this syntax) but (close to) 4.94065645841247e-324


Solution

  • To answer with my own initial solution, the syntax is a bit more extensive than I like, but this seems to do the trick using a variant record and implicit type casting.

    Nice feature/side effect is that you can quickly see binary representation and double representation together in the inspector/watchwindow.

    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;
    

    then when using it, declare as const:

    procedure TestIEEEDouble.TestCompareValueBoundary;
    const
      cSmallestPositiveDouble:RDoubleHelperRec=(BinData:$0000000000000001);
    begin
      CheckEquals(0,CompareValue(FSmallestPositiveDouble,cSmallestPositiveDouble),'CompareValue(FSmallestPositiveDouble,cSmallestPositiveDouble)');
    end;