2

I read some article about nan, but sites didn't mentioned all situations. For example I compiled this code and received nan. Why doesn't it give inf ?

#include <iostream>

using namespace std;

int main()
{
    double input,counter,pow= 1, sum = 0, sign = 1.0;
   
    cin >> input;
    
    for (counter = 1; pow / counter >= 1e-4; counter++)
    {
        pow *= input;
        sum += sign * pow / counter;
        sign = -sign;
    }
    cout << sum << endl;
}

The result is :

nan
Eugene
  • 6,194
  • 1
  • 20
  • 31
  • 7
    please include a [mcve] of the code in the question. The output depends on types of `i`, `x`,`t`,`m` and `a` and their initial values – 463035818_is_not_an_ai Jan 11 '21 at 18:55
  • Read first the http://floating-point-gui.de/ then some [C++ reference](https://en.cppreference.com/w/cpp). With [GCC](http://gcc.gnu.org/), compile with `g++ -Wall -Wextra -g` then use [GDB](https://www.gnu.org/software/gdb/) to understand the behavior of your program – Basile Starynkevitch Jan 12 '21 at 05:58
  • 1
    What is the value of `input`? – Eugene Jan 13 '21 at 01:59
  • see [Why is “using namespace std;” considered bad practice?](https://stackoverflow.com/q/1452721/995714). There's `std::pow` which may be brought into scope manually or accidentally so naming your variable `pow` is not a good idea – phuclv Jan 13 '21 at 03:34
  • Please hardcode the value for `input` that produces the unexpected result or at least tell us what input you gave. From first glance I don't see anything that could cause nan or inf, because `counter` can't become zero. – Lukas-T Jan 13 '21 at 06:22
  • For example give 2 for input in my compiler I recieved nan – soheil mirjalili Jan 13 '21 at 09:13
  • For input 2 you can't get any output, because then you have an endlesse loop. Sooner or later a variable overflows and you get undefined behaviour which renders the output irrelevant. – Lukas-T Jan 13 '21 at 11:27
  • @churill: There is no overflow causing undefined behavior. Repeatedly multiplying `pow` by 2 takes it to infinity. This will result in `sum` becoming a NaN when a negative infinity is added to a positive infinity or vice-versa. `count` is a `double`, so `counter++` stops having any effect once it reaches 2^53. – Eric Postpischil Feb 05 '21 at 13:04
  • The “Forward progress” clause (4.7.2 in draft n4659) of the C++ standard can have surprising effects in optimization. It says the compiler can assume your loop will not continue forever without doing something useful (like writing output or calling `exit`), and that allows the compiler to generate code that exits the loop even though it would otherwise continue forever with input of 2. But I do not see that in the code generated with a quick experiment I tried. Which compiler are you using, which version, and with what command-line switches? – Eric Postpischil Feb 05 '21 at 13:21

1 Answers1

3

With input of “2”, your program adds two infinities of opposite signs, which generates a NaN. This occurs because repeatedly multiplying pow by two causes it to become infinity, and the alternating sign results in a positive infinity being added to a negative infinity in sum from the previous iteration or vice-versa.

However, it is not clear why you see any output, as counter++ becomes ineffective once counter reaches 253 (in typical C++ implementations) because then the double format lacks precision to represent 253+1, so the result of adding one to 253 is rounded to 253. So counter stops changing, and the loop continues forever.

One possibility is that your compiler is generating code that always terminates the loop, because this is allowed by the “Forward progress” clause (4.7.2 in draft n4659) of the C++ standard. It says the compiler can assume your loop will not continue forever without doing something useful (like writing output or calling exit), and that allows the compiler to generate code that exits the loop even though it would otherwise continue forever with input of “2”.

Per the IEEE-754 standard, operations that produce NaN as a result include:

  • operations on a NaN,
  • multiplication of zero by an infinity,
  • subtraction of two infinities of the same sign or addition of two infinities of opposite signs,
  • division of zero by zero or an infinity by an infinity,
  • remainder when the divisor is zero or the dividend is infinity,
  • square root of a value less than zero,
  • various exceptions in some utility and mathematical routines (such as pow, see IEEE-754 9.2, 5.3.2, and 5.3.3).

C++ implementations do not always conform to IEEE-754, but these are generally good guidelines for sources of NaNs.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312