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 :(

Comments

  1. under Delphi 6
    42,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))

    ReplyDelete
  2. XE 7.1
    42,000
    4045000000000000

    463110779182042,317
    4045000000000000

    42,000
    00000000000668A0


    XE 8.1
    42,000
    4045000000000000

    463110779182042,317
    4045000000000000

    42,000
    00000000000668A0

    ReplyDelete
  3. Paul TOTH How can it be by design? Try typecasting an int64 to double: "double(i)"...

    ReplyDelete
  4. That 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.

    ReplyDelete
  5. Paul TOTH Also, why should it be a hard cast and not a conversion?

    ReplyDelete
  6. by design ! Shoud TObject(1) cast "1" as an Object ? Should PChar(IDI_APPLICATION) convert 32512 to a valid pointer ?

    ReplyDelete
  7. BTW you can't write like in C
     i := Integer(d);
    only
     i := Round(d)  - or - Trunc(d)

    ReplyDelete
  8. If f is single or extended, you get
    [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.

    ReplyDelete
  9. God I miss static_cast<>...

    Anyway, fair enough, so the bug here is that it doesn't disallow the cast.

    ReplyDelete
  10. 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.

    ReplyDelete
  11. Stefan Glienke Why should it be a valid cast? After all int64 can't be casted to currency.

    ReplyDelete
  12. Asbjørn Heid
    I 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})

    ReplyDelete
  13. The issue arrises because Currency is classified as tkFloat in TypeInfo, even though it is really an Int64 in disguise.

    ReplyDelete
  14. Johan 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.

    ReplyDelete
  15. Johan 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.

    ReplyDelete
  16. Asbjø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.

    ReplyDelete
  17. A. Bouchez "it always had" ... no, look at the first comment

    "the values should be assignable freely" ... they are

    ReplyDelete
  18. Stefan Glienke My mistake. I did not mean "type casting" but "assigning". Assignment should work. I never trusted type casting between float types.

    ReplyDelete
  19. A. 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. 
    it performs a ADD REG,10000
    the fixed 4 decimal places is just an implicit mul/div 10000.

    ReplyDelete
  20. 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.

    ReplyDelete
  21. A. Bouchez
    Sorry, 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.

    ReplyDelete

Post a Comment