略谈float
我們先來看這樣的一段代碼:
#include <stdio.h>void main() {float a = 0;for (int i = 0; i < 100; i++)a = a + 0.1;printf_s("a=%f", a);getchar(); }運行結果如下:
為什么不是10呢?而是10.000002
我們對小數部分:如0.5,0.25,0.125
他們分別表示:2^-1,2^-2,2^-3,
所以對于某些小數不能精確的表示如0.1下面看截圖
我們先來看float在內存中的位置
第一個s代表符號為,1代表負數,0代表正數。
第二個域是指數域,對于單精度float類型,指數域有8位,可以表示 0-255個指數值。指數值規定了小數點的位置,小數點的移動代表了所表示數值的大小。但是,指數可以為正數,也可以為負數。為了處理負指數的情況,實際的指數值按要求需要加上一個偏差(Bias)值作為保存在指數域中的值,單精度數的偏差 值為 -127,而雙精度double類型的偏差值為 -1023。比如,單精度指數域中的64 則表示實際的指數值 -63。 偏差的引入使得對于單精度數,實際可以表達的指數值的范圍就變成-127 到 128 之間(包含兩端)。我們不久還將看到,實際的指數值-127(保存為 全 0)以及 +128(保存為全1)保留用作特殊值的處理。這樣,實際可以表達的有效指數范圍就在 -126 和 +127 之間。
第三個域為尾數域,其中單精度數為 23 位長,雙精度數為 52 位長。比如一個單精度尾數域中的值為: 00001001000101010101000, 第二個域中的指數值則規定了小數點在尾數串中的位置,默認情況下小數點位于尾數串首位之前。
下面我們應該如何避免這個問題
1.避免小數計算(代碼如下)
#include <stdio.h>void main() {float a = 0;for (int i = 0; i < 100; i++)a = a + 0.1*10;printf_s("a=%f", a/10);getchar(); } 運行結果:
第二種是省略(直接忽略某一位的值,如下圖所示)
#include <stdio.h>void main() {float a = 0;for (int i = 0; i < 100; i++)a = a + 0.1;printf_s("a=%.5f", a);getchar(); }
總結
- 上一篇: Linux断点方法,一种基于Linux问
- 下一篇: 3.3栈与递归的实现