凌宇 在www.360doc.com中转帖【IEEE浮点数表示法】,经过仔细研究,终于有点心得了。
float转十六进制:
16进制浮点数的表示方法,根据IEEE的标准,分为32位和64位两种,参数分别如下:
符号位 | 指数位 | 指数偏移量 | 尾数位 | |
32位 | 1[31] | 8[23-30] | 23[0-22] | 127 |
64位 | 1[63] | 11[52-62] | 52[0-51] | 1023 |
float
共计32位,折合4字节
由最高到最低位分别是第31、30、29、……、0位
31位是符号位,1表示该数为负,0反之。
30-23位,一共8位是指数位。
22-0位,一共23位是尾数位。
现在让我们按照IEEE浮点数表示法,一步步的将float型浮点数123456.0f转换为十六进制代码。
在处理这种不带小数的浮点数时,直接将整数部转化为二进制表示:1 11100010 01000000。
也可以这样表示:11110001001000000.0。
然后将小数点向左移,一直移到离最高位只有1位,就是最高位的1:1.11100010010000000。
一共移动了16位,在布耳运算中小数点每向左移一位就等于在以2为底的科学计算法表示中指数+1,所以原数就等于这样:1.11100010010000000 * ( 2 ^ 16 )。
好了,现在我们要的尾数和指数都出来了。显而易见,最高位永远是1,因为你不可能把买了16个鸡蛋说成是买了0016个鸡蛋吧?所以这个1我们还有必要保留他吗?好的,我们删掉他。
这样尾数的二进制就变成了:11100010010000000最后在尾数的后面补0,一直到补够23位:11100010010000000000000。
再回来看指数,一共8位,可以表示范围是0 - 255的无符号整数,也可以表示-128 - 127的有符号整数。
但因为指数是可以为负的,所以为了统一把十进制的整数化为二进制时,都先加上127,在这里,我们的16加上127后就变成了143,二进制表示为:10001111。
12345.0f这个数是正的,所以符号位是0,那么我们按照前面讲的格式把它拼起来:
0 10001111 11100010010000000000000
01000111 11110001 00100000 00000000
再转化为16进制为:47 F1 20 00,最后把它翻过来,就成了:00 20 F1 47。
==========================================================
按照IEEE浮点数表示法,将float型浮点数123.456f转换为十六进制代码。
整数部直接化二进制:100100011。
小数部的处理比较麻烦一些。
来看一下步骤:1 / 2 ^1位(为了方便,下面仅用2的指数来表示位),
第1位:0.456小于位阶值0.5故为0;
2位,0.456大于位阶值0.25,该位为1,并将0.45减去0.25得0.206进下一位;
3位,0.206大于位阶值0.125,该位为1,并将0.206减去0.125得0.081进下一位;
4位,0.081大于0.0625,为1,并将0.081减去0.0625得0.0185进下一位;
5位0.0185小于0.03125,为0……
===========================
//得到浮点尾数二进制
double d = 0.0d;
double d1 =0.456;
StringBuilder sb = new StringBuilder();
for (int i = 1; i < 19; i++) {
d = Math.pow(2,- i);
if(d1<d){
sb.append(0);
}else {
sb.append(1);
d1 = d1 - d;
}
}
System.out.println(sb.toString());
==================================
问题出来了,即使超过尾数的最大长度23位也除不尽!这就是著名的浮点数精度问题了。不过我在这里不是要给大家讲《数值计算》,用各种方法来提高计算精度,因为那太庞杂了,恐怕我讲上一年也理不清个头绪啊。我在这里就仅把浮点数表示法讲清楚便达到目的了。
反正最后一直求也求不尽,加上前面的整数部算够24位就行了:1111011.01110100101111001。某BC问:“不是23位吗?”我:“倒,不是说过了要把第一个1去掉吗?当然要加一位喽!”
现在开始向左移小数点,大家和我一起移,众:“1、2、3……”好了,一共移了6位,6加上127得133(怎么跟教小学生似的?呵呵~),二进制表示为:10000101,符号位为……再……
不说了,越说越啰嗦,大家自己看吧:
0 10000101 11101101110100101111001
42 F6 E9 79
32位浮点数(123.456)在内存中如果存储为 79 E9 F6 42。
则先将其到序 42 F6 E9 79使其高位在前;
再将其转化为二进制:0 10000101 11101101110100101111001
最高位是符号位 0表示是正值;
接下来8位是指数位 转换为十进制再减127 结果6;
尾数部分右移6位111011.01110100101111001;
最前面添1 变为1111011.01110100101111001;
整数部分为1111011 转为十进制123;
小数部分01110100101111001;
其中0对应2的-1次方,接下来的1对应2的-2次方:
即0*2(-1)+1*2(-2)+1*2(-3)+1*2(-4)+0*2(-5)+1*2(-6)......≈ 0.456
最后相加接近于0。456
结果123.456
==========================================================
Java 程序:
System.out.println("将 123.456F 浮点数转换成16进制:");
System.out.println("十进制位:"+Float.floatToIntBits(123.456f));
System.out.println("十进制位转二进制:"+Integer.toBinaryString(Float.floatToIntBits(123.456f)));
String string = Integer.toHexString(Float.floatToIntBits(123.456f)).toUpperCase();
System.out.println("十六进制:"+string);
System.out.println("十六进制转换成10进制位:"+Integer.parseInt(string, 16));
System.out.println("十进制浮点数:"+Float.intBitsToFloat(Integer.parseInt(string, 16)));
===============================================================