| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5906 人关注过本帖, 1 人收藏
标题:整型与浮点型数据运算结果为什么是0?
只看楼主 加入收藏
chamlien
Rank: 1
等 级:新手上路
帖 子:9
专家分:0
注 册:2013-12-27
收藏
得分:0 
以下是引用vvvcuu在2015-9-4 23:29:48的发言:

先了解一下整型数据和浮点型数据在内存中的存储方式再来考虑这个问题吧.  强制类型转换仅仅在变量参与运算的那一刻起作用, 并不改变变量原来的类型和数值.

可以试着运行以下代码看看与你自己想想的结果是否一样:

# include <stdio.h>

int main(void)

{
  int a=30;
  float b=3.0;
  float c=0.00000003;
  float d=123456789.0;
  printf("%f\n%d\n%d\n%d\n",a,b,c,d);
  return 0;
}

是不是与自己想的答案有出入?
整型数据1在内存中是这样存储的00000000 00000000 00000000 00000001      //实际是连续的,这里为了方便观察,8位一组加空格了
//当然实际可能还设计补码,移码,反码之类的东西,详细讨论没有益处, 按照原码来理解更方便一些.



如果这个数字表述浮点数的话,那么就麻烦了, 除了一位符号位,8位阶码(指数),还有23位,这23位都在小数点后面啊, 算一下这个数字换成10进制成了多少?

2^(-23)

这个数字直接输出,对于只有6位有效数字的float实在是力不从心.所以它只好给你7个0了.


例子举得很到位,以上的值输出确实不同,不过自己的基础还没打好,先留着消化几天
2015-09-04 23:36
vvvcuu
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:12
帖 子:353
专家分:1253
注 册:2014-4-22
收藏
得分:0 
回复 21楼 chamlien
几天?

百度一下"浮点数存储方式", 有10多分钟就明白大概了. 如果不是搞硬件的, 消化几天有点浪费时间了.

另外, 不同的编译器对于整型和浮点型的规定不一样,  我一直以为浮点型数据占的位数要多, 可是我输出后发现, 我用的编译器整型和浮点型竟然都占4个字节.

代码测试环境:  WinXP+C-Free5.0.
2015-09-04 23:41
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:0 
表示的数据过小是根本原因,但并不像18楼所说的2^-23,而是更小的2^-127。
单精度数表示浮点数1在内存中的二进制印象是00111111 10000000 00000000 00000000,其中红色部分指数部分,蓝色部分为尾数部分(我们通常所说的有效位、精度)【二进制指数表示法可用23位表示出24位有效位,是二进制的特殊性导致的,因为第一位恒等于1(十进制则有1-9之间的数可选),所以虽然我们看到尾数部分为全0,但它实实在在地表示1】,很显然浮点数1的二进制指数表示应当为1.0*2^0,但实际数据却为1.0*2^127,因此,关键在指数部分,据说为了方便浮点运算,单精度浮点数指数部分基数为127,大于127的数为正指数,小于127的为负指数,不是我们通常理解的高位为1就是负指数,所以指数部分为全0的话该数据的指数为0-127=-127,即1前面小数点后面有127个0,那实在太小了。所以整数以浮点数格式表示会显示0了。

[ 本帖最后由 wmf2014 于 2015-9-5 09:58 编辑 ]

能编个毛线衣吗?
2015-09-05 09:50
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
很显然,是楼主的运行环境有问题。

授人以渔,不授人以鱼。
2015-09-05 21:21
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
用printf("%f\n", (float)(1 / 1));是没有问题的,输出为1.000000。

但用printf("%f\n", 1 / 1);则输出为零,无论是用1/2还是2/1,结果都是零。解释很简单:/整数运算,结果是int型,但格式符"%f"请求的数据类型是double,不是float,前者的数据长度比后者大一倍,在32位机上,将32位的int数据扩展为64位的double,就是零!

授人以渔,不授人以鱼。
2015-09-05 21:33
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
printf()的行为,不是标准的数据转换行为,它祗是把一个数据“视同”格式符所表达的数据类型来解读。整数1的字节数是4,但对使用"%f"的printf()函数来说,它不是取4个字节,而是取8个字节的数据,这样后面的4字节极可能是0,把这8字节连起来解释为double型数据,通常是0。

以下代码输出的结果为1.000000
float x = 1 / 1;
printf("%f", x);


[ 本帖最后由 TonyDeng 于 2015-9-6 11:34 编辑 ]

授人以渔,不授人以鱼。
2015-09-05 21:38
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:0 
回复 26楼 TonyDeng
嗯,T版说的是!
通过对编译后的代码跟踪,可以看到编译器会在调用printf前对float类型强制转换为双精度(不实际影响fload变量精度),而对整形变量不做变换,即虽然指示printf按%f格式显示,但数据只有低4位,高4位数据不确定,vc++编译器是push edi,也就是刚刚进入本函数时edi的值,本例中为0012ff80(见下图),所以本例中要按%f格式显示整形变量1的值,printf会按双精度数据“00 12 FF 80 00 00 00 01”来显示,该数据指数部分还是11个0,即这个数的小数点后面有1023个0(03 FF FF),这个数据就更小了,所以仍然会以0.0000显示了。
图片附件: 游客没有浏览图片的权限,请 登录注册

能编个毛线衣吗?
2015-09-06 09:52
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:1 
所谓的“强制类型转换”,字眼上就误导了人。事实上,那种写法并没有转换数据,而是“当什么数据看”。从26楼的测试代码就可以看出,关键是前面的赋值语句,在等号右边,数据都是常量,是不可能被转换的,但编译器的实际动作,是按照左边的数据类型解读,最后给变量x初始化的值是真正的float型,这个时候,才有数据提升过程,值是对的。但若省去这个赋值,直接把1/1写到下面的printf()函数中,就不是那么回事了。这种情况,是貌似可以替换,但事实上不能。

[ 本帖最后由 TonyDeng 于 2015-9-6 12:58 编辑 ]

授人以渔,不授人以鱼。
2015-09-06 11:38
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:1 
嗯,当什么数据看更准确。
我在27楼也说了,这种转换并不影响数据类型。比较奇怪的是编译器只转换float到double,其他类型不做这个操作,从表面上看,这个工作好像是编译器做的,printf函数只认显示格式和显示数据地址,但实际上编译器怎么知道我后面将要调printf函数呢?又怎么知道只有printf函数需要这种操作呢?printf并不是c内部关键字,而普通函数只需要往栈里压值或地址就可以了,无需提前做任何转换。
估计这还要从printf函数可变形参个数的特殊性方面考虑

能编个毛线衣吗?
2015-09-06 13:03
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
printf()函数的机制,是运行时解释的,不在编译阶段(vs2015编译器能够发出"%f"请求double的警告,别的编译器不知道)。我以前一直说过,像scanf()/printf()这样的东西,已经等于一个小型的BASIC语言了,是创建这些函数的程序猿自己制定的语言约定,不是C语言自己的。各种各样的C语言版本,有不同的输入输出函数库,并非一定要用scanf()/printf()。C标准,也没规定语言有内置输入输出功能。我还是那句话:C的强大,是因为它什么也没有!

授人以渔,不授人以鱼。
2015-09-06 13:26
快速回复:整型与浮点型数据运算结果为什么是0?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.094127 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved