对序列1/n的求和问题

test0231 2011-04-20 04:28:43
我们知道,由于受存储位数的限制,1/n的求和序列(即1/1+1/2+1/3+1/4+……+1/n+……)是收敛的。我写的代码在debug下收敛到15点多,与理论分析是一致的。但在release下结果就变成20多了。请高手指教为什么。
void fun()
//对于float,找到使1/n和式收敛的N
{
long i;
float sum=0.0;
float temp=1;
for(i=1;sum!=temp;i++)
{
temp=sum;
sum+=float(1.0/i);
if(i>=2147483647)//上溢
break;
}
cout<<setprecision(10)<<"求和结果为:"<<sum<<endl;
cout<<"和式的最后一项N= "<<i<<endl;
cout<<"1/N= "<<1.0/i<<endl;

}
...全文
1117 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
fellatioyzx 2011-04-27
  • 打赏
  • 举报
回复 1
不管怎么说,这年头还有用==和!=判断小数的相等,真稀奇
lt114896 2011-04-27
  • 打赏
  • 举报
回复
最近看到一个帖子,这应该是地址优化的问题,release对他的地址优化出现了问题。可以在变量的前面加一个volatile,这样就可以防止这种情况了,楼主可以试试!

void fun()
//对于float,找到使1/n和式收敛的N
{
volatile long i=0L;
volatile float sum=0.0;
volatile float temp=1.0;
for(i=1;sum!=temp;i++)
{
temp=sum;
sum+=float(1.0/i);
if(i>=2147483647)//上溢
break;
}
cout<<"setprecision(10)"<<"求和结果为:"<<sum<<endl;
cout<<"和式的最后一项N= "<<i<<endl;
cout<<"1/N= "<<1.0/i<<endl;
}
Meteor_Code 2011-04-22
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 bukeshuo8 的回复:]
为什么停止条件是10^-8呢?float型数据的精度为7位,而在计算机上,和式算到一个两位数就收敛了(比如你算的是18.997897多),那小数点后第6位,也就是7是不准确的,据此,停止条件应该是5*10^-6啊?不明白,求指教……
[/Quote]
停止条件是任意设的,只要足够小就可以,注意,我的代码是用double测试的
现实出来的18.997897是printf函数的约简值,理论上讲,这个值应该是无限不循环的
如果因为数据宽度问题5*10^-6就已经可以达到所需要的精度,10^-8不是更可以吗?
为什么不写一个可以广泛使用的精度呢?
test0231 2011-04-22
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 meteor_code 的回复:]
可以知道,在debug下,float类型的==和!=比较很可能是用int类型比较的,因为都是4个字节.没有使用浮点数寄存器比较,这个还要看看反汇编的情况
[/Quote]为什么停止条件是10^-8呢?float型数据的精度为7位,而在计算机上,和式算到一个两位数就收敛了(比如你算的是18.997897多),那小数点后第6位,也就是7是不准确的,据此,停止条件应该是5*10^-6啊?不明白,求指教……
Meteor_Code 2011-04-22
  • 打赏
  • 举报
回复
可以知道,在debug下,float类型的==和!=比较很可能是用int类型比较的,因为都是4个字节.没有使用浮点数寄存器比较,这个还要看看反汇编的情况
Meteor_Code 2011-04-22
  • 打赏
  • 举报
回复
使用下面的代码就很明显
FLA_COMPARE宏中的精度不同,结果也不会相同


#include "stdio.h"

#define TEST_TYPE double

#define FLA_COMPARE(a, b) (((a-b)>-0.00000001 && (a-b)<0.00000001) ? 1 : 0)

int main()
{
long i;
TEST_TYPE sum = 0.0;
TEST_TYPE temp = 1.0;

for(i = 1; !FLA_COMPARE(sum, temp) && (i < 0x7fffffff); i++)
{
temp = sum;
sum += float(1.0/i);
}

printf("\r\nsizeof(TEST_TYPE):%d sum:%lf, i:%08x", sizeof(TEST_TYPE), (double)sum, i);
getchar();
return 0;
}
Meteor_Code 2011-04-22
  • 打赏
  • 举报
回复
我的输出,release和debug都是这个
sizeof(TEST_TYPE):8 sum:22.064778, i:7fffffff
和我想的一样,应该就是lz sum!=temp的问题,对于浮点数来说,特别是计算以后,永远不会相等,浮点数比较应该用精度比较法
代码

#include "stdio.h"

#define TEST_TYPE double

int main()
{
long i;
TEST_TYPE sum = 0.0;
TEST_TYPE temp = 1.0;

for(i = 1; sum != temp && (i < 0x7fffffff); i++)
{
temp = sum;
sum += float(1.0/i);
}

printf("\r\nsizeof(TEST_TYPE):%d sum:%lf, i:%08x", sizeof(TEST_TYPE), (double)sum, i);
getchar();
return 0;
}
test0231 2011-04-22
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 meteor_code 的回复:]
在debug和release下
sum!=temp实现可能会不一样,lz输出的i都是多少?
[/Quote]
为什么不一样呢?在debug下,是2万多,在release下,是long型的上限。其实这个程序你也可以自己运行一下的
Meteor_Code 2011-04-22
  • 打赏
  • 举报
回复
在debug和release下
sum!=temp实现可能会不一样,lz输出的i都是多少?
test0231 2011-04-22
  • 打赏
  • 举报
回复
没有满意的回答啊……那个级数不收敛,我知道。我说过了——“由于受存储位数的限制……”。再者,我现在要用float型做一次,用double型做一次,来比较二者的结果。所以有人说用double型,没有解决的问题。而这个我也说过了——“要求用float型、double型的各做一次”。其实我最大的困惑是为什么这个程序在dedbug下与在release下结果不同。请高手解答……
lt114896 2011-04-21
  • 打赏
  • 举报
回复
试了半天,确实不行啊!
無_1024 2011-04-20
  • 打赏
  • 举报
回复
用double 防止精度不够
pathuang68 2011-04-20
  • 打赏
  • 举报
回复
我刚才算了一下,但n = 100的时候,其和为:5.19234。

欧拉常数精确值:0.5772156649...

仅供参考。
pathuang68 2011-04-20
  • 打赏
  • 举报
回复
楼主这个题目,应该可以用Euler constant来解决。
如果没有记错的话,调和级数的和:
1 + 1/2 + 1/3 + ... + 1/n + ... = ln(n + 1) + 欧拉常数。

欧拉常数好像是0.577左右,去查一下就知道了。
pathuang68 2011-04-20
  • 打赏
  • 举报
回复
当n->无穷大时,这个级数看起来好像有极限,其实是没有极限的。
test0231 2011-04-20
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 zhao4zhong1 的回复:]
float改为double
cout...改为printf("1/N=%.15lg\n",1.0/i);
[/Quote]这个不行啊。要求用float型、double型的各做一次。另外,我的那个double型的也有这样的问题。再说了,这跟cout、printf没有关系吧。应该是别的原因啊。
赵4老师 2011-04-20
  • 打赏
  • 举报
回复
float改为double
cout...改为printf("1/N=%.15lg\n",1.0/i);

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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