CGFloat badnum = 1.05f;
NSLog(@"badnumX100 = %f",badnum*100);
//輸出
//badnumX100 = 104.999995
複製代碼
在平常工做中涉及到浮點數(float、double)的運算git
#define NSDecimalMaxSize (8)
// Give a precision of at least 38 decimal digits, 128 binary positions.
#define NSDecimalNoScale SHRT_MAX
typedef struct {
signed int _exponent:8;//冪指數
unsigned int _length:4; // length == 0 && isNegative -> NaN
unsigned int _isNegative:1;//符號
unsigned int _isCompact:1;
unsigned int _reserved:18;
unsigned short _mantissa[NSDecimalMaxSize];//存儲數據
} NSDecimal;
複製代碼
//100.0轉化成NSDecimalNumber
NSDecimalNumber *g_100 = [NSDecimalNumber decimalNumberWithString:@"100"];
//1.05轉化成NSDecimalNumber
NSDecimalNumber *g_105 = [NSDecimalNumber decimalNumberWithString:@"1.05"];
//兩個數相乘 1.05X100
NSDecimalNumber *goodnum = [g_105 decimalNumberByMultiplyingBy:g_100];
NSLog(@"goodnum 1.05X100 = %@",goodnum);
//輸出
//goodnum 1.05X100 = 105
複製代碼
因爲浮點數內部存儲地不精確,在比較兩個浮點數是否相等時,不能簡單地使用 == 符號來判斷。 判斷兩個浮點數 A, B 是否相等,須要轉化成求這兩個浮點數差的絕對值 C,即 C = fabs(A - B),而後看這個值 C 是否小於一個極小數。 若是小於一個極小數,則能夠認爲這兩個浮點數是相等的。 根據實際工程中的須要,一般這個極小數的參考值是 1e-6 或 1e-8 。bash
不管是 float 類型仍是 double 類型,在存儲方式上都是聽從IEEE的規範:spa
float 聽從的是 IEEE R32.24;double 聽從的是 IEEE R64.53;.net
單精度或雙精度在存儲中,都分爲三個部分:code
符號位 (Sign):0表明正數,1表明爲負數; 指數位 (Exponent):用於存儲科學計數法中的指數數據; 尾數部分 (Mantissa):採用移位存儲尾數部分;cdn
R32.24 和 R64.53 的存儲方式都是用科學計數法來存儲數據的,好比:blog
8.25 用十進制表示爲:8.25 X 120.5 用十進制表示爲:1.205 X ip
而計算機根本不認識十進制的數據,他只認識0和1。因此在計算機存儲中,首先要將上面的數更改成二進制的科學計數法表示:內存
8.25 用二進制表示爲:1000.01 能夠表示爲1.0001 X 120.5 用二進制表示爲:1110110.1 能夠表示爲1.1101101 Xci
任何一個數的科學計數法表示都爲1. xxx * 2n ,尾數部分就能夠表示爲xxxx,因爲第一位都是1,因此將小數點前面的1省略。由此,23bit的尾數部分,能夠表示的精度卻變成了24bit,道理就是在這裏。
對於指數部分,由於指數可正可負(佔1位),因此8位的指數位能表示的指數範圍就只能用7位,範圍是:-127至128。因此指數部分的存儲採用移位存儲,存儲的數據爲元數據 加上 127
。
元數據 加上 127
:
二進制反推出浮點數: 以下內存數據:01000010111011010000000000000000, 將該數據分段:0 10000101 11011010000000000000000 計算出這樣一組數據表示爲:「指數」從00000000開始(表示-127)至11111111(表示+128) 因此,10000000表示指數1 (127 + 1 = 128 --> 10000000 ) ; 指數爲 3,則爲 127 + 3 = 130,表示爲 01111111 + 11 = 10000010 ;
1101101*10(133-127=6) =1.1101101 * 26 = 1110110.1=120.5
單精度的 2.2 轉換爲雙精度後,精確到小數點後13位以後變爲了2.2000000476837 而單精度的 2.25 轉換爲雙精度後,變爲了2.2500000000000
2.25** 的單精度存儲方式表示爲:**0 10000001 00100000000000000000000
2.25** 的雙精度存儲方式表示爲:**0 10000000 0010010000000000000000000000000000000000000000000000000
這樣 2.25 在進行強制轉換的時候,數值是不會變的。
**將十進制的小數轉換爲二進制的小數的方法是:****將小數*2****,取整數部分。**
0.2×2=0.4,因此二進制小數第一位爲0.4的整數部分0;
0.4×2=0.8,第二位爲0.8的整數部分0;
0.8×2=1.6,第三位爲1;
0.6×2=1.2,第四位爲1;
0.2×2=0.4,第五位爲0;
...... 這樣永遠也不可能乘到=1.0,獲得的二進制是一個無限循環的排列 00110011001100110011...
複製代碼
對於單精度數據來講,尾數只能表示 24bit 的精度,因此2.2的 float 存儲爲:
可是這種存儲方式,換算成十進制的值,卻不會是2.2。
由於在十進制轉換爲二進制的時候可能會不許確(如:2.2),這樣就致使了偏差問題!
而且 double 類型的數據也存在一樣的問題!
因此在浮點數表示中,均可能會不可避免的產生些許偏差!
在單精度轉換爲雙精度的時候,也會存在一樣的偏差問題。