打印Python和c++双精度值时的精度差异

Precision difference when printing Python and C++ doubles

本文关键字:精度 Python c++ 双精度 打印      更新时间:2023-10-16

我现在很惊讶:

c++ 11

#include <iostream>
#include <iomanip>
#include <limits>
int main()
{
  double d = 1.305195828773568;
  std::cout << std::setprecision(std::numeric_limits<double>::max_digits10) << d << std::endl;
  // Prints  1.3051958287735681
}
Python

>>> repr(1.305195828773568)
'1.305195828773568'

怎么回事,为什么c++中多了一个1 ?

到目前为止,我认为c++和Python在底层使用相同的64位IEEE double;这两个格式化函数都应该打印完整的精度。

你可以强制python打印1(以及后面更多的数字):

print('{:.16f}'.format(1.305195828773568))
# -> 1.3051958287735681
从https://docs.python.org/2/tutorial/floatingpoint.html

:

>>> 7205759403792794 * 10**30 // 2**56
100000000000000005551115123125L

在Python 2.7和Python 3.1之前的版本中,Python四舍五入值为17位有效数字,给出' 0.10000000000000001 '。在在当前版本中,Python会根据最短值显示一个值正确舍入回真实二进制值的十进制小数,结果就是' 0.1 '。

"打印全精度"很难做到:什么是全精度?浮点数的表示是二进制的;只有2次幂的分数可以精确地表示(完全精确);大多数十进制分数不能精确地以2为基数表示。

但是内存中的浮点数在python和c++中是相同的;

当格式最终使用定点记数法时,precision()指定小数位数的数量。因为在你的例子中有一个额外的非分数数字,比那些可以安全表示的数字多一个。

当使用科学记数法时,计算总位数,您将得到与原始数字相同的数字(当然,加上指数)。C和c++用于格式化浮点数的选项实际上相当糟糕。特别是,没有选项可以让格式化程序决定适当的位数,尽管底层算法实际上可以决定这些。

摘自对这个问题的回答:

IEEE 754浮点数是二进制的。没有从给定位数到给定十进制数的精确转换。3位可以保存0到7的值,4位可以保存0到15的值。从0到9的值大约占用3.5位,但这也不准确。

IEEE 754双精度数占用64位。其中,52位专用于有效位数(其余是符号位和指数位)。由于有效位数(通常)是归一化的,因此隐含第53位。

现在,给定53位,每个数字大约3.5位,简单的除法可以得到15.1429位的精度。但请记住,每十进位3.5位只是一个近似值,而不是一个完全准确的答案。

您提供的15位数字后面的这个奇怪的.1429可能是增加1的罪魁祸首。

不管怎样,Python在他们的网站上写着:

历史上,Python提示符和内置的repr()函数会选择有17位有效数字的那个,0.10000000000000001。从Python 3.1开始,Python(在大多数系统上)现在可以选择其中最短的一个,并简单地显示0.1。