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
This can be done directly thru unions:
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 );
The rest is obvious: either you now access ALL.d to see how 43 as Int64 is interpreted as Double. Or do it the other way around. Likewise you can even check how the TFileTime interpretation looks by accessing ALL.f.
When dealing with or checking binary keep in mind that the byte order is also important (LE versus BE) - especially when reading from different storage types (FS versus RAM).
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With