1,fp32(32bits float)類型數據在存儲器中佔用4Bytes存儲,且遵循IEEE-754標準:編碼
一個浮點數分三部分組成:spa
符號位s(1bit: 31b)+指數e(8bits: 30-23b)+底數m(23bits: 22-0b)
2,符號位scode
Bit31表示符號位,符號位指數值的正負,0表示正數,1表示負數。blog
3,指數e內存
bit30-23,8bits表示一個有符號的指數,他是十進制指數加上127所得的 數值。it
因此咱們計算指數的時候必須減去127。class
4,底數m循環
Bit22-0,23bits表示實際存儲的底數。二進制
底數實際佔用的是24bits的數據位,因爲最高位始終爲1,因此不顯式顯示。float
5,舉例
0.1:
轉換爲二進制=0.00001
科學計數表示=1.0*2^-1
S=0
E=-1+127=126=0111 1110b
M=000 0000 _ 0000 0000 0000 0000
0011 1111 0000 0000 _ 0000 0000 0000 0000
1.0:
轉換爲二進制=1.0
科學計數表示=1.0*2^0
S=0
E=0+127=127=0111 1111b
M=000 0000 _ 0000 0000 0000 0000
0011 1111 1000 0000 _ 0000 0000 0000 0000
3.0:
轉換爲二進制=11.0
科學計數表示=1.1*2^1
S=0
E=1+127=128=1000 0000b
M=100 0000 _ 0000 0000 0000 0000
0100 0000 0100 0000 _ 0000 0000 0000 0000
10.0:
轉換爲二進制=1010.0
科學計數表示=1.01*2^3
S=0
E=3+127=130=1000 0010b
M=010 0000 _ 0000 0000 0000 0000
0100 0001 0010 0000 _ 0000 0000 0000 0000
-10.0:
轉換爲二進制=-1010.0
科學計數表示=-1.01*2^3
S=1
E=3+127=130=1000 0010b
M=010 0000 _ 0000 0000 0000 0000
1100 0001 0010 0000 _ 0000 0000 0000 0000
1.625:
轉換爲二進制=1.101
科學計數表示=1.101*2^0
S=0
E=0+127=127=0x7F=0111 1111b
M=101 0000_0000 0000 0000 0000
0011 1111 1101 0000_0000 0000 0000 0000
實際代碼操做中,咱們對fp32進行手動編碼操做的過程以下:
大於2的除2,直到小於2爲止,每次操做均要e++
小於1的乘2,直到大於1爲止,每次操做均要e--
下面是取指的操做過程:
1 (* 小於1不爲0的數據, 直接放大到>1 *) 2 WHILE (real_data < 1.0) AND (real_data <> 0.0) DO 3 real_data := real_data * 2.0; 4 temp_E := temp_E - 1; 5 END_WHILE; 6 (* 大於2的數據, 直接縮小至<2 *) 7 WHILE (real_data > 2.0) DO 8 real_data := real_data / 2.0; 9 temp_E := temp_E + 1; 10 END_WHILE;
temp_E就是咱們獲得的實際指數。
下面是我用IEE61131 ST編寫的取底數操做:
1 (* 5, 計算底數, bit22..00 *) 2 int_pos := 22; (* 第一個小數位的起始點 *) 3 IF real_data <> 0.0 THEN 4 real_dec := real_data - 1.0; 5 ELSE 6 real_dec := 0.0; 7 END_IF; 8 9 WHILE (real_dec > 0.0) AND (int_pos > -1) DO 10 real_tmp := real_dec * 2.0; 11 (* 判斷是不是1 *) 12 real_int := REAL_TO_UDINT(real_tmp - 0.5); 13 IF real_int > UDINT#0 THEN 14 real_dec := real_tmp - 1.0; 15 temp_M := temp_M + SHL_DWORD(DWORD#1, int_pos); 16 ELSE 17 real_dec := real_tmp; 18 END_IF; 19 int_pos := int_pos - 1; 20 END_WHILE;
temp_M就是最後計算的底數碼值。
6,解碼計算浮點過程是對上述操做的反向定義,相對比較容易寫。
7,咱們能夠分指數、整數和小數分別解析。
8,指數直接取出便可
1 (* 2, 解析指數: bit30..23 *) 2 t_E := DWORD_TO_INT(SHR_DWORD(UDINT_TO_DWORD(code32), 23) AND DWORD#16#FF); 3 IF t_E <> 0 THEN 4 t_E := t_E - 127; 5 END_IF;
9,整數部分
指數爲正的乘2累加,好比:1010
1 -> 1
0 -> 1*2+0=2
1 -> 2*2+1=5
0 -> 5*2+0=10
指數爲負的除2累加,結果累加到小數。
1 (* 4, 計算整數部分數據 *) 2 bTemp := t_E; 3 IF bTemp < INT#0 THEN 4 t_Int := UDINT#0; 5 t_Dec := 1.0; 6 WHILE bTemp < 0 DO 7 bTemp := bTemp + 1; 8 t_M := t_M / UDINT#2; 9 t_Dec := t_Dec / 2.0; 10 END_WHILE; 11 ELSE 12 t_Int := UDINT#1; 13 t_Dec := 0.0; 14 WHILE bTemp > 0 DO 15 t_Int := t_Int * UDINT#2; 16 IF (UDINT_TO_DWORD(t_M) AND DWORD#16#80000000) <> DWORD#0 THEN 17 t_Int := t_Int + UDINT#1; 18 END_IF; 19 bTemp := bTemp - 1; 20 t_M := t_M * UDINT#2; 21 END_WHILE; 22 END_IF;
10,小數部分除2累加,好比:101
1 -> 1/2=0.5
0 -> 0.5+0=0.5
1 -> 0.5+1/8=0.625
1 (* 4, 計算小數部分數據 *) 2 factor := 2.0; 3 WHILE t_M > UDINT#0 DO 4 IF (UDINT_TO_DWORD(t_M) AND DWORD#16#80000000) <> DWORD#0 THEN 5 t_Dec := t_Dec + 1.0 / factor; 6 END_IF; 7 factor := factor * 2.0; 8 t_M := t_M * UDINT#2; 9 END_WHILE;
11,最後根據符號位調整數值結果便可。
12,同時要注意的是碼值爲0的時候直接浮點爲0.0便可。