c语言为啥警告说从“int”转换到“float”,可能丢失数据
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c语言为啥警告说从“int”转换到“float”,可能丢失数据相关的知识,希望对你有一定的参考价值。
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void main()
srand((unsigned)time(NULL));
for (int i=0; i<100; i++)
float a=rand()%11;//[0,10)
float b= a/10000;
printf("%f ", b);
getchar();
在C语言中,int是整型变量,其代表的是准确值。而float是单精度浮点数,其本身是有精度限制的。也就是说,存在float变量中的数据,可能看起来是那个数,打印出来也是,但是实际存的是一个很接近但是并不准确的值。
比如int的值是1000,转成float之后,可能存的就是1000.0000000000001(仅做举例,实际上并不一定是这个值)。
这样int转换成float的时候,就出现了精度丢失。
对于越大的数,这种现象就越普遍。 参考技术A int采用2进制补码存储,大小32位。表示范围 -2^31 ~ 2^31-1.
单精度浮点数 存储机制为 (-1)^s * M * 2^E ,长度32位。
具体为 1个符号位, 8个指数位, 23 个有效位。
具体怎么计算的分三种情况,比较复杂就不说了。
当整数转换为浮点数时,首先位序列小数点移至最高位1的后面,如
15 = 1111 = 1.111 * 2^3,由此可知 s = 0, M = 1.111 = 1 + 1/2 + 1/4 + 1/8, E = 3.
换算后 可得15.0f 的二进制序列为
0 1000 0010 111 0000 0000 0000 0000 0000.
问题就在移动小数点,如果该整数的值大于2^24,即最高位1后面有24位甚至更多位,浮点数的有效位只会保存最高位1后面23位值,其余的都被rounding了。从而导致可能的精度丢失,比如
int a = pow(2,24)+1;
位序列为 0000 0001 0000 0000 0000 0000 0000 0001
移动小数点 =》 1.000 0000 0000 0000 0000 0000 × 2^24
最低位的1就被rounding了。
所以归根到底,当被rounding的位有1时,精度就变化了。
同时,double 为 1个符号位 , 11 个指数位, 52 个有效位,故 int 到double 不会丢失精度。 参考技术B Widening primitive conversions(基本类型扩宽转换)。
以所占字节数为基准,单字节向多字节转换就是所谓的扩宽,比如1到2、2到4等。int到其他整数类型的转换、float到double是没有失真的,完全一致。但是整数到浮点数的转换虽然也是扩宽,但因为浮点数是用有效数字的方式进行表示的,转换的时候可能出现精度损失(float类型不能支持9位有效数字),如int i=1234567890;float pp = i - (float)i;pp不等于零。带符号int转换为其他整数类型的方法是对其数字的二位补码方式进行带符号扩展【这个me碰到问题的关键byte-》int】,char类型转换为int类型的方法是进行0扩展。提示:无论精度是否损失,扩宽转换都不能引发运行时错误。 参考技术C 现代计算机采用的是IEEE754标准表示float型,此时能表示真值的只有24位二进制数,而int型是32位二进制数,可想而知这少的8位数float中就没法体现出来 参考技术D int rand(void)
返回数据类型为int型
所以a=rand()%11也为int型
你却用float型当然它会那么提示本回答被提问者采纳
为啥 int 被提升为 double 而不是 float 以进行隐式转换
【中文标题】为啥 int 被提升为 double 而不是 float 以进行隐式转换【英文标题】:Why is int promoted to double and not float for implicit conversion为什么 int 被提升为 double 而不是 float 以进行隐式转换 【发布时间】:2016-09-05 11:38:02 【问题描述】:我目前正在学习 C++ 思想 C++ Primer。在关于类型转换的第 4.11 章中,我注意到该章很少讨论从整数到浮点类型的隐式转换,而是主要关注整数类型内的转换。因此,我不太确定从整数类型到浮点类型的转换规则。
我的问题来自本章的示例:
int ival = 3.541 + 3
章节中提到3在添加3.541之前转换为double
类型。
问题源于这样一个事实,对于大多数整数类型,它们在隐式转换期间大多被提升为int
,除非它们无法适应int
。既然int
和float
都是相同的4 字节大小,并且3.0 和3.541 可以完美地适合float
,为什么在这种情况下使用高阶double
而不是@987654329 用于隐式转换@?这是否意味着对于任何整数类型到浮点类型的隐式转换,无论精度或大小如何,整数类型都将转换为double
?
非常感谢!
【问题讨论】:
3.541 根本无法放入浮点数,它是二进制的重复分数。 如果你这样做int ival = 3.541f + 3
然后使用浮点数。
【参考方案1】:
3.541
是双精度。所以这就是另一个参数需要转换为的内容。
后缀用于表示文字的精度,3.541f
(或 F)是浮点数,3.541L
(或 l)是长双精度数。默认(无后缀)为双精度。来源http://en.cppreference.com/w/cpp/language/floating_literal。
3.541 不适合任何这些长度,因为它是二进制的重复分数。实际值将是尽可能接近 3.541 的浮点值(如 3.540999999999999925393012745189480483531951904296875 在双精度的情况下)。
【讨论】:
【参考方案2】:默认情况下,如果你写这样的东西:
int ival = 3.541 + 3;
3.541
将被视为double
,因为没有任何后缀,这是编译器默认假定的。如果您希望将其视为浮点数,请执行以下操作:
int ival = 3.541f + 3; //See the 'f' there. For floats
另外,如果您想知道为什么有时3.1541
没有正确表示可能是因为它的二进制表示不够准确。阅读this article for more info
【讨论】:
以上是关于c语言为啥警告说从“int”转换到“float”,可能丢失数据的主要内容,如果未能解决你的问题,请参考以下文章
C 中从 Float 到 Int 的类型转换导致数字大不相同,为啥?