x=4.0时,为什么4*x>16 在循环里面结果总是为随机的?有时候为TRUE?

coyer 2004-04-30 10:08:49
邪门了,我好歹也写了5年多的C代码了,怎么这个问题今天搞了一晚上还是没有搞明白啊?

留下邮箱,我把工程代码发给你,帮我调调,谢谢。

/*
* 函数说明:开始搜索过程
* 输入:x1,x2的范围和结果输出指针
* 本函数对于x1和x2的搜索间隔都使用interval,实际使用中可以对x1,x2都单独创建搜索间隔
* 输出:如果返回false,则说明没有找到一个合适约束条件的值,否则则求出该范围内的最合适的值。
*/
BOOL CSimplexDlg::StartSearching(double x1min, double x1max, //x1 range
double x2min, double x2max, //x2 range
double interval, //interval
double * x1Res,double *x2Res, //save x1,x2 fit value
double *maxz) //save result
{
double i,j;
double res;
BOOL finded=FALSE;
double x1,x2,maxres=0.0;
x1=*x1Res;
x2=*x2Res;

//循环检查测试所有约束范围内的值
for(i=x1min;i<=x1max;i=i+interval)
{
for(j=x2min;j<=x2max;j=j+interval)
{
//只对符合约束条件的值进行检测
if (CheckCondition(i,j))
{
res=2.0*i+3.0*j;
//如果当前值计算结果比所有的值都好,则记录下来
if (res>=maxres)
{
x1=i;
x2=j;
maxres=res;
finded=TRUE;
}
}
}
}
//记录结果
if (finded)
{
*x1Res=x1;
*x2Res=x2;
*maxz=maxres;
}
return finded;
}

/*
* 函数说明:约束条件检测
* 输入:x1,x2分别为检测值,本例子为示例程序,约束条件没有化简
* 输出:符合约束条件返回TRUE,otherwise return FALSE;
* 注意点:double类型的相等判断不能使用==,而应该使用fabs(val)<0.000001等自定义的精度。
*/
BOOL CSimplexDlg::CheckCondition(double x, double y)
{
TRACE("\nx=%6.2f,y=%6.2f",x,y);
//保证x1,x2都大于等于0
if (x*y<0.0)
{
TRACE("x*y<0");
return FALSE;
}
//其他各个分限制条件
if ((2*x+2*y)>12.0)
{
TRACE("\nError:(2*%f+2*%f)>12.0",x,y);
return FALSE;
}
if ((x+2*y)>8.0)
{
TRACE("\nError:(%f+2*%f)>8.0",x,y);
return FALSE;
}

if (4*x>16.0)
{
TRACE("\nError:4*%f>16.0",x);
return FALSE;
}
if (4*y>12)
{
TRACE("\nError:4*%f>12",y);
return FALSE;
}
TRACE("\nOK!!!!");
return TRUE;
}

测试条件:
x1: 0~6
x2: 0~4
在间隔为1.0的时候,能得出正确答案:x1=4,x2=2,res=14
在间隔为0.1的时候,得不出正确答案:x1=3.9,x2=2,res=13.8

x1=3.0 ~4.2
x2=1.7~2.2
间隔为1.0 时:得不出正确答案:x1=4,x2=1.7, res=13.1
间隔为0.1时:也得不出正确答案:x1=3.8,x2=2.1, res=13.9

真是邪门了。
...全文
23 17 点赞 打赏 收藏 举报
写回复
17 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
coyer 2004-05-02
哈哈,大家都明白了吧。

感谢 sgnaw(李逍遥) 得研究。

我以前一直以为double类型只有在判断==得时候需要使用自定义精度,没有想到>,<等判断也要这样。呵呵。

幸好分比较多,谢谢大家啦。
  • 打赏
  • 举报
回复
王国凡 2004-05-02
顺手写了个文档,欢迎参观指导:

http://www.csdn.net/Develop/read_article.asp?id=27404
  • 打赏
  • 举报
回复
shines77 2004-05-02
想起来了,以前在做一个数据(小数)的走势图的时候,比如手工计算等于0.925的值死活都有些误差,比如0.924,导致显示总是有偏差,后来我把这个值加大了0.005才解决,看了sgnaw(李逍遥)的测试,让我想起来了,由于浮点的存储格式,导致它是不可能很精确的,必要时要给个误差范围再进行比较,或者人为的加大所要判断的值再比较。
  • 打赏
  • 举报
回复
enoloo 2004-05-02
给我上了一课。

我做的太浮了。

这让我想起了以前写分形demo的时候,发现输出的图形中总有比较奇怪的输出点。当时就没大注意。现在算是明白了~
  • 打赏
  • 举报
回复
王国凡 2004-05-02
回到处理楼主的程序中来,加到 3.9 时也并不是真的 3.9 不多也不少,当加到 4.0 时,其实结果也并不就是 4.0 整,而在这里是得到了比 4.0 要大的一个值,使得此后,对于任何的 j 都有 4*x > 16.0 恒成立,即 CheckCondition (i,j) = FALSE;

这样,当 interval 为 0.1 时,开始进行 double 类型的运算,只算到了 i 为 3.9 那儿。

所以,double 类型是不精确的,在进行大小判断时,不能把它与某个确切的值进行比较,而是应该给个范围。
  • 打赏
  • 举报
回复
王国凡 2004-05-02
为此,我进一步展开了尝试,写了一个程序:

#include <iostream>
using namespace std;

int main()
{
double x = 0.000000;

for (; x<4.000000; x=x+0.100000);
if ( 4.000000*x > 16.000000 )
printf ("4x = %f, x = %f\n", 4*x, x);

return 0;
}

因为 4*x = 16,所以,在通常看来,这个程序它并不应该输出什么东西,可是事实上它却输出了:
4x = 16.000000, x = 4.000000

于是,我就在 printf 那儿设置一个断点,进入调试,会发现此时
x = 4.0000000000000018

但是,如果写个简单一点的却又是另外一种情况:

#include <iostream>
using namespace std;

int main()
{
double x = 0.000000;

x += 0.100000;
if ( x > 0.100000 )
printf ("x = %f\n", x);

return 0;
}

经调试发现 x = 0.1000000000000001 而且,此时似乎又正常了,不输出任何东西。

如果把 x 自加 10 次 0.100000 你会发现结果的 x 不是 1.000000 ,在 Visual C++ 6.0 里的结果是 x = 0.99999999999999989,如果把它和 1 去比较的话,它会显示比 1 小了。
  • 打赏
  • 举报
回复
王国凡 2004-05-02
经过一番研究得出结论:double 数据类型的计算过程是不精确的。

还是从头说起,慢慢道来吧。程序中有一个 i, j 循环,程序开始运行时
i --> 0, j --> 3
...
最后的值可能是
i --> 6, j --> 0

下面具体分析运行过程中的情况:
1.当 interval = 1 时
i += 1; j += 1;
当加到 i = 4; j = 2; 时,关键的下一步为 j = 3;
那么,4*x = 4*5 = 20; 即 CheckCondition (i,j) = FALSE; 跳出 j 循环,i 增 1 ,则 i = 5,
此后,对于任何的 j 都有 4*x = 4 * 5 > 16 恒成立,即 CheckCondition (i,j) = FALSE;
所以,结果为 4, 2, 14

2.当 interval = 0.1 时
当加到 i = 3.9; j = 2.0; 时,关键的下一步为 j = 2.1;
那么,x+2y = 3.9+ 2*2.1 = 8.1;即 CheckCondition (i,j) = FALSE; 跳出 j 循环,i 增 0.1 ,
则此时,i 是 i = 4.0 ,这个 i 值对吗?
如果是正确的,为什么结果会与我们想象的不一样呢?
  • 打赏
  • 举报
回复
shines77 2004-05-01
if (x*y<0.0)
==>
if(x<0.0 || y<0.0)

if ((2*x+2*y)>12.0)
==>
if ((2.0*x+2.0*y)>12.0)

if ((x+2*y)>8.0)
if (4*x>16.0)
类似,试试

  • 打赏
  • 举报
回复
shines77 2004-05-01
if (4*y>12)
==>
if (y>3.0)
  • 打赏
  • 举报
回复
enoloo 2004-05-01
我做个double的测试,比较没问题的。不会影响程序结果。

  • 打赏
  • 举报
回复
zxs790501 2004-05-01
float,double类型的数不能直接与整数比较。
不可以:double d;if(d>16)dosomething();else doanother();
应该这样:double d;if(d-16>0.0001)dosomething();else doanother();
其中0.0001是你希望的精度,可根据情况改变。
另外,不同的机器对float,double类型的数处理时的精度也不同。
  • 打赏
  • 举报
回复
enoloo 2004-05-01
楼主说得不到正确答案,那么正确答案是多少呢?
  • 打赏
  • 举报
回复
coyer 2004-05-01
多谢,楼上两位得邮箱,我已经发送。
  • 打赏
  • 举报
回复
tinyfog 2004-04-30
同意flyelf(空谷清音) 的说法,
精度损失是存在的,但是有没有影响到,你最好把你的算法用到不同系统上试试,看看结果是不是一样。
我原来做过一个十六系数拟合的程序,在其中,当达到10的负7次方以上时,就必须做处理。
  • 打赏
  • 举报
回复
flyelf 2004-04-30
double是有精度,也许在计算的时候会有误差
  • 打赏
  • 举报
回复
enoloo 2004-04-30
1noloo@163.com
  • 打赏
  • 举报
回复
王国凡 2004-04-30
发到这里:
sgnaw@163.com
  • 打赏
  • 举报
回复
相关推荐
发帖
VC/MFC
加入

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
帖子事件
创建了帖子
2004-04-30 10:08
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……