python中浮点的底层数据结构

python中浮点的底层数据结构,python,floating-point-precision,Python,Floating Point Precision,有一个关于Python中float(和precision)的底层数据结构的问题: >>> b = 1.4 + 2.3 >>> b 3.6999999999999997 >>> c = 3.7 >>> c 3.7000000000000002 >>> print b, c 3.7 3.7 >>> b == c False b和c的值似乎取决于机器,它们是最接近目标值的数字,但不是完

有一个关于Python中float(和precision)的底层数据结构的问题:

>>> b = 1.4 + 2.3
>>> b
3.6999999999999997

>>> c = 3.7
>>> c
3.7000000000000002

>>> print b, c
3.7  3.7

>>> b == c
False
b和c的值似乎取决于机器,它们是最接近目标值的数字,但不是完全相同的数字。有人监督我用“Print”获得“正确”的数字,有人告诉我这是因为Print“撒谎”,而Python选择告诉我们真相,即确切地显示它们存储了什么

我的问题是:

1.如何撒谎?e、 g.在一个函数中,我们取两个值并返回它们是否相同,如果十进制数(精度)未知,我怎么能有最好的猜测?像上面提到的b和c?是否有一个定义良好的算法来实现这一点?有人告诉我,如果涉及浮点计算,每种语言(C/C++)都会有这种问题,但他们如何“解决”这个问题呢?

2.为什么我们不能只存储实际数字而不存储最近的数字?这是限制还是为了效率而交易

非常感谢
约翰

浮点数不精确;这是表示方法的一个方面。有很多关于这到底是为什么的背景信息;可以说,在几乎所有提供浮点数的平台上,这都是一个问题


处理不精确性的最好方法是有一个置信区间;也就是说,比较两个计算出的浮点值是否相等可能会有问题,因为表示可能会偏离一个很小的量,因此处理这个问题的方法是减去它们中的两个,并确保差值不超过一个小的量。许多库已经为浮动内置了这种功能,但在有疑问的情况下自己实现并不特别困难。

要回答第一个问题,请看一下Python源代码中的以下代码(稍微精简):

#define PREC_REPR       17
#define PREC_STR        12

void PyFloat_AsString(char *buf, PyFloatObject *v) {
    format_float(buf, 100, v, PREC_STR);
}

void PyFloat_AsReprString(char *buf, PyFloatObject *v) {
    format_float(buf, 100, v, PREC_REPR);
}
因此,基本上,
repr(float)
将返回精度为17位的字符串,而
str(float)
将返回精度为12位的字符串。正如您可能猜到的,
print
使用
str()
,在解释器中输入变量名使用
repr()
。由于只有12位精度,看起来您得到了“正确”的答案,但这只是因为您期望的值和实际值在12位以内是相同的

下面是一个简单的差异示例:

>>> str(.1234567890123)
'0.123456789012'
>>> repr(.1234567890123)
'0.12345678901230001'
关于第二个问题,我建议您阅读Python教程的以下部分:

当您在基2中存储以10为基数的小数时,它可以归结为效率、更少的内存和更快的浮点运算,但您确实需要处理不精确性

正如JBernardo在评论中指出的那样,这种行为在Python 2.7和更高版本中是不同的,下面引用上述教程链接描述了这种差异(以
0.1
为例):

在Python2.7和Python3.1之前的版本中,Python对此进行了改进 值设置为17位有效数字,给出“0.100000000000001”。在里面 在当前版本中,Python显示基于最短路径的值 正确舍入到真实二进制值的十进制分数, 仅导致“0.1”


这堂课很好地洞察了变量是如何存储在内存中的,教授还举了一个例子,让你看到意想不到的结果。

如果您需要首先比较两个数字,将它们转换为整数,并且您会注意到,如果您执行测试,它们确实相等。

您在计算中会得到不同的结果,因为数字1.4和2.3也没有精确表示。添加它们时,还会累积它们的精度限制

所有浮点数的精度都是有限的,而且由于浮点数通常在内部表示(使用基数2而不是基数10),这些限制适用于我们人类认为易于精确表示的数字

有限的精度对于计算来说很少是个问题,因为对于大多数应用来说,精度仍然足够。另一方面,在比较浮点数时,必须考虑有限的精度

这通常通过减去数字来完成,并检查与数字相比差异是否足够小

因此,例如,如果:

abs(b - c) < abs(b) / 1000000000000
abs(b-c)
那么你可以认为他们是平等的。你想考虑的数字有多少取决于浮点数的精度,即如果你使用的是单精度或双精度数字,以及你为了达到这些数字所做的计算。由于每次计算都会累积精度限制,因此当它们被视为相等时,可能需要降低阈值

显示浮点数时,将根据其精度对其进行舍入。例如,如果它能够准确地表示15位数字,则可以在显示之前将其四舍五入到13位


浮点数用于快速计算。还有其他数据类型,如十进制,可以精确存储数字。例如,这些数字用于存储货币值。

所有数字都存储在有限的位数上,因此您不能只存储实际数字,而必须存储最接近的数字(想象一个分数
1/3
,如果你想用十进制数字存储在纸上,你将耗尽世界上的树木资源)。另一种方法是符号表示法,你可以在Mathematica中找到,它只是将
1/3
存储为
1
3
,但它远离机器,使计算变得更慢、更复杂

看看人们在这里发布的一些链接,读到一些关于浮点数的文章……这有点奇怪