关于float的有效位

mylzw 2004-09-15 07:39:38
很简单的一个程序:
main()
{
float ff;
ff=123456.789e5;
printf("\n%f\n",ff);
}

为什么结果为:12345678848.000000
不是说float用24位来保存尾数吗? 24位最多只能保存8位十进制数啊。
最后怎么会多出个848呢?
哪个高人能解释一下这个848从哪儿来的啊。~~
还有,一个十进制实数,到底是如何转换为二进制浮点数然后保存进内存中去的呢?然后又是怎么取出显示为十进制实数的?比如以上程序中的ff
...全文
462 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
柯本 2004-09-16
  • 打赏
  • 举报
回复
:C中float参于运算时都是会转成double,可是float ff它没参与运算啊。:
printf("\n%f\n",ff);
作为函数的参数,它就转成了double,汇编中已很清楚了
fstp qword ptr [esp] // 这里,转成double
mylzw 2004-09-16
  • 打赏
  • 举报
回复
goodboy1881的思路是对的,但计算有些误差! 我又算了算:
12345678900 转换为二进制为:
1011011111110111000001110000110100 (共34位)
然后将尾数规格化为:
1.011011111110111000001110000110100 * 2^33
根据浮点数规格标准,小数点前面的1可舍去,于是规格化的尾数为:
011011111110111000001110000110100 * 2^33
阶码为33,进行移码后就是33+128就是10100001,占8位,加上尾数符号位共9位。由于float只有32位存储空间,所以只余下23位来储存尾数。
这时尾数为:01101111111011100000111
这时完整的机器码应为:
0(尾符) 01101111111011100000111(尾数) 10100001(阶码)
按照以上浮点数,展开就是1011011111110111000001110000000000 正好是十进制数12345678848 :)

其实float尾数还是24位,符号位1位,阶码8位。这是没错的。

只是数太大,造成了直觉的假象。。。 算算的话就清楚了。。。

真是感谢大家,在学校问老师好几次了,都没得到个答案。
积木 2004-09-16
  • 打赏
  • 举报
回复
怎么最高位的两个1都“消失”了?

你再看看,我就去掉了小数点前面的那个1啊,因为电脑默认的小数点前面都是一个1~
所以可以省略掉。
bailingke 2004-09-15
  • 打赏
  • 举报
回复
应该是7位有效数字,第8位以后的数字是没有意义的。
把ff=123456.789e5改为ff=123456.790e5或ff=123456.788e5,输出也不会变化的。
因为有效数字的位数是固定的,多余的数字无法表示。
积木 2004-09-15
  • 打赏
  • 举报
回复
to ahhy(蓝色海洋) 就是这个意思啊~ 如果指数和表示的位数都定了
那么float的精度和表示的范围就都有很大的限制~
ahhy 2004-09-15
  • 打赏
  • 举报
回复
goodboy1881 你的大部分解释我都理解了,谢谢!
但还有一部分我有点晕,能解释一下吗?
因为上面已经是31位(第一位的1不用存),
而我们只有32位的存储单元,没有办法只要省掉最后的末尾用于存储
指数和符号(因为不是无符号形的),就是

0 11111 1011111110111000001110000

怎么最高位的两个1都“消失”了?



mylzw 2004-09-15
  • 打赏
  • 举报
回复
这么说float的尾数和阶码的分配是随机的,不是固定的?
我还以为float的尾数固定为24位呢! <是书上说的,一般float的阶码为24位,老谭的《C程序设计》第二版>
ahhy 2004-09-15
  • 打赏
  • 举报
回复
不是说float型数据的有效位是7位吗?
还有,十进制转为二进制不是由编译器而定的吗?
根据小数,整数以及指数所占位数再存储的吗?
mylzw 2004-09-15
  • 打赏
  • 举报
回复
感谢 goodboy1881 的含泪叙述 ! :)
mylzw 2004-09-15
  • 打赏
  • 举报
回复
汇编俺不懂。。。
C中float参于运算时都是会转成double,可是float ff它没参与运算啊。
难道float ff,和double k 所能表示的值一样?

另外,为什么float转换为double会有误差呢?~
积木 2004-09-15
  • 打赏
  • 举报
回复
……
我建议你去看一下float的存储,然后就大致清楚后面的精度为什么不够,原来是省略了~
也就知道为什么它比int表达的范围大,原来它有几位是用来存储指数的,算了还是写写吧
比如这个数是12345678900
二进制的数是多少呢?

11011111110111000001110000110100 (我都快哭了~)
然后这个数变成小数
1.1011111110111000001110000110100 * 2^31
然后对31进行编码就是 11111
因为上面已经是31位(第一位的1不用存),
而我们只有32位的存储单元,没有办法只要省掉最后的末尾用于存储
指数和符号(因为不是无符号形的),就是

0 11111 1011111110111000001110000 这个数还原回去就一定不是那个数了你算算

后面少了110100=32+16+4=52

正好就是你说的那个少的部分~
柯本 2004-09-15
  • 打赏
  • 举报
回复
另外,float 转成double 会有误差
看下面程序:
#include <stdio.h>
main()
{
float ff;

double k,m;

ff=123456.789e5;

k=ff;
printf("\n%f\n",k);
m=123456.789e5;
printf("\n%f\n",m);

}
表面上看,两个结果应相同,实际为
12345678848.000000

12345678900.000000
这是因为 k=ff;转换时有误差,且与 printf("\n%f\n",ff); 完全相同

kinglonghr 2004-09-15
  • 打赏
  • 举报
回复
楼上的回答是正确的
柯本 2004-09-15
  • 打赏
  • 举报
回复
在C中float参于运算时都是会转成double,看看汇编就知了:
_main segment virtual
@_main proc near
?live16385@0:
;
; main()
;
push ebp
mov ebp,esp
push ecx
;
; {
; float ff;
; ff=123456.789e5;
;
@1:
mov dword ptr [ebp-4],1345844999
;
; printf("\n%f\n",ff);
;
fld dword ptr [ebp-4]
add esp,-8
fstp qword ptr [esp] // 这里,转成double
push offset s@
call @_printf
add esp,12
xor eax,eax
;
; }
;
@3:
@2:
pop ecx
pop ebp
ret
@_main endp
_main ends

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧