如何将double类型打印到流中,以便在读取时不会丢失精度?
我尝试过:
std::stringstream ss;
double v = 0.1 * 0.1;
ss << std::setprecision(std::numeric_limits<T>::digits10) << v << " ";
double u;
ss >> u;
std::cout << "precision " << ((u == v) ? "retained" : "lost") << std::endl;
这并没有像我预期的那样起作用。
但我可以增加精度(这让我感到惊讶,因为我认为digits10是必需的最大精度)。
ss << std::setprecision(std::numeric_limits<T>::digits10 + 2) << v << " ";
// ^^^^^^ +2
这与有效数字的数量有关,其中前两个数字在(0.01)中不计算。
所以有没有人考虑过精确表示浮点数? 我需要在流上执行的确切操作是什么魔法咒语?
经过一些实验:
问题出在我的原始版本上。在小数点后面的字符串中存在非显着数字,影响了精度。
因此,为了补偿这一点,我们可以使用科学计数法进行补偿:
ss << std::scientific
<< std::setprecision(std::numeric_limits<double>::digits10 + 1)
<< v;
这仍然没有解释为什么需要+1。另外,如果我以更高精度打印数字,那么我就会得到更多的精度!
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10) << v << "\n";
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v << "\n";
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits) << v << "\n";
它的结果是:
1.000000000000000e-02
1.0000000000000002e-02
1.00000000000000019428902930940239457413554200000000000e-02
根据下面 @Stephen Canon 的回答:
我们可以使用 printf() 格式化控制字符 "%a" 或 "%A" 精确打印出结果。在 C++ 中,我们可以通过使用 fixed 和 scientific 修饰符来实现这一点(参见 n3225: 22.4.2.2.2p5 表格88)。
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
std::cout << v;
目前我已经定义了:
template<typename T>
std::ostream& precise(std::ostream& stream)
{
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
return stream;
}
std::ostream& preciselngd(std::ostream& stream){ return precise<long double>(stream);}
std::ostream& precisedbl(std::ostream& stream) { return precise<double>(stream);}
std::ostream& preciseflt(std::ostream& stream) { return precise<float>(stream);}
下一步:我们如何处理NaN/Inf?
ss
时,为什么在v
后面包含一个空格? - chrisaycock