如何让所有平台编译器为 NaN 输出相同的字符串
How to have all platform compiler output the same string for NaN?
考虑以下代码片段:
#include <iostream>
#include <string>
#include <limits>
int main()
{
std::cout << std::numeric_limits<double>::quiet_NaN();
}
使用 Visual Studio 2010 编译时,输出为 1.#QNAN
。使用 g++ 编译时,输出为 nan
。请注意,Visual Studio 2015 输出 "nan"。
但是,我需要两者来产生相同的输出。最简单的方法是什么?我试图为double
覆盖operator<<
,但我觉得这不是正确的方法。用于NaN
值的字符串是否可以在stream
级别强制使用,或者更好的是,在全局级别强制(使用std::locale
的东西?...从来没有用过...
我发现这个squaring_num_put例子。有趣的是,这是一种修改数字的方法,被重定向到输出。但是我很难尝试使其适应我的问题(无法do_put
向ostream
发送数字或硬编码的"NaN"字符串......
您可以使用流操纵器或修改基础区域设置:
机械手:
#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';
}
现场:
#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';
}
只需根据quiet_NaN
值实现自己的检查,并基于该值进行打印。
- 从 std::num_put 派生您的
YourNumPut
。 - 覆盖您需要的内容,例如:
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());
-
将其设置为全局,
cout
和cerr
或您需要的地方:std::locale::global(yourLocale); std::cout.imbue(yourLocale); std::cerr.imbue(yourLocale);
-
测试它
- 。
- 利润;)
使用 isnan
() 可移植地测试double
是否为 NaN。
#include <cmath>
// ...
double d;
if (isnan(d))
// ...
在 C++20 中,您将能够使用 std::format
来执行此操作:
std::cout << std::format("{}", std::numeric_limits<double>::quiet_NaN());
这将在所有具有quiet_NaN
的平台上打印nan
。
免责声明:我是C++20 std::format
的作者。
相关文章:
- 递归函数计算序列中的平方和(并输出过程)
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 请解释"函数1(p1,p2,p3);"的输出
- C++:将控制台输出存储在宏中更好吗
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 为什么我的代码在输出中增加了93天
- 如何从void函数输出字符串
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- AES加密到解密未正确输出
- 输出是NaN,如何
- 为什么我在输出端得到 nan?
- C++ 每次运行程序时我都会"nan"输出的问题
- 如何在 c++ 中处理 -nan 输出
- 程序输出"nan"
- 尝试在数组(C )中找到平均值时,获取-NAN(IND)输出
- 为什么该浮点联盟的输出是NAN的
- C++,在输出时将NaN移动到数组的末尾
- 如何让所有平台编译器为 NaN 输出相同的字符串
- 计算输出=nan