- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
如何将 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)。
那么有没有人研究过精确地表示 float ?我需要在流中执行的确切魔法咒语是什么?
经过一些实验:
问题在于我的原始版本。字符串中小数点后有非有效数字影响准确性。
所以为了弥补这一点,我们可以用科学记数法来弥补:
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++ 中实现这一点,我们需要使用固定的和科学的操纵器(参见 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?
最佳答案
说“ float 不准确”是不正确的,尽管我承认这是一个有用的简化。如果我们在现实生活中使用以 8 或 16 为基数,那么周围的人会说“以 10 为基数的十进制小数包不准确,为什么有人会编造它们?”。
问题是整数值从一个基数精确地转换为另一个基数,但小数值不会,因为它们代表积分步长的分数,并且只使用了其中的一小部分。
浮点运算在技术上是完全准确的。每个计算都有一个且只有一个可能的结果。 存在一个问题,它是大多数小数具有重复的base-2表示。事实上,在 0.01、0.02、... 0.99 的序列中,只有 3 个值具有精确的二进制表示。 (0.25、0.50 和 0.75。)有 96 个值重复,因此显然没有准确表示。
现在,有多种方法可以写入和读取 float 而不会丢失一个位。这个想法是避免尝试用以 10 为底的小数来表示二进制数。
您也可以只写更多的小数位数。这是否逐位准确取决于转换库的质量,我不确定我是否会在这里指望完美的准确性(来自软件)。但是任何错误都会非常小,并且您的原始数据肯定没有低位信息。 (没有一个物理和化学常数是 52 位已知的,地球上的任何距离也没有被测量到 52 位精度。)但是对于可以自动比较逐位精度的备份或恢复,这显然不理想。
关于c++ - 双印不失精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4738768/
我是一名优秀的程序员,十分优秀!