python中float的底层数据结构

Joh*_*ohn 6 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
Run Code Online (Sandbox Code Playgroud)

似乎b和c的值取决于机器,它们是最接近目标值但不完全相同的数字.我受到监督,我们得到'正确'的数字与'打印',有人告诉我,这是因为打印'谎言',而Python选择告诉我们真相,即显示他们已存储的确切内容.

我的问题是:

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

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

非常感谢约翰

And*_*ark 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);
}
Run Code Online (Sandbox Code Playgroud)

所以基本上,repr(float)将返回一个格式为17位精度str(float)的字符串,并返回一个12位精度的字符串.正如你可能已经猜到,print使用str()和解释输入变量名称使用repr().只有12位精度,看起来你得到了"正确"的答案,但这只是因为你所期望的和实际值相同,最多12位数.

这是一个区别的快速示例:

>>> str(.1234567890123)
'0.123456789012'
>>> repr(.1234567890123)
'0.12345678901230001'
Run Code Online (Sandbox Code Playgroud)

至于你的第二个问题,我建议你阅读Python教程的以下部分:浮点算术:问题和限制

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

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

在Python 2.7和Python 3.1之前的版本中,Python将此值四舍五入为17位有效数字,给出"0.10000000000000001".在当前版本中,Python显示一个基于最小小数的值,该小数正确地回滚到真正的二进制值,结果只是'0.1'.