I have some questions regarding NaNs for floating-point types:
First, am I correct that NaNs are NOT trap values, that is reading a NaN
itself (but not using it in an arithmetic expression) does not
automatically yield UB?
I guess the following snippet below is OK, correct?:
double X = std::numeric_limits<double>::quiet_NaN();
// some code
if (X == std::numeric_limits<double>::quiet_NaN())
...
else
...
Second, 18.2.1.2 of the C++-Standard describes some utility-functions of
numeric_limits, including NaN related. The (non-normative) note to these
functions says "required by LIA-1". Please, what is LIA-1. And moreover,
how shall I read that note practically speaking? Although the note is of
course non-normative, can I interpret it in a way that practically every
realized platform will offer me NaNs for float, double and long double ?
Third, are there any intended changes to NaNs in the upcoming version of
the Standard?
Thanks a lot for your help,
Thomas
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
> I have some questions regarding NaNs for floating-point types:
>
> First, am I correct that NaNs are NOT trap values, that is reading a NaN
> itself (but not using it in an arithmetic expression) does not
> automatically yield UB?
No, that's not correct. There are two types of NaNs, non-signaling and
signaling NaNs. Signalling NaNs are "trap-values".
> I guess the following snippet below is OK, correct?:
>
>
> double X = std::numeric_limits<double>::quiet_NaN();
quiet_NaN() is a non-signaling NaN.
> // some code
>
> if (X == std::numeric_limits<double>::quiet_NaN())
Looks like a bad idea to me; not because it may "trap" (which it
shouldn't), but since there is more than one type of NaN, test for
equality is a bad idea. I suggest to look into "isnan()" (IIRC, that's
C99, but your C++ compiler may support it nevertheless).
> Second, 18.2.1.2 of the C++-Standard describes some utility-functions of
> numeric_limits, including NaN related. The (non-normative) note to these
> functions says "required by LIA-1". Please, what is LIA-1. And moreover,
> how shall I read that note practically speaking? Although the note is of
> course non-normative, can I interpret it in a way that practically every
> realized platform will offer me NaNs for float, double and long double ?
No, I doubt that this is the case. While most platforms around today use
IEEE-floats and offer NaNs, they don't have to, and I remember some very
old floating point standards that did not have NaNs.
> Third, are there any intended changes to NaNs in the upcoming version of
> the Standard?
I can only forward the question; I would suppose that isnan() will be
available in C++0x, but I cannot answer this for sure.
Greetings,
It's already in the current draft.
Ganesh
There are "quiet" NaNs and "signaling" NaNs. The latter are trap values.
A platform may have either, both or none of the two types of NaNs.
>
> I guess the following snippet below is OK, correct?:
>
>
> double X = std::numeric_limits<double>::quiet_NaN();
>
> // some code
>
> if (X == std::numeric_limits<double>::quiet_NaN())
> ...
> else
> ...
>
It's not ok, because a NaN always compare false with any floating point
value, including itself. In fact a NaN can easily be detected by the
expression (x == x) == false. However, it's better (for several reasons)
to use the library provided function isnan().
> Second, 18.2.1.2 of the C++-Standard describes some utility-functions of
> numeric_limits, including NaN related. The (non-normative) note to these
> functions says "required by LIA-1". Please, what is LIA-1. And moreover,
For LIA-1, see http://en.wikipedia.org/wiki/ISO/IEC_10967 which includes
link to download the paper.
> how shall I read that note practically speaking? Although the note is of
> course non-normative, can I interpret it in a way that practically every
> realized platform will offer me NaNs for float, double and long double ?
No, it just says that: LIA-1 requires those features. The standard does
not require an implementation to implement LIA-1, so those feature may
or may not be present.
> Third, are there any intended changes to NaNs in the upcoming version of
> the Standard?
I don't think so.
HTH,
Ganesh
>
> I have some questions regarding NaNs for floating-point types:
>
> First, am I correct that NaNs are NOT trap values, that is reading a NaN
> itself (but not using it in an arithmetic expression) does not
> automatically yield UB?
>
> I guess the following snippet below is OK, correct?:
>
>
> double X = std::numeric_limits<double>::quiet_NaN();
>
> // some code
>
> if (X == std::numeric_limits<double>::quiet_NaN())
> ...
> else
> ...
As Thomas Richter pointed out, different hardware uses different
varieties of floating-point, so there is no absolute rule. On the other
hand, both C and C++ give favored status to IEEE-754 floating-point,
and many hardware systems implement it, so it's a good base for
understanding.
Yes, by default, NaN values are not trap values, properly understood.
But various operations on floating-point values do cause a trap. There
is a great deal of confusion here because the first "trap" is not the
same word as the second "trap". Similarly, some floating-point
operations cause exceptions, but those are not C++ exceptions.
Floating-point operations have their own terminology, and you have to
interpret statements about them from that perspective.
You get a floating-point exception when something out of the ordinary
occurs: dividing 0.0 by 0.0, dividing 1.0 by 0.0, etc. By default,
those exceptions simply set a bit in the floating-point flags which you
can test later, and return a special value: NaN for the first one,
infinity for the second. There are functions in C99 and in the upcoming
C++0x standard to check and to clear those flags.
Under IEEE-754 you can install a function as a "trap handler"; it will
be called whenever the floating-point exception you've attached it to
occurs. There's no support for trap handlers in C99 nor in C++0x.
This kind of a "trap" is not the same as the C99 term "trap
representation", which refers to a value that produces undefined
behavior when you access it. In the absence of a trap handler, IEEE-754
floating-point operations have well-defined behavior.
One of the quirks of NaN values is that they compare unequal to all
other values, including NaNs. So the test in the code snippet above
will always fail. Similarly, X == X will be false when X is a NaN.
>
>
> Second, 18.2.1.2 of the C++-Standard describes some utility-functions of
> numeric_limits, including NaN related. The (non-normative) note to these
> functions says "required by LIA-1". Please, what is LIA-1. And moreover,
> how shall I read that note practically speaking? Although the note is of
> course non-normative, can I interpret it in a way that practically every
> realized platform will offer me NaNs for float, double and long double ?
LIA-1 refers to ISO/IEC 10967-1, "Language independent arithmetic -
Part 1". As you say, those are footnotes, and LIA-1 is not one of the
normative references listed in the front of the standard. So you can't
assume that LIA-1 applies, nor can you assume that IEEE-754 applies.
Floating-point is still highly implentation dependent.
>
>
> Third, are there any intended changes to NaNs in the upcoming version of
> the Standard?
>
No, other than adding some C99 stuff like isnan() for detecting them.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
More to the point, there are a very large
number of bit patterns that count as NaN.
IIRC from the IEEE-754 standard, NaN is
any float with all ones in the exponent
and a non-zero mantissa.
In addition, all IEEE floating point
values are signed -- positive and negative
NaNs are different, as are +Inf
and -Inf, and +0 and -0.
On the other hand, again IIRC, I believe
that floating-point operations can only
generate quiet NaNs, and there's only one
bit pattern for positive quiet NaN.
(And another for negative quiet NaN.)
Signalling NaN values have to be
explicitly created; it's intended to
be sort of an "uninitialized variable"
indicator.
> > ... can I interpret it [the note] in a way that practically every
> > realized platform will offer me NaNs for float, double and long double ?
>
> No, I doubt that this is the case. While most platforms around today use
> IEEE-floats and offer NaNs, they don't have to, and I remember some very
> old floating point standards that did not have NaNs.
IEEE-754 was the first floating-point _standard_,
as far as I know. Before then, each manufacturer
made up its own floating-point format(s). Some
(CDC, as I recall) had floating infinity. NaN
and gradual underflow were first introduced by
IEEE-754.
Most mainframes that
are not based on microprocessors do _not_ use
IEEE-754 floating point, and do not have NaNs,
Infinity, or gradual underflow. This includes
VAXen, IBM 360/370-type machines, and most
traditional supercomputers.
Both Thomas and Alan and OP Tom, please note that (1) number of bitpatterns is
irrelevant, because (2) an IEEE NaN is required to be unequal to anything,
including itself.
Correct testing, after having established IEEE floating point, is
if( x != x )
{
// This is a NaN
}
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[...]
> > More to the point, there are a very large
> > number of bit patterns that count as NaN.
>
> Both Thomas and Alan and OP Tom, please note that (1) number of bitpatterns is
> irrelevant, because (2) an IEEE NaN is required to be unequal to anything,
> including itself.
>
> Correct testing, after having established IEEE floating point, is
>
> if( x != x )
> {
> // This is a NaN
> }
>
Unfortunately, the above test itself will trigger the floating point
trap
if x is signalling NaN. Also it is quite possible optimizer will just
ignore/remove such test.
Jiang
--
And am I correct that until that one becomes official + implemented into
compiler, using boost::math::isnan is the way to go in the meanwhile?
Thanks,
Thomas
You mean, in the context of IEEE, if the C++ implementation supports signaling
NaNs (i.e. std::numeric_limits<double>::has_signaling_NaN) and x is a signalling
NaN (e.g. an uninitialized double) and trapping on invalid operation exception
has been enabled, then the above test will invoke some handler.
I think that's /fortunate/. :-)
Also, note that the IEEE 754 standard reportedly (I only have a draft of a later
standard) says, in its ยง7.1, that "The invalid operation exception is signaled
if an operand is invalid for the operation to be performed. The result, when the
exception occurs without a trap, shall be a quiet NaN (6.2) provided the
destination has a floating-point format. The invalid operations are:
1. Any operation on a signaling NaN (6.2)"
> Also it is quite possible optimizer will just ignore/remove such test.
It's always possible with an error in the compiler, rendering it non-conforming.
I fail to see the relevance of that to anything.
That argument is like, don't use 'main', or don't use 'int', because there could
be an error in the compiler that, uh, well, something.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[...]
> >> Correct testing, after having established IEEE floating point, is
>
> >> if( x != x )
> >> {
> >> // This is a NaN
> >> }
>
> > Unfortunately, the above test itself will trigger the floating point
> > trap if x is signalling NaN.
>
> You mean, in the context of IEEE, if the C++ implementation supports signaling
> NaNs (i.e. std::numeric_limits<double>::has_signaling_NaN) and x is a signalling
> NaN (e.g. an uninitialized double) and trapping on invalid operation exception
> has been enabled, then the above test will invoke some handler.
>
> I think that's /fortunate/. :-)
>
> Also, note that the IEEE 754 standard reportedly (I only have a draft of a later
> standard) says, in its ยง7.1, that "The invalid operation exception is signaled
> if an operand is invalid for the operation to be performed. The result, when the
> exception occurs without a trap, shall be a quiet NaN (6.2) provided the
> destination has a floating-point format. The invalid operations are:
> 1. Any operation on a signaling NaN (6.2)"
>
> > Also it is quite possible optimizer will just ignore/remove such test.
>
> It's always possible with an error in the compiler, rendering it non-conforming.
>
> I fail to see the relevance of that to anything.
>
> That argument is like, don't use 'main', or don't use 'int', because there could
> be an error in the compiler that, uh, well, something.
>
Hey Alf:
I wish I emphasized this at the very beginning, what you've said is
true,
but the main point is how useful is it.
All your words are based on one *strong* assumption, that is, an
IEEE754
implementation is available for your above "correct test".
But, let's first go back to the reality first.
1. The current C++ standard simply ignores IEEE754. Add it will just
contribute to the amount of UBs, IMHO.
2. Even now the so-called IEEE754 conformable compiler does not exist.
(correct me if I am wrong)
3. Things are much different if we compare this issue with "don't use
'main'" or something like that. Without the specifications
in the holly standard, you/we can not call it an error.
the vender's can do whatever they want.
To prove my words, I find at least one optimizer does removes the
test you proposed, so it is real. For the following code,
$ cat op.cpp
#include <iostream>
bool is_nan(double x)
{
return (x != x) ? true : false;
}
int main()
{
double a = 0.0;
double b = 0.0;
std::cout << "0.0/0.0 is a NaN? : "
<< std::boolalpha << is_nan(a/b) << std::endl;
}
, if the floating point optimization is switched on, then
$ icl /fp:fast op.cpp
[...]
$ ./op
0.0/0.0 is a NaN? : false
Also my DSP (ccs) compiler cl6x simply ignores the above
test even in debug build.
You may say the "over-optimization" violates IEEE754,
and they are not IEEE754 conformant, then what should
we do next?
So you see we poor programmers must face such a difficult
situation. Using your test will introduce strong
dependencies, for example, compiler version, optimization
options, and platform dependent issues, etc...
To restate my points:
1. We should stick to the implementation for this issue.
User code should not do such kind of testing.
2. If no implementation available, instead of testing
the possible NaN, try to prevent it.
3. If we can not prevent it, well, at least we can
crash the program [intentionally, same as some
fp exception default behaviors ].
4. If NaN test is a must, instead of using unreliable
assumption on IEEE754, snprintf&match the NaN's
symbol (for NaN, nan, etc..) is another way to
try. (well, other assumptions must be made)
Sorry for the bad wording, I hope you can get my
point, and please correct me if I am wrong.
regards,
Jiang
--
> On Jul 29, 8:35 am, "Alf P. Steinbach" <al...@start.no> wrote:
>> * Alan McKenney:
>>
>>> On Jul 28, 4:34 am, Thomas Richter <t...@math.tu-berlin.de> wrote:
>>>> Tom wrote:
>
> [...]
>
>>> More to the point, there are a very large
>>> number of bit patterns that count as NaN.
>>
>> Both Thomas and Alan and OP Tom, please note that (1) number of bitpatterns is
>> irrelevant, because (2) an IEEE NaN is required to be unequal to anything,
>> including itself.
>>
>> Correct testing, after having established IEEE floating point, is
>>
>> if( x != x )
>> {
>> // This is a NaN
>> }
>>
>
> Unfortunately, the above test itself will trigger the floating point
> trap
> if x is signalling NaN. Also it is quite possible optimizer will just
> ignore/remove such test.
>
It own't trigger a trap if no trap handler is installed, and by
default, no trap handlers are installed. It will trigger a
floating-point invalid operation exception. By default, that exception
sets a status bit to indicate that the exception occurred, and converts
the value to a quiet NaN.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> Alberto Ganesh Barbati wrote:
>> Thomas Richter ha scritto:
>>>
>>> I can only forward the question; I would suppose that isnan() will be
>>> available in C++0x, but I cannot answer this for sure.
>>>
>>
>> It's already in the current draft.
>>
>> Ganesh
>
>
> And am I correct that until that one becomes official + implemented into
> compiler, using boost::math::isnan is the way to go in the meanwhile?
>
If your compiler has a C99 library you already have isnan.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[...]
>
> > Unfortunately, the above test itself will trigger the floating point
> > trap
> > if x is signalling NaN. Also it is quite possible optimizer will just
> > ignore/remove such test.
>
> It own't trigger a trap if no trap handler is installed, and by
> default, no trap handlers are installed. It will trigger a
> floating-point invalid operation exception. By default, that exception
> sets a status bit to indicate that the exception occurred, and converts
> the value to a quiet NaN.
>
Thanks for the info, but without setting the hardware control bits,
what's the point for exception handling? BTW, for example, signal
like SIGFPE does terminate the process.
Well, it is also true some implementations even won't bother
check the status bit, I would like to withdraw my above words
for trap trigger, since it does not really matter in the
real world.
Regards,
Jiang
--
The fact is that an aggressive optimizer might replace "x == x" with
true and "x != x" with false even if that may be produce incorrect
results for float and double. This is very common. So the test "x != x",
while being theoretically correct, it's not practically useful. And
that's why isnan() is good to have.
Ganesh
--
[snip]
>>
>> Also, note that the IEEE 754 standard reportedly (I only have a draft of a later
>> standard) says, in its ยง7.1, that "The invalid operation exception is signaled
>> if an operand is invalid for the operation to be performed. The result, when the
>> exception occurs without a trap, shall be a quiet NaN (6.2) provided the
>> destination has a floating-point format. The invalid operations are:
>> 1. Any operation on a signaling NaN (6.2)"
>>
>>> Also it is quite possible optimizer will just ignore/remove such test.
>> It's always possible with an error in the compiler, rendering it non-conforming.
>>
>> I fail to see the relevance of that to anything.
>>
>> That argument is like, don't use 'main', or don't use 'int', because there could
>> be an error in the compiler that, uh, well, something.
>>
>
> Hey Alf:
>
> I wish I emphasized this at the very beginning, what you've said is
> true,
> but the main point is how useful is it.
>
> All your words are based on one *strong* assumption, that is, an
> IEEE754
> implementation is available for your above "correct test".
> But, let's first go back to the reality first.
>
> 1. The current C++ standard simply ignores IEEE754. Add it will just
> contribute to the amount of UBs, IMHO.
Oh, no, the C++ standard doesn't quite ignore IEEE754. It just refers to it via
another name, IEC ;-). When I wrote "after having established IEEE floating
point" I meant after checking std::numeric_limits<double>::is_iec559.
> 2. Even now the so-called IEEE754 conformable compiler does not exist.
> (correct me if I am wrong)
Don't know, sorry. I guess Dave Abrahams would know since presumably they've
been up against this issue in Boost development. And, hey, Dave is with us in
this thread! :-)
But, at least the compilers I'm familiar with *claim* that they conform to
IEEE754, by having that 'is_iec559' set to 'true'.
If the compiler says that and still optimizes equality checks away so that it
changes the effect of the source code, then it's a compiler bug, and perhaps the
best response then is to report it to the compiler vendor.
> 3. Things are much different if we compare this issue with "don't use
> 'main'" or something like that. Without the specifications
> in the holly standard, you/we can not call it an error.
> the vender's can do whatever they want.
>
> To prove my words, I find at least one optimizer does removes the
> test you proposed, so it is real. For the following code,
>
> $ cat op.cpp
> #include <iostream>
>
> bool is_nan(double x)
> {
> return (x != x) ? true : false;
> }
>
> int main()
> {
> double a = 0.0;
> double b = 0.0;
> std::cout << "0.0/0.0 is a NaN? : "
> << std::boolalpha << is_nan(a/b) << std::endl;
> }
>
> , if the floating point optimization is switched on, then
>
> $ icl /fp:fast op.cpp
>
> [...]
>
> $ ./op
> 0.0/0.0 is a NaN? : false
Hm, there's no checking of IEEE 754 support in that program.
I don't have that compiler, but try the following program:
<code>
#include <iostream>
#include <limits>
typedef char CompilerSupportsIEEE[std::numeric_limits<double>::is_iec559];
bool isNaN( double x ) { return (x != x); }
int main()
{
using namespace std;
double a = 0.0;
double b = 0.0;
cout << "0.0/0.0 is a NaN? : " << boolalpha << isNaN( a/b ) << endl;
}
</code>
> Also my DSP (ccs) compiler cl6x simply ignores the above
> test even in debug build.
>
> You may say the "over-optimization" violates IEEE754,
> and they are not IEEE754 conformant, then what should
> we do next?
Check for IEEE 754 conformance, e.g. as shown above (if the compiler supports
zero sized arrays as a language extension the above static assert may not
correctly yield any diagnostic, so better use e.g. Boost or Loki static assert).
> So you see we poor programmers must face such a difficult
> situation. Using your test will introduce strong
> dependencies, for example, compiler version, optimization
> options, and platform dependent issues, etc...
I don't think so. :-)
> To restate my points:
>
> 1. We should stick to the implementation for this issue.
> User code should not do such kind of testing.
>
> 2. If no implementation available, instead of testing
> the possible NaN, try to prevent it.
>
> 3. If we can not prevent it, well, at least we can
> crash the program [intentionally, same as some
> fp exception default behaviors ].
>
> 4. If NaN test is a must, instead of using unreliable
> assumption on IEEE754, snprintf&match the NaN's
> symbol (for NaN, nan, etc..) is another way to
> try. (well, other assumptions must be made)
I think these points describe a personal preference (not very arguable), and
anyway, I think arguments for or against would depend on the concrete situation.
Cheers, & hth.,
- Alf
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
I'm shocked. I truly am. It's *very common* for C++ compilers to produce
incorrect machine code?
Yes, I'm aware you wrote this.
But please pardon me, it's a bit hard to swallow. When I first learned
programming compilers were infallible, any error would be the programmer's and
not the compiler's. And now at least C++ compilers have devolved to the opposite
end, now just heaps of erronous dirty hacks thrown together in haphazard fashion
by amateurs, very common with incorrect machine code generation, yes?
> So the test "x != x",
> while being theoretically correct, it's not practically useful.
I'm wondering, besides comparisions not working correctly, what other IEEE 754
features do, very commonly, work incorrectly when the compiler's standard
library implementation defines is_iec559?
Or, from another point of view, are there any features that can be relied on?
> And that's why isnan() is good to have.
Hm, well, yes, I'm shocked -- *very common* with incorrect machine code! Grumble.
Perhaps this is the end of C++.
Cheers,
- Alf (hoping someone may clear this up)
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[...]
> But, at least the compilers I'm familiar with *claim* that they conform to
> IEEE754, by having that 'is_iec559' set to 'true'.
>
Interesting enough, it is difficult to find a compiler that set
numeric_limits<double>::is_iec559 to false. :-)
> If the compiler says that and still optimizes equality checks away so that it
> changes the effect of the source code, then it's a compiler bug, and perhaps the
> best response then is to report it to the compiler vendor.
I am considering issue a bug report for Intel's icl.
>
> Hm, there's no checking of IEEE 754 support in that program.
>
> I don't have that compiler, but try the following program:
>
> <code>
> #include <iostream>
> #include <limits>
>
> typedef char CompilerSupportsIEEE[std::numeric_limits<double>::is_iec559];
>
> bool isNaN( double x ) { return (x != x); }
>
> int main()
> {
> using namespace std;
> double a = 0.0;
> double b = 0.0;
> cout << "0.0/0.0 is a NaN? : " << boolalpha << isNaN( a/b ) << endl;}
>
> </code>
>
Above code tested, same result. Intel's icl reports here 0./0. is not
a NaN.
---------- Alf's code with log added ---------
$ cat test.cpp
#include <iostream>
#include <limits>
typedef char
CompilerSupportsIEEE[std::numeric_limits<double>::is_iec559];
bool isNaN( double x ) { return (x != x); }
int main()
{
using namespace std;
cout << "numeric_limits::has_quiet_NaN? : " << boolalpha <<
numeric_limits<double>::has_quiet_NaN << endl;
cout << "numeric_limits::has_signaling_NaN? : " << boolalpha
<<
numeric_limits<double>::has_signaling_NaN << endl;
cout << "numeric_limits::is_iec559? : " << boolalpha <<
numeric_limits<double>::is_iec559 << endl;
double a = 0.0;
double b = 0.0;
cout << "0.0/0.0 is a NaN? : " << boolalpha << isNaN( a/b ) <<
endl;
}
--------------
$ icl /fp:fast test.cpp
Intel(R) C++ Compiler for applications running on IA-32, Version
10.1 Build 20080312 Package ID: w_cc_p_10.1.021
Copyright (C) 1985-2008 Intel Corporation. All rights reserved.
test.cpp
Microsoft (R) Incremental Linker Version 9.00.30428.01
Copyright (C) Microsoft Corporation. All rights reserved.
-out:test.exe
test.obj
$ ./test
numeric_limits::has_quiet_NaN? : true
numeric_limits::has_signaling_NaN? : true
numeric_limits::is_iec559? : true
0.0/0.0 is a NaN? : false
---------------
> > To restate my points:
>
> > 1. We should stick to the implementation for this issue.
> > User code should not do such kind of testing.
>
> > 2. If no implementation available, instead of testing
> > the possible NaN, try to prevent it.
>
> > 3. If we can not prevent it, well, at least we can
> > crash the program [intentionally, same as some
> > fp exception default behaviors ].
>
> > 4. If NaN test is a must, instead of using unreliable
> > assumption on IEEE754, snprintf&match the NaN's
> > symbol (for NaN, nan, etc..) is another way to
> > try. (well, other assumptions must be made)
>
> I think these points describe a personal preference (not very arguable), and
> anyway, I think arguments for or against would depend on the concrete situation.
Which is quite true. I totally agree with you here.
Regards,
Jiang
--
>> The fact is that an aggressive optimizer might replace "x == x" with
>> true and "x != x" with false even if that may be produce incorrect
>> results for float and double. This is very common.
>
> I'm shocked. I truly am. It's *very common* for C++ compilers to produce
> incorrect machine code?
FYI, this is what g++ generates:
thor@rusime04:~> g++ nantest.cpp
thor@rusime04:~> a.out
0.0/0.0 is a NaN? : true
thor@rusime04:~> g++ -O2 nantest.cpp
thor@rusime04:~> a.out
0.0/0.0 is a NaN? : true
thor@rusime04:~> g++ -O3 nantest.cpp
thor@rusime04:~> a.out
0.0/0.0 is a NaN? : true
thor@rusime04:~> g++ -O3 -funsafe-math-optimizations nantest.cpp
thor@rusime04:~> a.out
0.0/0.0 is a NaN? : false
thor@rusime04:~> g++ -O3 -ffinite-math-only nantest.cpp
thor@rusime04:~> a.out
0.0/0.0 is a NaN? : false
thor@rusime04:~> g++ -O3 -fno-trapping-math nantest.cpp
thor@rusime04:~> a.out
0.0/0.0 is a NaN? : true
That is, by default options it does the right thing and does not
optimize (x != x) away. There are a couple of "unsafe" math
optimizations you may enable, with the expected side-effects. They are
not enabled in the default optimizing mode.
So long,
Thomas
--
Have you checked the documentation for icl to see what options are
required and what options are forbidden to operate in a mode that
conforms to the relevant standards? Have you tried compiling your
test program with just the required options?
My guess is that the icl docs says that /fp:fast renders the compiler
no longer conformant to IEEE 754. Indeed, I see that both gcc and
Sun's cc document that their "fast math" options make the compiler
generate results that don't conform. For example, gcc's docs say
this:
`-ffast-math'
Sets `-fno-math-errno', `-funsafe-math-optimizations',
`-fno-trapping-math', `-ffinite-math-only' and
`-fno-signaling-nans'.
This option causes the preprocessor macro `__FAST_MATH__' to be
defined.
This option should never be turned on by any `-O' option since it
can result in incorrect output for programs which depend on an
exact implementation of IEEE or ISO rules/specifications for math
functions.
Philip Guenther
Good point, I checked the document and what I learned are:
1. /fp:fast is the default option for the optimizer, we need
specify other options explicitly to change this behavior.
2. The /fp:fast (a.k.a fast model) can be used by itself.
3. Using fast model will enable more aggressive
optimizations on floating-point data, the cost is, well,
the value is less accurate.
(no IEEE conformant issue mentioned for /fp models)
The document does say using this [default] option
will hurt the accuracy, but seems this is not exactly
what we are looking for.
Finally, I found this option, /Op, which can be use to
"Enables conformance to the ANSI C and IEEE 754
standards for floating-point arithmetic."
Also it can not be used together with /fp:fast.
I was wondering maybe this one is right the bullet
for our problem, however, soon after the above
statement, the doc showed me that:
[quote icl doc: /Op ]
Specifying the /Op option has the following
effects on program compilation:
* [...]
* Floating-point arithmetic comparisons
conform to the IEEE 754 specification
except for NaN behavior.
* [...]
[end quote]
For NaN comparison, it seems that icl is *not*
conformant to IEEE754, even /Op is specified explicitly.
> My guess is that the icl docs says that /fp:fast renders the compiler
> no longer conformant to IEEE 754. Indeed, I see that both gcc and
> Sun's cc document that their "fast math" options make the compiler
> generate results that don't conform. For example, gcc's docs say
> this:
>
> `-ffast-math'
> Sets `-fno-math-errno', `-funsafe-math-optimizations',
> `-fno-trapping-math', `-ffinite-math-only' and
> `-fno-signaling-nans'.
>
> This option causes the preprocessor macro `__FAST_MATH__' to be
> defined.
>
> This option should never be turned on by any `-O' option since it
> can result in incorrect output for programs which depend on an
> exact implementation of IEEE or ISO rules/specifications for math
> functions.
>
Seems here GCC did it right. Thanks for the pointer.
For this issue, I would like to repeat what Alf said in another post,
the correct/useful method comes form the trade-offs for concrete
situations/considerations.
Jiang