社区
C++ 语言
帖子详情
[100分请教]float强制转化为long时遇到的怪问题
brinker
2005-07-25 03:06:02
代码很简单:
float f1,f2;
... // 计算f1和f2的值,在VC中用Watch观察发现,f1和f2的值都等于203.000
long l1 = (long)f1; // 这时候l1的值竟然不等于203,而是202
long l2 = (long)f2; // l2的值是正常的203
请问这是什么原因?如何避免
...全文
573
18
打赏
收藏
[100分请教]float强制转化为long时遇到的怪问题
代码很简单: float f1,f2; ... // 计算f1和f2的值,在VC中用Watch观察发现,f1和f2的值都等于203.000 long l1 = (long)f1; // 这时候l1的值竟然不等于203,而是202 long l2 = (long)f2; // l2的值是正常的203 请问这是什么原因?如何避免
复制链接
扫一扫
分享
转发到动态
举报
AI
作业
写回复
配置赞助广告
用AI写文章
18 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
Start13
2005-07-25
打赏
举报
回复
楼主:
怎么在内存中看l1,l2的值啊?请教啊!
brinker
2005-07-25
打赏
举报
回复
谢谢各位,我把情况再详细说说,请各位看看能不能帮我,谢了
我现在做的东西是显示一幅地图,而地图是分块显示的,比如分为左右两块显示,从地图库中读取后要把地图中的经纬度转换为屏幕上的坐标才能显示出来,这时候问题就出来了,因为坐标转换的过程有少许误差,这样左边地图的右边界的屏幕坐标和右边地图的左边界的屏幕坐标(浮点数)就有一个比较小的(大约0.001)差值,而显示到屏幕的时候要转换成整数,这样就出现了我上面所说的问题。比如左边地图右边界(X)坐标是202.999 右边是203.000,又或者左边坐标是202.499,右边是202.500,直接转化成整数的时候就会有一个像素的误差,我的问题是怎么能尽可能少地避免这种误差。
sjjf
2005-07-25
打赏
举报
回复
把最后一位拼上 0x01,试一下
float f1,f2;
long l1 = (long)(f1|0x01);
long l2 = (long)(f2|0x01);
pcboyxhy
2005-07-25
打赏
举报
回复
仔细看下面的
#include <stdio.h>
int main(int argc, char *argv[])
{
float p = 5.1f;
int f = (int)(p*100);
printf("%d", f);
getch( );
return 0;
}
我想要输出 510,可是机器nnd居然输出509(竟然敢扣我工钱)。
到底是what's wrong。我上看下看,左看又看,看了又看,就是发现不了错误。
于是我试着把5.1改成5.5,一切正常啊。捣鼓了N个小时后猜想,莫非是浮点数的表示问题,
于是花了很久找到浮点数的机器表示方法,照着规定克隆操作了一下。(据说练过乾坤大
挪移的人什么招式都可以克隆)。
IEEE规定的浮点数的机器表示:
32位机器的 float 是4字节的,共32位。
第1位是符号位,接着8位指数位,接着23位基数位。
以5.1为例。
5 = 101 (2进制)
0.1 = 0.0 0011 0011 0011 0011 0011 0011 .....(无限循环)
所以 5.1 = 101.0 0011 0011 0011 0011 0011 0011 0011 0011 ...
5.1= 1.010 0011 0011 0011 0011 0011 0011 0011 0011 0011... * 2^2
因为第一位总是为1,如果是0,就移动小数点直到是非0的,所以第一位的1丢弃。
得到 010 0011 0011 0011 0011 0011 0011 0011 0011....
取23位 得到 0100 0110 0110 0110 0110 011
接着看指数部分
指数是2, 根据规定,指数统一+127再转换为无符号8位2进制数,
2+127=129 (1000 0001)
存储的时候指数部分存储在基数之前,这样就有31位了,
因为5.1是正的,所以符号为是0,存储在指数部分之前
这样就得到 0100 0000 1010 0011 0011 0011 0011 0011
我们来看一下机器上是否真的如此
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
float a=5.1;
int *i=&a;
printf("%x", *i);
system("PAUSE");
return 0;
}
40a33333
0100 0000 1010 0011 0011 0011 0011 0011
果真是一样的。
这个例子就说明了为什么浮点数有时存在这样的问题。
这个数化为10进制整数的时候,
由于不可能达到5.1(5.099..)
所以×100后截取了前面的值 509。
无奈吧,这个时候想要精确的浮点数的话,
只有自己写高精度算法了。
老夏Max
2005-07-25
打赏
举报
回复
一般浮点小数是用二进制小数表示的,和整数部分类似,小数也是2的幂次方,只不过幂次是负数而已。
例如:0.5(10)表示为0.1(2),通俗的说,就是2^-1,也就是1/2,同样:0.25(10)表示为0.01(2),即2^-2,也就是1/4。对于一个定长的小数,例如8位二进制小数,其实际的值就是所有位上的值相加而成,例如:
0.75(10)=0.11(2)=1/2+1/4
因此对于像0.1(10)这样的值需要很多值进行相加,设8位二进制小数,那么
0.1(10) 可表示为 0.00011001(2) = 1/16+1/32+1/256 = 0.09765625
或者
0.1(10) 可表示为 0.00011010(2) = 1/16+1/32+1/128 = 0.1015625
由于0.00011001和0.00011010之间已经没有可用的二进制表示了(相对于8位定长二进制小数来说),因此只能用这两个值来代替0.1,具体取那个根据实际的舍入规则确定,由此出现了误差。
所以,对于二进制小数来说,只有2的负整数次幂的小数才能够精确表示,否则就可能出现误差。
老夏Max
2005-07-25
打赏
举报
回复
这就是我所说的情况。只要加0.5然后再做就不会出错了!
老夏Max
2005-07-25
打赏
举报
回复
这就是我所说的情况。只要加0.5然后再做就不会出错了!
megaboy
2005-07-25
打赏
举报
回复
唉,楼主想到哪里去了,对于
float f1=203.0,f2=203.0;
long l1 = (long)f1;
long l2 = (long)f2;
这种情况来说,f1的值只会在203的附近,不会偏离到202.450012这么远的。对于202.450012这个值来说,只有f1=202.500这种情况才有可能,这时候,你应该给它加上个0.05l。
robinzsy
2005-07-25
打赏
举报
回复
四舍五入总要有一个分割点的,如果非要实现楼主的要求,可以先判断两数是否十分接近,如里两数之差绝对值小于0.01,如果十分接近,则使用其中一个数的舍入结果作为两数共同的舍入结果。
brinker
2005-07-25
打赏
举报
回复
试了一下,四舍五入到小数点后一位可以解决一部分问题,但是像这种数还是不行
比如:f1 = 302.450012
f2 = 302.449982
当然,四舍五入到小数点后两位就可以了,但是如果
f1 = 308.445007
f2 = 308.444977
又不行了
megaboy
2005-07-25
打赏
举报
回复
楼主的问题可以这样解决:
long l1 = (long)f1+0.5l;
long l2 = (long)f2+0.5l;
robinzsy
2005-07-25
打赏
举报
回复
好像还是不行。那就先四舍五入到小数点后一位,再四舍五入到整数吧。
robinzsy
2005-07-25
打赏
举报
回复
先用ceil()或floor()统一向上或向下取整,再转换成long
brinker
2005-07-25
打赏
举报
回复
谢谢各位,刚才看了一下内存,发现
f1大约等于202.999984
f2大约等于203.000010
现在的问题是如何能把它们都转化为203?
我试了一下用四舍五入,但是不好用,因为除了这种情况以外,还有一种
f1等于384.500030
f2等于384.499999
我想让转化后的结果是相等的,请问有什么方法?
robinzsy
2005-07-25
打赏
举报
回复
f1可能为202.9999999999....由于float类型的精度问题,故显示为203.00但实际上小于203,所以转换成long时,会被截断小数点后的部分。
PMsg
2005-07-25
打赏
举报
回复
如果f1和f2的值都等于203.000
那么后面long l1 l2 的值是一样的
你可以自己赋给f1 f2 203.000 然后强制转换看看啊
PMsg
2005-07-25
打赏
举报
回复
如果f1和f2的值都等于203.000
那么后面long l1 l2 的值是一样的
你可以自己赋给f1 f2 203.000 然后强制转换看看啊
oo
2005-07-25
打赏
举报
回复
浮点表示是不精确的。
你确认f1和f2都是 203.00 ?
java入门到精通整理(一)语言基础
1.代码注释与语言规范 (1)、单行注释: “//”为单行注释标记,从符号“//”开始到行结束 (2)、多行注释: “/* /”为多行注释标记,符号“/ ”与“*/”之间的所有内容都为注释内容 (3)、文档注释: “/* /”文档注释标记。“/**” 与 “/”之间的内容为文档注释内容 //单行注释 /* 注释内容 */ **语言规范:在编码的
时
候所有的标点符号必须是英文、一个类中只能有一个main()方法、并且只能有一个类才能有public修饰 ** 2.变量与常量 (1)、java语言规定标识符由任意顺序的字母、下划线、美元符号、和数字组成。 注意:标识符的第一个字符不能是数字组成 3
MFC中
强制
转换总结
强制
类型转换符号的一般形式如下: cast_name(expression); 其中cast_name为static_cast,dynamic_cast,const_cast和reinterpret_cast之一,type为转换的目标类型,而expression则是被
强制
转换的值。
强制
转换的类型指定了在expression上执行某种特定类型的转换。 1.static_cast 它
VC++数据类型转换
长整型(
long
)ltoa(l,temp,10); 浮点数(
float
,double)用fcvt可以完成转换,这是MSDN中的例子:int decimal, sign; char *buffer; double source = 3.1415926535; buffer = _fcvt( source, 7, &decimal, &sign ); 运行结果:source: 3.1415926535
VC++数据类型转换大全
Cpp代码 int i =
100
;
long
l = 2001;
float
f=300.2; double d=12345.119; char username[]="程佩君"; char temp[200]; char *buf; CString str; _variant_t v1; _bstr_t v2;
数据类型转换的整理
数据类型转换的整理说明:本文纯粹是总结一下有关类型转换的贴子,本人并未对所有方法都做测试,仅仅是为了给大家一个参考。读者层次:初学int i =
100
;
long
l = 2001;
float
f=300.2;double d=12345.119;char username[]="程佩君";char temp[200];char *buf;CString
C++ 语言
65,187
社区成员
250,526
社区内容
发帖
与我相关
我的任务
C++ 语言
C++ 语言相关问题讨论,技术干货分享,前沿动态等
复制链接
扫一扫
分享
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++
技术论坛(原bbs)
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
请不要发布与C++技术无关的贴子
请不要发布与技术无关的招聘、广告的帖子
请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下
试试用AI创作助手写篇文章吧
+ 用AI写文章