Home > C++ > Generating NaNs

Generating NaNs

Nanonano
While converting serialized double precision floating point numbers received in a datagram over a UDP socket into a native C++ double type, I kept getting NaN values (Not a Number) whenever I used the deserialized version of the number in a numeric computation. Of course, the problem turned out to be the well-known Endian” issue where one machine represents numbers internally in Big Endian format and the other uses Little Endian format.

Endians

One way of creating a NaN is by taking the square root of a negative number. Another way is to jumble up the bytes in a float or double such that an illegal bit pattern is produced. Uncompensated Endian mismatches between machines can easily produce illegal bit patterns that create NaNs. Note that NaNs are only an issue in the floating point types because every conceivable bit pattern stored in an integral type is always legal.

To prove just how easy it is to produce a NaN by jumbling up the bytes in a double, I wrote this little program that I’d like to share:

NanGen

Here is a fragment of the output from a typical program run:

NanOut

I was a little surprised at the low number of iterations it typically takes to produce a NaN, but that’s a good thing. If it takes millions of iterations, it may be hard to trace a bug back to a NaN problem.

For those who would try this program out, here is a copy-paste version of the code:

#include <cstdint>
#include <iostream>
#include <random>
#include <cmath>

int main() {
    //Determine the number of bytes in a double
	const int32_t numBytesInDouble{sizeof(double)};

	//Create a fixed-size buffer that holds the number of bytes
	//in a double
	int8_t buffer[numBytesInDouble];

    //Setup a random number generator to produce
    //a uniformly distributed int8_t value
    std::random_device rd{};
    std::mt19937 gen{rd()};
    std::uniform_int_distribution<int8_t> dis{-128, 127};

    //interpret the buffer as a double*
    const double* dp{reinterpret_cast<double*>(buffer)};
    int32_t count{-1};
    do{
      //fill our buffer with random valued bytes
      for(int32_t i=0; i<numBytesInDouble; ++i) {
        buffer[i] = dis(gen);
      }

      std::cout << *dp << "\n";
      ++count;
    }while(not std::isnan(*dp));

    std::cout << "count = " << count << "\n";
}
Categories: C++ Tags: ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: