Could someone please check if casting to currency is broken in versions >XE7? I'm making a bug report for QP.
Could someone please check if casting to currency is broken in versions >XE7? I'm making a bug report for QP.
uses
System.SysUtils;
type
PUInt64 = ^UInt64;
var
f: double;
c: currency;
begin
f := 42;
WriteLn(Format('%.3f', [f]));
WriteLn(Format('%16x', [PUInt64(@f)^]));
WriteLn;
c := currency(f);
WriteLn(Format('%.3f', [c]));
WriteLn(Format('%16x', [PUInt64(@c)^]));
WriteLn;
c := f;
WriteLn(Format('%.3f', [c]));
WriteLn(Format('%.16x', [PUInt64(@c)^]));
ReadLn;
end.
On XE6/XE7 it outputs:
42.000
4045000000000000
463110779182042.317
4045000000000000
42.000
00000000000668A0
Seems the compiler simply copies the bytes directly when you cast the double to currency :(
uses
System.SysUtils;
type
PUInt64 = ^UInt64;
var
f: double;
c: currency;
begin
f := 42;
WriteLn(Format('%.3f', [f]));
WriteLn(Format('%16x', [PUInt64(@f)^]));
WriteLn;
c := currency(f);
WriteLn(Format('%.3f', [c]));
WriteLn(Format('%16x', [PUInt64(@c)^]));
WriteLn;
c := f;
WriteLn(Format('%.3f', [c]));
WriteLn(Format('%.16x', [PUInt64(@c)^]));
ReadLn;
end.
On XE6/XE7 it outputs:
42.000
4045000000000000
463110779182042.317
4045000000000000
42.000
00000000000668A0
Seems the compiler simply copies the bytes directly when you cast the double to currency :(
under Delphi 6
ReplyDelete42,000
4045000000000000
463110779182042,317
4045000000000000
42,000
00000000000668A0
but it is as designed, Currency(f) is not a conversion, it's a hard cast.
Like
ListBox1.Items.AddObject('test', TObject(1))
XE 7.1
ReplyDelete42,000
4045000000000000
463110779182042,317
4045000000000000
42,000
00000000000668A0
XE 8.1
42,000
4045000000000000
463110779182042,317
4045000000000000
42,000
00000000000668A0
Paul TOTH How can it be by design? Try typecasting an int64 to double: "double(i)"...
ReplyDeleteThat is, either it should behave like double(i), ie compiler error, or it should do the right thing. Either way it's a compiler bug.
ReplyDeletePaul TOTH Also, why should it be a hard cast and not a conversion?
ReplyDeleteby design ! Shoud TObject(1) cast "1" as an Object ? Should PChar(IDI_APPLICATION) convert 32512 to a valid pointer ?
ReplyDeleteBTW you can't write like in C
ReplyDeletei := Integer(d);
only
i := Round(d) - or - Trunc(d)
If f is single or extended, you get
ReplyDelete[dcc32 Error] : E2089 Invalid typecast for the cast, which indicates that it is a binary cast, and not a conversion.
The assignment correctly does a conversion.
God I miss static_cast<>...
ReplyDeleteAnyway, fair enough, so the bug here is that it doesn't disallow the cast.
https://quality.embarcadero.com/browse/RSP-11529
ReplyDeleteThanks for checking guys.
There is no bug and that report is invalid (imho). You are doing a hard cast and it produces the correct result for your hardcast. And a hardcast is allowed because the type sizes are equal.
ReplyDeleteStefan Glienke Why should it be a valid cast? After all int64 can't be casted to currency.
ReplyDeleteAsbjørn Heid
ReplyDeleteI commented that the bug is not a bug. I agree with Stefan.
BTW did you know you can mark code as such in your RSP by surrounding it with {code} tags (note the opening and closing tags are the same, no {/code})
The issue arrises because Currency is classified as tkFloat in TypeInfo, even though it is really an Int64 in disguise.
ReplyDeleteJohan Bontes Well we'll see, I see it as an inconsistency. And yes I know about the code tag but they were removed from my earlier reports.
ReplyDeleteJohan Bontes AFAIK the Currency type maps a native x87 type, and the OLE Automation Currency type. And it has decimals, so it is definitively a tkFloat, in a standard format. It is NOT an Int64 in disguise. It is a floating-point value, stored as a 64 bit integer at binary level.
ReplyDeleteAsbjørn Heid I agree with you. IMHO type-casting a currency into a double, or vice-versa, should do the proper value conversion. It always had, and was documented as such: currency is a floating point type, just like single, double or extended, so the values should be assignable freely - with potential rounding issues or precision loss, of course.
ReplyDeleteA. Bouchez "it always had" ... no, look at the first comment
ReplyDelete"the values should be assignable freely" ... they are
Stefan Glienke My mistake. I did not mean "type casting" but "assigning". Assignment should work. I never trusted type casting between float types.
ReplyDeleteA. Bouchez it's unfortunate that borland insisted on calling currency a float type. it is really an alias for the old comp type. (now int64)check out the assembly when you add 1 to a currency.
ReplyDeleteit performs a ADD REG,10000
the fixed 4 decimal places is just an implicit mul/div 10000.
Johan Bontes IMHO it has decimals, so it is a float type. The fact that the decimals are fixed to 4, and that it is most of the time sufficient to use 64 bit integer math is how it was implemented.
ReplyDeleteA. Bouchez
ReplyDeleteSorry, no. It's fixed point. Which has been implemented using integers since time immemorial. Even the Apple II basic by the Woz had some support for it.
This has nothing to do with IEEE 784 and floating point.