对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.为什么我们不能只存储实际数字而不是存储最接近的数字?这是效率的限制还是交易?
答案 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/3
和1
,但它远离机器并且使计算更慢且更复杂。
看一看人们在这里发布的一些链接,并阅读有关浮点数的信息......虽然它有点可怕但你不再信任机器了。