Archive

Posts Tagged ‘NaN’

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: ,
%d bloggers like this: