問題描述
我已經在 python shell 中輸入了這個:
I've typed this into python shell:
>>> 0.1*0.1
0.010000000000000002
我預計 0.1*0.1 不是 0.01,因為我知道以 10 為底的 0.1 在以 2 為底的周期性.
I expected that 0.1*0.1 is not 0.01, because I know that 0.1 in base 10 is periodic in base 2.
>>> len(str(0.1*0.1))
4
我預計會得到 20 個,因為我在上面看到了 20 個字符.為什么我得到 4?
I expected to get 20 as I've seen 20 characters above. Why do I get 4?
>>> str(0.1*0.1)
'0.01'
好的,這就解釋了為什么我 len
給我 4,但為什么 str
返回 '0.01'
?
Ok, this explains why I len
gives me 4, but why does str
return '0.01'
?
>>> repr(0.1*0.1)
'0.010000000000000002'
為什么 str
圓而 repr
不圓?(我已閱讀 this answer,但我想知道他們是如何決定何時 str
舍入一個浮點數,當它不舍入時)
Why does str
round but repr
not? (I have read this answer, but I would like to know how they have decided when str
rounds a float and when it doesn't)
>>> str(0.01) == str(0.0100000000001)
False
>>> str(0.01) == str(0.01000000000001)
True
所以浮動的準確性似乎有問題.我認為 Python 會使用 IEEE 754 單精度浮點數.所以我已經這樣檢查了:
So it seems to be a problem with the accuracy of floats. I thought Python would use IEEE 754 single precicion floats. So I've checked it like this:
#include <stdint.h>
#include <stdio.h> // printf
union myUnion {
uint32_t i; // unsigned integer 32-bit type (on every machine)
float f; // a type you want to play with
};
int main() {
union myUnion testVar;
testVar.f = 0.01000000000001f;
printf("%f
", testVar.f);
testVar.f = 0.01000000000000002f;
printf("%f
", testVar.f);
testVar.f = 0.01f*0.01f;
printf("%f
", testVar.f);
}
我明白了:
0.010000
0.010000
0.000100
Python 給了我:
Python gives me:
>>> 0.01000000000001
0.010000000000009999
>>> 0.01000000000000002
0.010000000000000019
>>> 0.01*0.01
0.0001
為什么 Python 會給我這些結果?
Why does Python give me these results?
(我使用 Python 2.6.5.如果您知道 Python 版本的差異,我也會對它們感興趣.)
(I use Python 2.6.5. If you know of differences in the Python versions, I would also be interested in them.)
推薦答案
repr
的關鍵要求是它應該往返;也就是說,eval(repr(f)) == f
在所有情況下都應該給出 True
.
The crucial requirement on repr
is that it should round-trip; that is, eval(repr(f)) == f
should give True
in all cases.
在 Python 2.x(2.7 之前)中,repr
通過使用 %.17g
格式執行 printf
并丟棄尾隨零來工作.IEEE-754 保證這是正確的(對于 64 位浮點數).從 2.7 和 3.1 開始,Python 使用了一種更智能的算法,可以在某些情況下找到更短的表示,其中 %.17g
給出了不必要的非零終端數字或終端九.請參閱 3.1 中有哪些新功能? 和 問題 1580.
In Python 2.x (before 2.7) repr
works by doing a printf
with format %.17g
and discarding trailing zeroes. This is guaranteed correct (for 64-bit floats) by IEEE-754. Since 2.7 and 3.1, Python uses a more intelligent algorithm that can find shorter representations in some cases where %.17g
gives unnecessary non-zero terminal digits or terminal nines. See What's new in 3.1? and issue 1580.
即使在 Python 2.7 下,repr(0.1 * 0.1)
也會給出 "0.010000000000000002"
.這是因為0.1 * 0.1 == 0.01
在IEEE-754解析和算術下是False
;也就是說,最接近 0.1
的 64 位浮點值,當與自身相乘時,會產生一個不是最接近 0.1
的 64 位浮點值的 64 位浮點值代碼>0.01:
Even under Python 2.7, repr(0.1 * 0.1)
gives "0.010000000000000002"
. This is because 0.1 * 0.1 == 0.01
is False
under IEEE-754 parsing and arithmetic; that is, the nearest 64-bit floating-point value to 0.1
, when multiplied by itself, yields a 64-bit floating-point value that is not the nearest 64-bit floating-point value to 0.01
:
>>> 0.1.hex()
'0x1.999999999999ap-4'
>>> (0.1 * 0.1).hex()
'0x1.47ae147ae147cp-7'
>>> 0.01.hex()
'0x1.47ae147ae147bp-7'
^ 1 ulp difference
repr
和 str
(pre-2.7/3.1) 的區別在于 str
格式有 12 位小數,而不是 17 位,這是不可往返的,但在許多情況下會產生更具可讀性的結果.
The difference between repr
and str
(pre-2.7/3.1) is that str
formats with 12 decimal places as opposed to 17, which is non-round-trippable but produces more readable results in many cases.
這篇關于浮點數和字符串轉換的奇怪行為的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!