Home Ask Login Register

Developers Planet

Your answer is one click away!

jpo38 February 2016

How to have all platform compiler output the same string for NaN?

Consider this code snippet:

#include <iostream>
#include <string>
#include <limits>

int main()
{
    std::cout << std::numeric_limits<double>::quiet_NaN();
}

When compiled with Visual Studio 2010, output is 1.#QNAN. When compiled with g++, output is nan. Note that Visual Studio 2015 outputs "nan".

However, I need both to produce the same output. What's the most simple way to do that? I tried to override operator<< for double but I feel like that's not the right way to do. Can string to be used for NaN value be forced at stream level, or better, at global level (using std::locale stuff?...never used that...).

I found this squaring_num_put example. Interesting because it's a way to modify a number is redirected to the output. But I'm having a hard time trying to adapt it to my problem (Could not make do_put send either a number or a hard coded "NaN" string to the ostream...).

Answers


Marcus Müller February 2016

Just implement your own checking against the quiet_NaN value, and print based on that.


Sam Varshavchik February 2016

Use isnan() to portably test if a double is a NaN.

#include <cmath>

// ...

double d;

if (isnan(d))
   // ...


Öö Tiib February 2016

  • Derive your YourNumPut from std::num_put.
  • Override what you need for example: virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, double v ) const;
  • Create locale that uses it: std::locale yourLocale(std::locale(), new YourNumPut());
  • Set it global, imbue cout and cerr or where you need: std::locale::global(yourLocale); std::cout.imbue(yourLocale); std::cerr.imbue(yourLocale);

  • Test it

  • ...
  • Profit ;)


Dieter Lücking February 2016

You might use a stream manipulator or modify the underlying locale:

Manipulator:

#include <cmath>
#include <ostream>

template <typename T>
struct FloatFormat
{
    const T value;

    FloatFormat(const T& value)
    : value(value)
    {}

    void write(std::ostream& stream) const {
        if(std::isnan(value))
            stream << "Not a Number";
        else
            stream << value;
    }
};

template <typename T>
inline FloatFormat<T> float_format(const T& value) {
    return FloatFormat<T>(value);
}

template <typename T>
inline std::ostream& operator << (std::ostream& stream, const FloatFormat<T>& value) {
    value.write(stream);
    return stream;
}

int main() {
    std::cout << float_format(std::numeric_limits<double>::quiet_NaN()) << '\n';

}

Locale:

#include <cmath>
#include <locale>
#include <ostream>

template<typename Iterator = std::ostreambuf_iterator<char>>
class NumPut : public std::num_put<char, Iterator>
{
    private:
    using base_type = std::num_put<char, Iterator>;

    public:
    using char_type = typename base_type::char_type;
    using iter_type = typename base_type::iter_type;

    NumPut(std::size_t refs = 0)
    :   base_type(refs)
    {}

    protected:
    virtual iter_type do_put(iter_type out, std::ios_base& str, char_type fill, double v) const override {
        if(std::isnan(v))
            out = std::copy(std::begin(NotANumber), std::end(NotANumber), out);
        else
            out = base_type::do_put(out, str, fill, v);
        return out;
    }

    virtual iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long double v) const override {
        if(std::isnan(v))
            out = std::copy(std::begin(NotANumber), std::end(NotANumber), out);
        else
            out = base_type:: 

Post Status

Asked in February 2016
Viewed 1,887 times
Voted 14
Answered 4 times

Search




Leave an answer


Quote of the day: live life