深刻浅出计算机组成原理学习笔记:第十六讲

你是否是感到很疑惑,浮点数的近似值到底是怎么算出来的?浮点数的加法计算又是怎么回事儿?在实践应用中,咱们怎么才用好浮点数呢?这一节,咱们就一块儿来看这几个问题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、总结延伸

一、浮点数的缺点

 

二、浮点数不适合的场景

三、浮点的应用场景

相关文章
相关标签/搜索