回覆列表
  • 1 # 使用者7634198286601

    解釋下 0.1+0.1-0.2=0 具體是怎麼蒙對的,0.1+0.1+0.1-0.3 怎麼就蒙不對了。

    首先在 CPython 中浮點數總是64位的,這裡為了書寫方便,假設為32位的IEEE 754浮點數,計算的道理都一樣,於是第一位是符號位,後面8位是階碼,最後23位是尾數。

    0.1換算成二進位制:

    因為尾數只能有23位所以需要修約,IEEE 754定義的修約的規則可以有四種:取最靠近的(對於中間數0.5,IEEE 754預設修約成偶數,叫做 round half to even,譬如23.5和24.5都取為24),向上取整,向下取整,向靠近0取整。預設的取整規則是取就近的,這個很重要,直接決定了什麼數能蒙對,什麼數蒙不對。

    0.1再換成以2為基數的冪數,尾數只取23位的話:

    注意最後1100被round成了1101,因為第24位是一個1(於是進位,第23位的0變成1)。因為階碼有-127的移位(單精度),即使真正的2的指數加上127才是儲存階碼,所以階碼應該為

    再加上尾數和符號位,整個32位(最左端為符號位)就為:

    Intel的CPU都是little endian的,我們假設這裡的CPU是Intel,所以在程序的虛擬記憶體中0.1被表示為cd cc cc 3d。

    再看0.2,0.2換成位二進位制:

    因為0.2=0.1*2,所以就是把0.1向左移一位的結果,他和0.1不出意料地具有相同的尾數,只是階碼多了一位:

    同理,這裡階碼相當於0.1的階碼加一,於是就是01111011 + 00000001 = 01111100,同理,整個32位(最左端為符號位)就為:

    那0.1+0.1時又發生了什麼呢?兩個浮點數相加時,遵循以下步驟:

    0 運算元檢查 比較階碼大小並完成對階 尾數求和運算 結果規格化(舍入處理)

    首先兩個數都不為0(回憶下0是怎麼在浮點數中被表示的),階碼也相等,所以直接對尾數求和。兩個尾數又相等,求和的結果相當於左移1位,結果是11.00110011001100110011010,溢位了,所以再右移1位以規格化(相當於小數點左移一位),階碼加1,右移的時候末尾的0被捨去,最後尾數變為1.10011001100110011001101,階碼是-4+1=-3,和0.2長得一模一樣。

    那如果0.2再加上一個0.1呢?這時候為了得出Python直譯器給出的那個結果,我們需要真正使用雙精度浮點數了(11位的階碼和52的尾數)。0.1的尾數和階碼分別為1.1001100110011001100110011001100110011001100110011010和-4,請注意尾數原本以110011001結尾,只不過最後這個1後面又是一個1,並且後面大於0.5,於是110011001加一變為110011010,這就是導致0.2+0.1和0.3不一樣的根本原因。

    0.2則具有相同的尾數和-3的階碼,做0.1和0.2的加法時,首先把0.1的尾數變為0.11001100110011001100110011001100110011001100110011010以對階,然後把這個數再和1.1001100110011001100110011001100110011001100110011010相加,結果是

    10.01100110011001100110011001100110011001100110011001110,這個數的尾數是53位的,而且又有溢位,所以應該右移一位,然後捨去最後兩位,注意最後兩位剛好是中間數,但是根據IEEE 754的預設rounding scheme,應該向前進位變成偶數,所以結果就是

    1.0011001100110011001100110011001100110011001100110100 (10被捨去),同時階碼加一變為-2。

    再看0.3是怎麼表示的,它的階碼和尾數分別為1.0011001100110011001100110011001100110011001100110011和-2。注意尾數結尾0011後面接著的本應是剩下0011的迴圈,小於0.5,所以無法進位,所以導致了0.3和0.2+0.1不一樣,我們把0.3和0.2+0.1擺在一起,看看區別有多大:

    0.2+0.1:

    0.3:

    也就是說只要0.3在最低位加一的話就和0.2+0.1一樣了,而尾數的最低位是第52位,再乘上-2的階碼,就是2的負54次方,這個數剛好就是:5.551115123125783e-17。

  • 中秋節和大豐收的關聯?
  • 怎麼一開啟就GPU怎麼回事?