一直在忙,有好一阵子没顾得上写blog了,今天一来还是看到有网友对浮点数的十六进制表示问题存有疑问(
http://blog.chinaunix.net/u/11768/showart_137027.html),可能还是因为我没把问题说清楚,这回再通过一个简单的例子解释一下,以后该是不会再写与此问题相关的文章了。
先看看问题:0.6875的16进制如何表示?
我们知道0.6875是一个浮点数的十进制表示法,而计算机在存储的时候是不能把这样一个小数往存储器里存的,而是通过把数据转换成二进制的形式存储,从而对应到物理上的高电平、低电平来表示(为什么要这样?问问计算机的先驱——图灵大神吧)。那么我们首先来看看,0.6875这样一个小数如何转成一种我们可以看的懂的二进制表示形式呢?
对于一个整数怎么转二进制想必大家都已经很清楚了,小数其实也是一样的道理。
20 ---- 1/1 ---- 1
2-1 ---- 1/2 ---- 0.5
2-2 ---- 1/4 ---- 0.25
2-3 ---- 1/8 ---- 0.125
2-4 ---- 1/16 ---- 0.0625
2-5 ---- 1/32 ---- 0.03125
...
0.6875 = 0.5 + 0.125 + 0.0625
由此转换我们可以接受的一种二进制表示是0.1011,可这样的表示我们是看懂了,但计算机却看不懂,计算机是无法把小数点往存储器里存的。怎么办呢?于是大家便按照一个统一的约定来表示浮点数在内存中的存储,目前采用的就是IEEE的浮点数规格化表示。关于这个表示方法可以查资料,本blog里也有过两篇文章提到过这个问题(
http://blog.chinaunix.net/u/11768/showart.php?id=100351和
http://blog.chinaunix.net/u/11768/showart_137027.html)。简言之,对于float类型来说,就是以1位的符号位+8位的指数域位+23位的小数域位凑成的32个bit的二进制数来存储。
还是按照之前的方法移动小数点,留出一个整数位的1,成了1.011,在这过程中小数点右移了一位。而在之前的例子中都是以左移居多。这样,在公式
E = e-Bias中,E=126-127=-1,也就是说指数域e=126,也就是说指数域是01111110,
因此0.6875在二进制中的存储就应是:
0 01111110 01100000000000000000000
|1|<---8--->|<---------23---------->|
亦即
0011 1111 0011 0000 0000 0000 0000 0000
就是十六进制的0x3F300000啦。
说了那么多次了,次次都是空口无凭,还是写个程序来验证一下吧。
/*
* =====================================================================================
*
* Filename: floatStorage.c
*
* Description: convert the memory storage of a float number to a hexadecimal string
*
* Version: 1.0
* Created:
* Revision: none
* Compiler: gcc -Wall -g -o floatStorage floatStorage.c
*
* =====================================================================================
*/
#include <stdio.h>
#define F2HEX_LEN 11
#define TRUE (1==1)
#define FALSE (!TRUE)
int isLittleEndian()
{
int x = 1;
if (*(char *)&x == 1) {
printf("little-endian\n");
return TRUE;
}
else {
printf("big-endian\n");
return FALSE;
}
}
char *float2HexStr(float f, char *buff)
{
unsigned char *pf = (unsigned char *)&f;
if (sizeof(f)>sizeof(float))
return NULL;
if (isLittleEndian())
snprintf(buff, F2HEX_LEN, "0x%02x%02x%02x%02x", pf[3], pf[2], pf[1], pf[0]);
else
snprintf(buff, F2HEX_LEN, "0x%02x%02x%02x%02x", pf[0], pf[1], pf[2], pf[3]);
return buff;
}
int main() {
float f1 = 0.6875, f2 = -0.6875, f3 = 551051722752.0;
char buff[F2HEX_LEN];
printf("f1=%g=%s\n\n", f1, float2HexStr(f1, buff));
printf("f2=%g=%s\n\n", f2, float2HexStr(f2, buff));
printf("f3=%g=%s\n\n", f3, float2HexStr(f3, buff));
return 0;
}
|
运行结果为:
> ./floatStorage
little-endian
f1=0.6875=0x3f300000
little-endian
f2=-0.6875=0xbf300000
little-endian
f3=5.51052e+11=0x53004d3e
通过这个小sample我们还可以看到符号位的问题,还有之前的文章中讨论的那个浮点数
551051722752是不是像我说的那样存储。
阅读(1362) | 评论(2) | 转发(0) |