python中float的底层数据结构

时间:2011-07-18 23:00:45

标签: 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选择告诉我们真相,即显示他们已存储的确切内容。

我的问题是:

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

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

非常感谢 约翰

6 个答案:

答案 0 :(得分:7)

关于第一个问题的答案,请查看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教程的以下部分:Floating Point Arithmetic: Issues and Limitations

当你在基数2中存储基数为10的小数而不是任何其他表示时,它归结为效率,更少的内存和更快的浮点运算,但你确实需要处理不精确。

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

  

在Python 2.7和Python 3.1之前的版本中,Python对此进行了四舍五入   值为17位有效数字,给出'0.10000000000000001'。在   当前版本,Python显示基于最短的值   正确舍入回到真实二进制值的小数部分,   结果只是'0.1'。

答案 1 :(得分:2)

你应该阅读臭名昭着的论文:

What every computer scientist should know about floating-point arithmetic

点击“CACHED”链接,以PDF格式下载论文。

答案 2 :(得分:1)

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

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

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

这通常是通过减去数字,并检查相对于数字是否足够小来完成的。

因此,例如:if:

abs(b - c) < abs(b) / 1000000000000
那么你可以认为它们是平等的。您要考虑多少位数取决于浮点数的精度,即,如果您使用单精度数或双精度数,以及您为达到数字所做的计算。由于精度限制随着每次计算而累积,您可能需要降低它们被认为相等的阈值。

当显示一个浮点数时,它的舍入是它的精度。例如,如果它能够准确地表示15位数,则可以在显示之前将其四舍五入为13位。

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

答案 3 :(得分:0)

浮点数不精确;它是表示方法的一个方面。有很多关于这个原因的背面信息;这足以说明在任何提供浮点数的平台上它都是一个问题。

处理不精确性的最佳方法是建立置信区间;也就是说,两个计算浮点数的等效性的比较可能会有问题,因为表示可能会很少量,因此处理这个问题的方法是减去它们中的两个,并确保差异不超过一小部分数量。许多库已经具有内置于浮点数的这种功能,但是当有疑问时,自己实现起来并不是特别困难。

答案 4 :(得分:0)

本讲座非常清楚地了解变量如何存储在内存中,教授还提供了一个可以给出您所看到的意外结果的示例。
http://www.youtube.com/watch?v=jTSvthW34GU 如果你需要比较这些数字,首先将它们作为整数进行比较,你会注意到如果你进行测试它们是相等的。

答案 5 :(得分:0)

所有数字都存储在有限数量的位上,因此您不能只存储实际数字并且必须与存储最接近数字的一起生活(想象一下分数{ {1}},如果你想用十进制数字将它存储在纸上,那么你将耗尽世界上的树木资源。替代方案是您可以在Mathematica中找到的符号表示,它只是将1/3存储为1/31,但它远离机器并且使计算更慢且更复杂。

看一看人们在这里发布的一些链接,并阅读有关浮点数的信息......虽然它有点可怕但你不再信任机器了。