2011-09-28 63 views
4

在我的python程序中,沒有輸入if語句。我已將代碼簡化爲以下內容:程序沒有輸入if語句

x = -5 
while x < 5: 
    if (x == 0): 
     print 0 
    x += .01 

此程序不輸出任何內容。

但是,將最後一行更改爲x + = .5會使程序輸出0.問題是什麼?

+7

您可能想閱讀[每位計算機科學家應瞭解的浮點算術知識](http://download.oracle.com/docs/cd/E19957-01/806 -3568/ncg_goldberg.html) – Dirk

回答

9

浮點數表示可能不夠準確。你不應該測試零相等性,而應該使用一些東西

if (abs(x) < 1E-10) ... 
+0

和'abs(x - y)ε'一般來說,其中'x'和'y'是您正在比較的值,而'epsilon'是一個小於您所關心的誤差範圍的小數字。 – delnan

+0

雖然這個修復很煩人。例如,如果我想在零點以外的地方使用,如果我想在.05的話,就必須使用.04999 gsingh2011

+0

不幸的是,「修復」是不可能的,因爲「等於」對於不同的人來說可能意味着完全不同的東西。請注意,python的人都知道這一點,並提供解釋:http://docs.python.org/tutorial/floatingpoint.html – drozzy

3

這是一個四捨五入的問題 - 十進制值不能完全以二進制表示的,所以X從未恰好等於0.0000000000 ....

嘗試if -0.001 < x < 0.001:

BTW更換if (x == 0):,括號是一個不必要的python if聲明。

編輯: 打印出來-1和1之間的值在0.01示出了該步驟的話 - 其中零應該是它打印7.52869988574e-16。

+3

_有些十進制值可以用二進制精確表示。 「0.1」不是這些值中的一個。 – agf

+0

@agf:是的,我應該做得更清楚。這就是爲什麼0.5工作,但0.1不工作 - 0.5在二進制中完全可以表示。 –

0

在二進制中,.01沒有確切的表示,但是.5沒有。

如果你將1/3代表爲.333333,並且一直添加1/3直到達到1,那麼這與你在十進制中遇到的問題是一樣的。三次添加之後,您將擁有.999999,它不完全等於1.

Don't compare non-integers for equality除非你正確理解這樣做的規則,並100%確定你的情況是可以工作的規則之一。

0
-0.01 
7.52869988574e-16 
0.01 

我建議你說X> -.001和X < 0.001或排序

3

其他人所指出的問題與浮點數是不能準確地表示值的東西。如果你需要一些確切十進制表示,你可以使用Decimal類:

from decimal import Decimal 

x = Decimal(-5) 
while x < 5: 
    if (x == 0): 
     print 0 
    x += Decimal(".01") 

這將打印0如您所願。

注意使用字符串作爲增量。如果您使用的是Decimal(.01),則會出現與0.01的精確表示相同的問題,因爲您正在從浮點數轉換而已失去準確性,所以班級不允許這樣做。

+0

這是正確的做法。 OP不應該對float類型進行任何科學計算。 – patrys

7

看看打印聲明的力量...

讓我們插入一個打印語句...

x = -5 
while x < 5: 
    if (x == 0): 
     print 0 
    x += .01 
    print x 

運行該程序,並圍繞0檢查輸出揭示了問題:

... 
-0.13 
-0.12 
-0.11 
-0.1 
-0.0900000000001 
-0.0800000000001 
-0.0700000000001 
-0.0600000000001 
-0.0500000000001 
-0.0400000000001 
-0.0300000000001 
-0.0200000000001 
-0.0100000000001 
-6.23077978101e-14 
0.00999999999994 
0.0199999999999 
0.0299999999999 
0.0399999999999 
0.0499999999999 
0.0599999999999 
0.0699999999999 
0.0799999999999 
0.0899999999999 
0.0999999999999 
0.11 
0.12 
0.13 
... 

哦,孩子,這是從來沒有實際上等於零!

解決方案:

  1. 使用整數。最可靠的。

    x = -500 # times this by a 100 to make it an integer-based program 
    while x < 500: 
        if (x == 0): 
        print 0 
        x += 1 
    
  2. 決不測試浮點運算的平等,而是使用範圍:

    delta = 0.00001 #how close do you need to get 
    point = 0 #point we are interested in 
    if (point-delta) <= x <= (point+delta): 
        # do stuff 
    
+0

對於這個微小的邊距,「epsilon」是一個比「delta」更好的名稱選擇,因爲它按照約定表示無限小的微分量,通常對應於某個期望的精度。「delta」通常用作兩個值之間的差異(觀察期望值或當前值先前值)。不像使用i,j和k作爲循環計數器那麼強大,但仍然是一個很好的區別。 – PaulMcG

+0

@PaulMcGuire:根據數學慣例,epsilon和delta都用於小數量。我認爲delta實際上是一個更好的選擇,因爲「epsilon」在浮點運算領域具有特定的含義,這與它在這裏的使用方式不同。一個更好的名字將是'comparisonThreshold',然而=) –

+0

@StephenCanon:你確定嗎?我的工程類都使用epsilon來實現這個目的(也許這是一個「工程師說epsilon,科學家說delta」的東西)。一個「浮點epsilon」和「浮點三角洲」的快速谷歌搜索似乎爲「epsilon」增加了更多的點擊量,並且前幾名都描述了它僅用於此目的。即使是「每個計算機程序員......」的引用都指的是epsilon,或者特別是「機器epsilon」,它是FPU中最小的可區分的差異。你在考慮什麼是「FP算術領域的具體含義」? – PaulMcG

0

要精確到您的查詢,浮點數被存儲在計算機硬件二進制(基2)分數。所以,即使你在變量中存儲了像0.01這樣的浮點數,計算機也會最終將其轉換爲相應的二進制值。爲方便起見,0.01浮點轉換爲二進制:

0.01 * 2 = 0.02 [0] 
0.02 * 2 = 0.04 [0] 
0.04 * 2 = 0.08 [0] 
0.08 * 2 = 0.16 [0] 
0.16 * 2 = 0.32 [0] 
0.32 * 2 = 0.64 [0] 
0.64 * 2 = 1.28 [0] 
0.28 * 2 = 0.56 [0] 
0.56 * 2 = 1.12 [1] 
... 

這種計算將是過於冗長顯示在這裏完全及可能不會在所有的結束。但我想在此陳述的事實是,大多數小數不能完全轉換成二進制分數。因此,您存儲的小數點將近似於機器中存儲的二進制浮點數(顯然不能存儲非常長的二進制值)。所以當計算完成後,你肯定不應該期望精確的浮動值。將x + = 0.01放入代碼就是這種情況。 0.5至它然而轉換的二進制等效值將給出:

0.5 * 2 = 1.0 [1] 

所以0.5浮子的二進制等效爲0.1。因爲它在您的機器中完全以二進制表示。你會得到確切的結果。

它與你的代碼或python無關。這只是計算機硬件的工作方式:)