深刻淺出計算機組成原理學習筆記:第十六講

你是否是感到很疑惑,浮點數的近似值到底是怎麼算出來的?浮點數的加法計算又是怎麼回事兒?在實踐應用中,咱們怎麼才用好浮點數呢?這一節,咱們就一塊兒來看這幾個問題java

1、浮點數的二進制轉換

一、十進制浮點數9.1

二、小數的二進制表示是怎麼回事

 

三、浮點數實際上是用二進制的科學計數法來表示的

 

四、爲何0.3+0.6=0.899999?

2、浮點數的加法和精度

一、浮點數的加法原理

二、好比0.5,表示成浮點數

 

實現這樣一個加法,也只須要位移。和整數加法相似的半加器和全加器的方法就可以實現,在電路層面,也並無引入太多新的複雜性。算法

三、這個加法計算的浮點數的結果是否是正確

一、先對齊

二、在加法發生以前,就丟失精度

三、32位浮點數的加法

你能夠試一下,我下面用一個簡單的Java程序,讓一個值爲2000萬的32位浮點數和1相加,你會發現,+1這個過程由於精度損失,被「徹底拋棄」了。

機器學習

public class FloatPrecision {
  public static void main(String[] args) {
    float a = 20000000.0f;
    float b = 1.0f;
    float c = a + b;
    System.out.println("c is " + c);
    float d = c - a;
    System.out.println("d is " + d);
  }
}

對應的輸出結果就是:學習

c is 2.0E7
d is 0.0

3、Kahan Summation算法

那麼,咱們有沒有什麼辦法來解決這個精度丟失問題呢?雖然咱們在計算浮點數的時候,經常能夠容忍必定的精度損失,可是像上面那樣,
若是咱們連續加2000萬個1,2000萬的數值都會被精度損失丟掉了,就會影響咱們的計算結果。spa

在機器學習中的應用

咱們能夠作一個簡單的實驗,用一個循環相加2000萬個1.0f,最終的結果會是1600萬左右,而不是2000萬。這是由於,3d

加到1600萬以後的加法由於精度丟失都沒有了。這個代碼比起上面的使用2000萬來加1.0更具備現實意義。blog

public class FloatPrecision {
  public static void main(String[] args) {
    float sum = 0.0f;
    for (int i = 0; i < 20000000; i++) {
    	float x = 1.0f;
    	sum += x;    	
    }
    System.out.println("sum is " + sum);   
  }	
}

對應的輸出結果是:ip

sum is 1.6777216E7

面對這個問題,聰明的計算機科學家們也想出了具體的解決辦法。他們發明了一種叫做Kahan Summation的算法來解決這個問題。ci

算法的對應代碼我也放在文稿中了。從中你能夠看到,一樣是2000萬個1.0f相加,用這種算法咱們獲得了準確的2000萬的結果數學

public class KahanSummation {
  public static void main(String[] args) {
    float sum = 0.0f;
    float c = 0.0f;
    for (int i = 0; i < 20000000; i++) {
    	float x = 1.0f;
    	float y = x - c;
    	float t = sum + y;
    	c = (t-sum)-y;
    	sum = t;    	
    }
    System.out.println("sum is " + sum);   
  }	
}

對應的輸出結果是:

sum is 1.6777216E7

其實這個算法的原理其實並不複雜,就是在每次的計算過程當中,都用一次減法,把當前加法計算中損失的精度記錄下來,而後在後面的循環中,把這個精度損失放在要加的小數上,再作一次運算。

若是你對這個背後的數學原理特別感興趣,能夠去看一看Wikipedia連接裏面對應的數學證實,也能夠生成一些數據試一試這個算法。這個方法在實際的數值計算中也是經常使用的,也是大量數據累加

中,解決浮點數精度帶來的「大數吃小數」問題的必備方案

4、總結延伸

一、浮點數的缺點

 

二、浮點數不適合的場景

三、浮點的應用場景

相關文章
相關標籤/搜索