免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2586 | 回复: 5
打印 上一主题 下一主题

[C] [求教]浮点数的2进制表示法疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-18 10:19 |只看该作者 |倒序浏览
10可用积分
如题,这两天研究了一下IEEE浮点数表示法,根据一位dx的提示看了一下这个帖子
http://blog.csdn.net/zhaomu/archive/2006/06/27/840462.aspx

然后我在solaris8上面用gcc作了一个实验,实验的结果和我期望的相差很远
1.源代码
>cat f.c
#include<stdio.h>
int main(void){
float f=1.0f;
float f2=2.0f;
float f3=3.0f;
float f4=4.0f;
float f5=0.0f;
int *pf;
int *pf2;
int *pf3;
int *pf4;
int *pf5;
pf=(int*)&f;
pf2=(int*)&f2;
pf3=(int*)&f3;
pf4=(int*)&f4;
pf5=(int*)&f5;
printf("%x\n",*pf);
printf("%x\n",*pf2);
printf("%x\n",*pf3);
printf("%x\n",*pf4);
printf("%x\n",*pf5);
return 0;
}

2.运行结果
> gcc f.c && ./a.out
3f800000
40000000
40400000
40800000
0

3.我看了一下这几个数字的2进制表示形式,和IEEE浮点表示法相差很远:
首先高位是3(0011或者4(0100),符合第一位是0的条件(正数)。但是指数位的值也太大了。
例如3f8就是001111110100,指数位是(01111110),远远不止1.0f吧,这是怎么回事呢?

4.这里的printf输出浮点数的值是用了一个类型转换,请问在这里机器硬件是big-endian还是small-endian对于输出结果有没有影响,也就是说,我应该把3f800000反过来看? 打印了5个数字看起来只有0是正确的。

10分感谢!

最佳答案

查看完整内容

再看看这个:测试一下其中的代码。详细讲解IEEE浮点数[原创] http://breakman.bokee.com/4651854.html

论坛徽章:
3
戌狗
日期:2014-09-10 17:07:162015年辞旧岁徽章
日期:2015-03-03 16:54:15wusuopu
日期:2016-06-17 17:43:45
2 [报告]
发表于 2008-12-18 10:19 |只看该作者
再看看这个:测试一下其中的代码。

详细讲解IEEE浮点数[原创] http://breakman.bokee.com/4651854.html

从存储结构和算法上来讲,double和float是一样的,不一样的地方仅仅是float是32位的,double是64位的,所以double能存储更高的精度。
    任何数据在内存中都是以二进制(0或1)顺序存储的,每一个1或0被称为1位,而在x86CPU上一个字节是8位。比如一个16位(2字节)的short int型变量的值是1000,那么它的二进制表达就是:00000011 11101000。由于Intel CPU的架构原因,它是按字节倒序存储的,那么就因该是这样:11101000 00000011,这就是定点数1000在内存中的结构。
    目前C/C++编译器标准都遵照IEEE制定的浮点数表示法来进行float,double运算。这种结构是一种科学计数法,用符号、指数和尾数来表示,底数定为2——即把一个浮点数表示为尾数乘以2的指数次方再添上符号。下面是具体的规格:
````````符号位 阶码 尾数 长度
float    1     8    23   32
double   1    11    52   64
临时数   1    15    64   80
由于通常C编译器默认浮点数是double型的,下面以double为例:
共计64位,折合8字节。由最高到最低位分别是第63、62、61、……、0位:
    最高位63位是符号位,1表示该数为负,0正;
    62-52位,一共11位是指数位;
    51-0位,一共52位是尾数位。
^P
    按照IEEE浮点数表示法,下面将把double型浮点数38414.4转换为十六进制代码。
    把整数部和小数部分开处理:整数部直接化十六进制:960E。小数的处理:
0.4=0.5*0+0.25*1+0.125*1+0.0625*0+……
    实际上这永远算不完!这就是著名的浮点数精度问题。所以直到加上前面的整数部分算够53位就行了(隐藏位技术:最高位的1不写入内存)。
    如果你够耐心,手工算到53位那么因该是:38414.4(10)=1001011000001110.0110101010101010101010101010101010101(2)
(注:实际上我也没算到那么位,这个也只是意思一下,所谓的55 55 55 55 CD C1 E2 40 对应却是38414.4166666666642……)科学记数法为:1.001……乘以2的15次方。指数为15!
    于是来看阶码,一共11位,可以表示范围是-1024 ~ 1023。因为指数可以为负,为了便于计算,规定都先加上1023,在这里,15+1023=1038。二进制表示为:100 00001110
    符号位:正—— 0 !
    合在一起(尾数二进制最高位的1不要):
01000000 11100010 11000001 11001101 01010101 01010101 01010101 01010101
    按字节倒序存储的十六进制数就是:
55 55 55 55 CD C1 E2 40

    另外:float方法类似,不再叙述。下面一个小程序可用于显示任意float在内存中的二进制数。

  1. /**********************************************************/

  2. #include<stdio.h>

  3. int main()
  4. {
  5. float f;
  6. unsigned int i;
  7. char *p=(char*)&f;
  8. scanf("%f",&f);
  9. for(i=0;i<4;i++)
  10. {
  11. unsigned int j=0x80,tmp=*(p+i);
  12. for(;j;j>>=1)
  13.               if(j&tmp)printf("1");
  14.               else printf("0");
  15. printf("\t");
  16. }
  17. return 0;
  18. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2008-12-18 10:28 |只看该作者
我觉得楼主应该用移位办法打出这些值

楼主想要做什么呢?

论坛徽章:
0
4 [报告]
发表于 2008-12-18 10:49 |只看该作者
原帖由 linternt 于 2008-12-18 10:28 发表
我觉得楼主应该用移位办法打出这些值

楼主想要做什么呢?

就是打印出来浮点数的2进制存储的内容,谢谢 ... ...

论坛徽章:
3
戌狗
日期:2014-09-10 17:07:162015年辞旧岁徽章
日期:2015-03-03 16:54:15wusuopu
日期:2016-06-17 17:43:45
5 [报告]
发表于 2008-12-18 10:53 |只看该作者
楼主好有耐心。我看到数学有点头疼,就没自己写代码。
参考一下这个帖子。里面有个文档比较有用
http://bbs.chinaunix.net/viewthread.php?tid=721362

论坛徽章:
0
6 [报告]
发表于 2008-12-18 14:06 |只看该作者
原帖由 ynchnluiti 于 2008-12-18 11:12 发表
再看看这个:测试一下其中的代码。

详细讲解IEEE浮点数[原创] http://breakman.bokee.com/4651854.html



/**********************************************************/

#include

int main()
...

谢谢,上面的这句话很重要:"于是来看阶码,一共11位,可以表示范围是-1024 ~ 1023。因为指数可以为负,为了便于计算,规定都先加上1023,在这里,15+1023=1038。二进制表示为:100 00001110
"

所以对于浮点数来说,就是把有符号的8位阶码加上127成为一个总是正数的8位无符号证书,
于是

-1的表示就是
符号位1 阶码127(01111111) 尾数0
10111111 10000000 00000000 00000000
4的表示就是
符号位0 阶码127+2(10000001) 尾数0
0100 0000 10000000 00000000 00000000 也就是16位表示的40 80 00 00

0.5的表示就是
符号位0 阶码127-1(01111110) 尾数0
00111111 00000000 00000000 00000000
------------------------------------------------------
同理
0.75就是 00111111 01000000 00000000 00000000
1.5就是  01000000 10000000 00000000 00000000

经测试,3个unix平台的浮点表示都是顺序位
Solaris+sparc
HP-parisc
Itanium
而x86的pc是按byte倒序。

谢谢dx的指点,结贴给分!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP