Reputation: 21514
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
...).
Upvotes: 9
Views: 525
Reputation: 55605
In C++20 you'll be able to use std::format
to do this:
std::cout << std::format("{}", std::numeric_limits<double>::quiet_NaN());
This will print nan
on all platforms that have quiet_NaN
.
Disclaimer: I'm the author of C++20 std::format
.
Upvotes: 0
Reputation:
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::do_put(out, str, fill, v);
return out;
}
private:
static const char NotANumber[];
};
template<typename Iterator>
const char NumPut<Iterator>::NotANumber[] = "Not a Number";
#include <iostream>
#include <limits>
int main() {
#if 1
{
const std::size_t NoDestroy = 1;
NumPut<> num_put(NoDestroy);
std::locale locale(std::cout.getloc(), &num_put);
std::locale restore_locale = std::cin.getloc();
std::cout.imbue(locale);
std::cout << std::numeric_limits<double>::quiet_NaN() << '\n';
// The num_put facet is going out of scope:
std::cout.imbue(restore_locale);
}
#else
{
// Alternitvely use a reference counted facet and pass the ownership to the locales:
auto num_put = new NumPut<>();
std::locale locale(std::cout.getloc(), num_put);
std::cout.imbue(locale);
std::cout << std::numeric_limits<double>::quiet_NaN() << '\n';
}
#endif
std::cout << std::numeric_limits<double>::quiet_NaN() << '\n';
}
Upvotes: 5
Reputation: 11014
YourNumPut
from std::num_put.virtual iter_type do_put( iter_type out, std::ios_base& str, char_type fill, double v ) const;
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
Upvotes: 2
Reputation: 118445
Use isnan
() to portably test if a double
is a NaN.
#include <cmath>
// ...
double d;
if (isnan(d))
// ...
Upvotes: 0
Reputation: 36402
Just implement your own checking against the quiet_NaN
value, and print based on that.
Upvotes: 3