35

Consider the following code:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

template<class T>
bool IsNaN(T t)
{
    return t != t;
}

int main(int argc, char**argv)
{
    double d1, d2;
    sscanf(argv[1], "%f", &d1);
    sscanf(argv[2], "%f", &d2);

    double dRes = d1/d2;

    cout << "dRes = " << dRes << "\n";

    if(IsNaN(dRes))
        cout << "Is NaN\n";
    else
        cout << "Not NaN\n";

}

Couple of questions:

  1. When I pass 0 and 0 as arguments, it outputs dRes = inf. But I was expecting dRes = NaN or something like that.
  2. Is NaN representable in double variables? For that matter, any variable?
  3. When I changed the data type of d1,d2,dRes to int and passed 0 and 0, I got a Floating exception. What is the difference?
  4. How to check if a variable's value is equal to inf?
nakiya
  • 14,063
  • 21
  • 79
  • 118

3 Answers3

47
  1. When using scanf() double should be read using %lf, not %f. %f will convert the input into a 32-bit float, so the first 32 bits of your variables will be filled with some invalid data, and the last 32 bits will be left as garbage.

  2. Yes. #include <limits>, then std::numeric_limits<double>::quiet_NaN(). Some compilers (e.g. gcc) also provides the NAN macro in <cmath>.

  3. There is no NaN or infinity for integer types. Divide-by-zero for integer will cause an exception (SIGFPE).

  4. #include <cmath>, then std::isinf(x). Use std::isfinite(x) to ensure x is not NaN or Infinity.

sleep
  • 4,855
  • 5
  • 34
  • 51
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • Integer division and floating point division behave differently because integer division is done in hardware and floating point division is not? Or is it something else? – nakiya Nov 04 '10 at 09:51
  • 2
    @nakiya: No, floating point division is also done in hardware. The difference is Infinity is not representable with `int`. – kennytm Nov 04 '10 at 09:53
  • Building on this, is there anyway to recover from a division by 0 for integers? (Other than checking for the value up front - Which I can't do because I do not have control over that code). – nakiya Nov 04 '10 at 10:17
  • 1
    @nakiya: You need to catch the SIGFPE signal which is quite complex to implement. – kennytm Nov 04 '10 at 10:20
  • :(. It's like this. We have a scripting language that supports basic arithmetic operations. Only problem is, it doesn't check whether divisors are 0. Can't touch the library code atm. The input system is also contrived so we can't easily check if we are passing 0 values as divisors. For floating point values, this is ok as you said. But, having trouble with integers. – nakiya Nov 04 '10 at 10:27
  • If I do catch SIGFPE, can I resume processing? If so, what is the state of the result? – nakiya Nov 04 '10 at 10:28
  • @nakiya: :( You can read http://stackoverflow.com/questions/618215/how-do-i-catch-system-level-exceptions-in-linux-c on how to catch the SIGFPE, or http://stackoverflow.com/questions/3013757/are-there-possible-approaches-to-map-signal-handling-c-library-into-a-c-excep/3014035#3014035 on how to convert a SIGFPE into a C++ exception. – kennytm Nov 04 '10 at 10:29
  • @Ben: `isinf` is in C99. It has been in gcc ages before C++11 is standardized. – kennytm Apr 06 '13 at 16:58
  • @KennyTM: This question is about C++. though. – Petter May 27 '13 at 22:23
  • 1
    By the way, SIGFPE is thrown _on x86_ when you attempt integer division by zero, but this is not defined behavior. Other CPU architectures do not necessarily respond the same way. ARM CPUs, for example -- such as are found on nearly every phone and tablet in the world -- simply produce N/0 == zero, with no error reported. – ctate Jul 28 '15 at 00:24
  • `"%f"` handles double precision: http://www.cplusplus.com/reference/cstdio/printf/ – sleep Jun 07 '18 at 12:14
  • @JarrodSmith Yes, but that's for `printf`. The question asks about `scanf`. – kennytm Jun 07 '18 at 16:34
0

The function fpclassify will let you inspect a floating-point value for all the special cases.

It's found in <math.h> as a macro since C99, and in <cmath> as a family of functions, for float, double, and long double under the overloaded name std::fpclassify since C++11.

cppreference has a nice example

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
-3

Just do it like that:

if (dRes  == +1.0/0.0 || dRes  == -1.0/0.0) ... //+INF, -INF
if (dRes  == +0.0/0.0 ) ... //+NaN; i.e. pow(2.0 ,16384.0)
  • 2
    If `dRes` is a NaN, then even `dRes == dRes` is false. This fact creates a new way of checking for NaN, but it also means that your check is totally broken. – Ben Voigt Jan 14 '18 at 19:27