float存储方式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了float存储方式相关的知识,希望对你有一定的参考价值。
为范围是-3.4*10^-38~3.4*10^38那么大?如:float f;f=0.123他在内存中如何存放?f=0.123e+5他在内存中又如何存放?请那位高手详解一下~谢谢
参考技术A 这是计算机组成原理关于浮点数的存储方式,属于底层细节具体情况可以参考http://hi.baidu.com/xiaoduo170/blog/item/8e79b617122dd601c83d6d7f.html 参考技术B Type Exponent length Mantissa length float 8 bits 23 bits double 11 bits 52 bits第一位是表示正负,0正1负
接下来23位表示mantissa,就是底数部分,是一个大等于1小于2的数字
剩下的8位是exponent,就是幂。。。 参考技术C float即浮点型变量,在计算机内存中占用4字节(Byte),即32-bit。遵循IEEE-754格式标准。
一个浮点数由2部分组成:底数m 和 指数e。
表示为: ±mantissa × 2exponent
注意,公式中的mantissa 和 exponent使用二进制表示
底数部分:使用2进制数来表示此浮点数的实际值。底数部分实际是占用24-bit的一个值,由于其最高位始终为 1 ,所以最高位省去不存储,在存储中只有23-bit。
指数部分:占用8-bit的二进制数,可表示数值范围为0-255。但是指数应可正可负,所以IEEE规定,此处算出的次方须减去127才是真正的指数。所以float的指数可从 -126到128.
Float在内存中的存储方式及IEC61131处理
Float在内存中的存储方式及IEC61131处理
1,fp32(32bits float)类型数据在存储器中占用4Bytes存储,且遵循IEEE-754标准:
一个浮点数分三部分组成:
符号位s(1bit: 31b)+指数e(8bits: 30-23b)+底数m(23bits: 22-0b)
2,符号位s
Bit31表示符号位,符号位指数值的正负,0表示正数,1表示负数。
3,指数e
bit30-23,8bits表示一个有符号的指数,他是十进制指数加上127所得的 数值。
所以我们计算指数的时候必须减去127。
4,底数m
Bit22-0,23bits表示实际存储的底数。
底数实际占用的是24bits的数据位,由于最高位始终为1,所以不显式显示。
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进行手动编码操作的过程如下:
- 考虑到0的特殊性,对0作单独处理。
- 非零值,底数均要转化为1.x * 2 ^e。
- 定义指数e=0;先把原始数据转码:
大于2的除2,直到小于2为止,每次操作均要e++
小于1的乘2,直到大于1为止,每次操作均要e--
- 此时我们已经取到了指数e,e+127就是我们指数域的数值了。
下面是取指的操作过程:
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就是我们得到的实际指数。
- 此时的底数为1.x,由于1固定不写,所以我们把小数部分0.x转化为二进制数值,左对齐,写入到码值的22..0数据域即可。
- 循环体以小数码值不为0 与 数据域23bits写满作为条件。
- 小数部分每次乘2,记录整数部分是否为1,为1的话当前对应的bit写1。
- 更新小数部分的值,更新当前的置位位置。
- 取整数的过程,需要考虑不同平台的差异性,避免由于四舍五入出错。
下面是我用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即可。
以上是关于float存储方式的主要内容,如果未能解决你的问题,请参考以下文章