1

i want to test some code to make sure it handles NAN, INF and -INF inputs properly.

i know there exists functions that return NAN, INF and -INF, but as a Double:

unit IEEE754;
...
function NAN: Double;
function PositiveInfinity:  Double;
function NegativeInfinity:  Double;

Except in my case i need to test when a Currency is one of these three edge-case values. Unfortunatly you cannot convert any of these to a Double:

Test(NAN);

procedure Test(const Value: Currency);
  ...

There's an EInvalidOp Invalid floating point operation exception when converting a Double NAN to a Currency.

Is it possible to assign a NAN to a Currency?

Perhaps, rather than it being possible to assign a NAN to a Currency, it is instead not possible - and i can just ignore this edge case.

Can i ignore this edge case?

Is it possible to "Set a Currency value to NAN, INF or -INF?"


{   David Heffernan says it's impossible for a currency to contain INF,-INF or NAN.
    So there's no need to test for it.
    http://stackoverflow.com/questions/7096966/set-a-currency-value-to-nan-inf-or-inf

    //Handle NaN, where exponent is -32767
    test(NAN, 'NAN');

    //Handle +inf, where exponent is 32767 and Negative is true
    test(PositiveInfinity, 'INF');

    //Handle -inf, where expondent is 32767 and Negative is true
    test(NegativeInfinity, '-INF');
}
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • What on earth is the code in your addition supposed to be? Currency **has no exponent**. – Rudy Velthuis Aug 18 '11 at 00:48
  • You're looking at a snippet of code, without realize what it's testing. The `Exponent` is, as you might recall, the "Exponent" returned by Delphi's `FloatToDecimal`, which converts a currency into `Digits` and `Exponent`. (http://stackoverflow.com/questions/7069204/how-to-convert-float-or-currency-to-a-localized-string) – Ian Boyd Aug 18 '11 at 01:20
  • Indeed. I am looking at a piece of code no one except you can understand. So I wonder why it was posted. I know what FloatToDecimal does, and it does **not** what you expect it to do in the case of a Currency parameter. I guess your code is supposed to be some kind of proof, but since no one can follow it, it doesn't serve that purpose very well. – Rudy Velthuis Aug 18 '11 at 01:46
  • It was born out of the comments of the accepted answer. – Ian Boyd Aug 18 '11 at 01:48
  • But it is totally useless, since **no one except you** can retrieve any meaning from it. Note that `NAN`, `NegativeInfinity` and `PositiveInfinity` are **Doubles**, not **Currencies**. – Rudy Velthuis Aug 18 '11 at 01:51

1 Answers1

11

Currency is not an IEEE754 float type and does not have NAN or INF values.

The documentation explains that Currency is implemented as a 64 bit integer with implicit scale of 10000 and that the range of possible values is -922337203685477.5808 to 922337203685477.5807. Since this covers the full range of a 64 bit integer it follows that there are no bit patterns available for sentinel values like NAN or INF.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • The only reason i ask is because `FloatToDecimal` (which can be called with a `Currency` value) returns a `TFloatRec`. `TFloatRec` documents values for `Exponent` when the original value was an `INF/-INF/NAN`. If the function i'm calling documents these possibilities, i'd like to make sure i handle it correctly. But if you are guaranteeing that Delphi's `FloatToDecimal` will never return `INF/-INF/NAN` when given a `Currency`, then i'll ignore the case, and document it as impossible. (If there's ever a crash i'll tell the customer, "But that guy on that web-site said it could never happen.") – Ian Boyd Aug 17 '11 at 17:42
  • 3
    Currency is an Int64 with implicit scaling by 10000. It's decimal rather than binary to avoid rounding errors in base 10 arithmetic. Definitely no NAN or INF. You can blame me if it goes pear shaped.it goes pear shaped. – David Heffernan Aug 17 '11 at 17:53
  • 2
    Ian, `Currency` is a scaled 64-bit integer, not a floating-point type. It's impossible to represent non-numbers with it because all bit patterns represent actual values. It has the same range as Int64, except all the values are divided by 10000. – Rob Kennedy Aug 17 '11 at 17:58
  • 1
    i knew it was Int64 with implicit 4 digits; but since there is this function in the RTL where "Integer with implicit digits" meets floating point values...who knows what edge cases Delphi might have. – Ian Boyd Aug 17 '11 at 17:59
  • In that case, Ian, I'd turn to the source code: What does FloatToDecimal *really* do for Currency arguments? If you don't like what it does, or if you don't trust that it will continue to work the same way in future versions, then you can implement your own function that does exactly what you need for Currency values. Currency is pretty easy to work with for something like this. – Rob Kennedy Aug 17 '11 at 18:08
  • 1
    @Rob: IIRC, the source of FloatToDecimal is more than a few lines of assembler, with a few nested routines, and not so easy to read. – Rudy Velthuis Aug 17 '11 at 19:00
  • @Ian: "Integer with implicit digits" doesn't mean floating point. If it's always 4 digits, (which it is here), that's *fixed point*, which is a different way to represent non-integer real numbers. Floating point = the decimal point can "float around" between different precision levels. Fixed point = there's a fixed number of places after the decimal point. – Mason Wheeler Aug 17 '11 at 19:33
  • Some more input about Currency http://stackoverflow.com/questions/182475/how-to-avoid-rounding-problems-when-comparing-currency-values-in-delphi – LU RD Aug 17 '11 at 19:46
  • @Rudy Velthuis That's exactly what i was going to say. @Mason Wheeler: And yet `FloatToDecimal` turns a currency into a mantissa and an exponent; documenting that NAN and INF can be returned. At the very least you can see my concern. – Ian Boyd Aug 17 '11 at 20:33
  • @Ian: In FloatToDecimal, a Currency is not turned into a mantissa and an exponent, it is turned into a string of digits and a scale. Your "exponent"/scale merely tells the formatting routine where to put the decimal point. FloatToDecimal is an output routine ans has no influence on the value in the currency. Currency can't represent +INF, -INF or NAN. Every possible value is a valid Currency, just like Integer or Int64. They can't represent +INF, -INF or NAN either, and every possible bit combination is a valid Integer or Int64, respectively. – Rudy Velthuis Aug 17 '11 at 21:50
  • Documentation documents possible return values. i could ignore the documentation because i think i know better, or i could program defensively. – Ian Boyd Aug 17 '11 at 23:34
  • @Ian: What documentation are you talking about? The official documentation for the FloatToDecimal routine can be found online at http://docwiki.embarcadero.com/VCL/en/SysUtils.FloatToDecimal and it doesn't say anything about mantissas, exponents, NANs or INFs. Again, Currency is a **fixed-point** type, not a floating-point type. Only floating-point types have mantissas and exponents. Fixed-point types have an integer value and a predefined, implicit scale factor, which is different. – Mason Wheeler Aug 17 '11 at 23:41
  • 1
    @Mason: the docs for TFloatRec do show fields named Exponent, Mantissa, etc. I guess that is where he gets his misconception. – Rudy Velthuis Aug 18 '11 at 00:46