449,110 Members | 1,010 Online
Need help? Post your question and get tips & solutions from a community of 449,110 IT Pros & Developers. It's quick & easy.

# Dark-corners floating-point behavior in C++

 P: n/a Does the C++ standard specify the behavior of floating point numbers during "exceptional" (exceptional with respect to floating point numbers, not exceptions) conditions? For example: double a = 1.0 / 0.0; // What is the value of a? Infinity? double b = 0.0 / 0.0; // What is the value of b? NaN? What about overflow/underflow conditions in the library? Is HUGE_VAL always a defined constant? #include using namespace std; double c = pow(1e100, 1e100); // What is the value of c? double d = pow(0.5, 1e100); // What is the value ef d? Sep 7 '05 #1
12 Replies

 P: n/a On Wed, 07 Sep 2005 05:32:17 GMT, Dave Rahardja wrote in comp.lang.c++: Does the C++ standard specify the behavior of floating point numbers during "exceptional" (exceptional with respect to floating point numbers, not exceptions) conditions? For example: double a = 1.0 / 0.0; // What is the value of a? Infinity? double b = 0.0 / 0.0; // What is the value of b? NaN? The behavior of both of the above is just plain undefined. There is no requirement or specification of a value, there is none. What about overflow/underflow conditions in the library? Is HUGE_VAL always a defined constant? HUGE_VAL is a required macro in /. It expands to a positive double constant expression not necessarily representable in a float. The intent is that it be the largest possible value that can be held in a double, or a representation of positive infinity, if the floating point type has such a representation. #include using namespace std; double c = pow(1e100, 1e100); // What is the value of c? Assuming that the result is too large to be represented in a double, his one should result in HUGE_VAL, and errno is set to ERANGE. double d = pow(0.5, 1e100); // What is the value ef d? Again assuming limitations on the range of a double, so that this underflows to 0, the return will be 0.0, errno might or might not be set to ERANGE. But don't confuse library functions, which have fully defined behavior, with overflow or underflow when using the build-in arithmetic operators on any arithmetic type, be it floating point or signed integer types. The latter has just plain undefined behavior. Division by 0, even with unsigned integer types, is also undefined behavior. None of the / functions are allowed to produce undefined behavior when passed arguments representable in the argument type. If the arguments are out of range for the function, such as an argument outside the range of [-1,+1] to acos(), an implementation-defined value is returned and errno is set to EDOM. If the result of the function is not representable in the return type, the functions mostly return HUGE_VAL or -HUGE_VAL and set errno to ERANGE on magnitude overflow, and 0 with errno possible set to ERANGE. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html Sep 7 '05 #2

 P: n/a First: appologies for sending the first version to you instead of the NG. If your compiler follows the float standard Which you can check by including then test for conformance using: numeric_limits::is_iec559 The following should result if it follows the standard: double a = 1.0 / 0.0; // What is the value of a? Infinity? An error since the compiler should discover a division by 0 when it attempts to turn 1.0/0.0 into a constant. Ignoring that: +Infinity (infinity keeps sign) double b = 0.0 / 0.0; // What is the value of b? NaN? See comment above. The result would be: Indetermined What about overflow/underflow conditions in the library? Is HUGE_VAL always a defined constant? This kind of error generally gets trapped at the processor. There are OS specific solutions to get at these errors. double c = pow(1e100, 1e100); // What is the value of c? +Infinity double d = pow(0.5, 1e100); // What is the value ef d? 0 And depending on how the OS works all 4 calculations will result in various errors that can be recoved using os specific functions. Sep 7 '05 #3

 P: n/a On Wed, 07 Sep 2005 02:38:39 -0500, Jack Klein wrote: double c = pow(1e100, 1e100); // What is the value of c?Assuming that the result is too large to be represented in a double,his one should result in HUGE_VAL, and errno is set to ERANGE. Thanks for your reply. Is there a portable way to detect these conditions at run-time, even after they have happened? My trouble with errno is that it is usable only in a single-threaded application. My applications are almost always multithreaded at some point. There are hooks in some libraries like _matherr() that allow me to trap for these errors, but I suspect those hooks are not part of the standard library. Am I right? -dr Sep 7 '05 #4

 P: n/a Dave Rahardja wrote: My trouble with errno is that it is usable only in a single-threaded application. My applications are almost always multithreaded at some point. [DISCLAIMER: NON STANDARD SINCE THE STANDARD DOESN'T ADDRESS THREADS] The implementations that I've seen (MSVC and G++) define errno in a multithreaded environment as a macro which gives thread-specific error info. i.e. [SAMPLE ONLY, NOT ACTUAL IMPLEMENTATION] int *thread_specific_errno(); #define errno (*thread_specific_errno()) Sep 7 '05 #5

 P: n/a ve*********@hotmail.com wrote: First: appologies for sending the first version to you instead of the NG. If your compiler follows the float standard Which you can check by including then test for conformance using: numeric_limits::is_iec559 The following should result if it follows the standard:double a = 1.0 / 0.0; // What is the value of a? Infinity? An error since the compiler should discover a division by 0 when it attempts to turn 1.0/0.0 into a constant. Ignoring that: +Infinity (infinity keeps sign) It's not an error. The result, as you say, is +infinity. double b = 0.0 / 0.0; // What is the value of b? NaN? See comment above. The result would be: Indetermined No. Again, it's not an error. The result is NaN (not a number). What about overflow/underflow conditions in the library? Is HUGE_VAL always adefined constant? This kind of error generally gets trapped at the processor. There are OS specific solutions to get at these errors. Under IEC 60559 (the successor to IEC 559, which is the basis for the name used in numeric_limits) the result of an overflow is a suitably signed infinity. The result of an underflow is a denormal value if the compiler supoprts them, or a suitably signed zero. double c = pow(1e100, 1e100); // What is the value of c? +Infinity If the value is too large for double to handle, which is usually the case. But it isn't required. double d = pow(0.5, 1e100); // What is the value ef d? 0 If the value is too small for double to handle, which is usually the case. But it isn't required. And depending on how the OS works all 4 calculations will result in various errors that can be recoved using os specific functions. No, under IEC 60559 these are not errors. They lead to floating-point exceptions, which are nothing like C++ exceptions. The default behavior is to continue the computation, with (mostly) well-defined rules for what happens when code manipulates NaNs and infinities. You then test at the end to see whether you got a NaN or an infinity, in which case you conclude that you screwed up, or whether one or more of the exception sticky bits is set, in which case you conclude that you might have screwed up. C99 incorporates most of this in the language and library. The C++ TR1 incorporates the library portions of C99, and C++0x will almost certainly have all that C99 has in this area. -- Pete Becker Dinkumware, Ltd. (http://www.dinkumware.com) Sep 7 '05 #6

 P: n/a On Wed, 07 Sep 2005 11:24:39 -0500, Pete Becker wrote: Under IEC 60559 (the successor to IEC 559, which is the basis for thename used in numeric_limits) the result of an overflow is a suitablysigned infinity. The result of an underflow is a denormal value if thecompiler supoprts them, or a suitably signed zero. So can we assume the behaviors you described if std::numeric_limits::is_iec559 == true? -dr Sep 8 '05 #7

 P: n/a Dave Rahardja wrote: On Wed, 07 Sep 2005 11:24:39 -0500, Pete Becker wrote:Under IEC 60559 (the successor to IEC 559, which is the basis for thename used in numeric_limits) the result of an overflow is a suitablysigned infinity. The result of an underflow is a denormal value if thecompiler supoprts them, or a suitably signed zero. So can we assume the behaviors you described if std::numeric_limits::is_iec559 == true? is_iec559 asserts that the implementation conforms to the IEC 559 standard. IEC 60559 is the same thing. -- Pete Becker Dinkumware, Ltd. (http://www.dinkumware.com) Sep 8 '05 #8

 P: n/a On Thu, 08 Sep 2005 10:02:29 -0500, Pete Becker wrote: Dave Rahardja wrote: On Wed, 07 Sep 2005 11:24:39 -0500, Pete Becker wrote:Under IEC 60559 (the successor to IEC 559, which is the basis for thename used in numeric_limits) the result of an overflow is a suitablysigned infinity. The result of an underflow is a denormal value if thecompiler supoprts them, or a suitably signed zero. So can we assume the behaviors you described if std::numeric_limits::is_iec559 == true?is_iec559 asserts that the implementation conforms to the IEC 559standard. IEC 60559 is the same thing. Thanks Pete! Just got my hands on a copy of IEEE 754. How is IEC 559/60559 different from the IEEE standards? -dr Sep 9 '05 #9

 P: n/a > Just got my hands on a copy of IEEE 754. How is IEC 559/60559 different from the IEEE standards? They are the same standard only classified by a different organisation. Sep 9 '05 #10

 P: n/a Pete Becker wrote: ve*********@hotmail.com wrote: First: appologies for sending the first version to you instead of the NG. If your compiler follows the float standard Which you can check by including then test for conformance using: numeric_limits::is_iec559 The following should result if it follows the standard:double a = 1.0 / 0.0; // What is the value of a? Infinity? An error since the compiler should discover a division by 0 when it attempts to turn 1.0/0.0 into a constant. Ignoring that: +Infinity (infinity keeps sign) It's not an error. The result, as you say, is +infinity. Please read again. I point out that the compiler would probably have a fit as it would try to replace 1.0/0.0 with a constant and generate a compile time error for division by 0. double b = 0.0 / 0.0; // What is the value of b? NaN? See comment above. The result would be: Indetermined No. Again, it's not an error. The result is NaN (not a number). The result is indetermined not NaN seeing that it can be any number. This is one of the few situations you do not get a NaN returned (although a lot of material on the net assumes you get one) the other situation I can come up with would trying to divide infinity by infinity. Sep 9 '05 #11

 P: n/a On 9 Sep 2005 03:14:44 -0700, "ve*********@hotmail.com" wrote: > > >>double b = 0.0 / 0.0; // What is the value of b? NaN? > > See comment above. > The result would be: Indetermined > No. Again, it's not an error. The result is NaN (not a number).The result is indetermined not NaN seeing that it can be any number.This is one of the few situations you do not get a NaN returned(although a lot of material on the net assumes you get one) the othersituation I can come up with would trying to divide infinity byinfinity. Actually, not if your compiler (and library) are IEEE-754 compliant. From the standard: 7.1 Invalid Operation The invalid operation exception is signaled if an operand is invalid for the operation on 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) 2) Addition or subtraction—magnitude subtraction of infinites such as, (+inf) + (-inf) 3) Multiplication—0 * inf 4) Division—0/0 or inf/inf 5) Remainder— x REM y, where y is zero or x is infinite 6) Square root if the operand is less than zero 7) Conversion of a binary floating-point number to an integer or decimal format when overflow, infinity, or NaN precludes a faithful representation in that format and this cannot otherwise be signaled 8) Comparison by way of predicates involving < or >, without ?, when the operands are unordered (5.7, Table 4) Item 4 specifies that 0/0 results in a NaN if not otherwise trapped. -dr Sep 9 '05 #12

 P: n/a ve*********@hotmail.com wrote:An error since the compiler should discover a division by 0 when itattempts to turn 1.0/0.0 into a constant.Ignoring that: +Infinity (infinity keeps sign)It's not an error. The result, as you say, is +infinity. Please read again. I point out that the compiler would probably have a fit as it would try to replace 1.0/0.0 with a constant and generate a compile time error for division by 0. It should not generate a compile time error under IEC 60559. It should use the value +infinity. double b = 0.0 / 0.0; // What is the value of b? NaN?See comment above.The result would be: IndeterminedNo. Again, it's not an error. The result is NaN (not a number). The result is indetermined not NaN seeing that it can be any number. No, that's the classic case where NaN is appropriate. Look it up. This is one of the few situations you do not get a NaN returned (although a lot of material on the net assumes you get one) the other situation I can come up with would trying to divide infinity by infinity. Which also produces a NaN. -- Pete Becker Dinkumware, Ltd. (http://www.dinkumware.com) Sep 11 '05 #13

### This discussion thread is closed

Replies have been disabled for this discussion.