【问题标题】:Gaussian integral and double division高斯积分和双除法
【发布时间】:2014-08-28 14:37:17
【问题描述】:

为了好玩,我尝试使用级数展开来评估从 0 到 1 的高斯积分。出于这个原因,我写了一个阶乘函数,它在 20 以内都能很好地工作!(我检查过)然后我写了这个:

int main(){
    int n;
    long double result=0;
    for(n=0; n<=5; n++){
        if(n%2==0){
            result+=(((long double) 1/(long double)(factorial(n)*(2*n+1))));
        } else {
            result-=(((long double) 1/(long double)(factorial(n)*(2*n+1))));
        }
    }        
    printf("The Gaussian integral from 0 to 1 is %Lf\n", result);
}

这给了我一个奇怪的负数,显然甚至不接近。我怀疑问题出在演员表上,但我不知道是什么问题。有什么想法吗?这不是我尝试的第一件事。我尝试转换表达式中的任何内容并将显式转换放在开头,但它不起作用。

【问题讨论】:

  • factorial(0) 的结果是什么?
  • 为我工作:ideone.com/VLgnoS
  • 是1,我在写函数的时候就解决了这个问题。
  • 你用的是什么编译器?如果是 MinGW,它不能正确处理 long double
  • 供将来参考:最好在您的帖子中包含“奇怪的负数”中的意外输出和您的预期输出。这两件事有助于解决问题。

标签: c integral


【解决方案1】:

您正在使用 MinGW 编译器(Windows 的 gcc 端口),它与 long double 类型存在问题。这是由于 GCC 的 long double 实现与微软的 C 库之间的冲突。另见this question

根据this question,定义__USE_MINGW_ANSI_STDIO 可以解决这个问题。如果没有,请改用double

【讨论】:

  • 令人印象深刻的演绎壮举。
【解决方案2】:

(long double)(factorial(n)*(2*n+1) 中,乘法是整数乘法,如果factorial 的结果已经接近使用的整数类型的限制,第一个可能会溢出。

写入((long double)(factorial(n))*(2*n+1),使第一个乘法是浮点乘法。

【讨论】:

  • n&lt;=5 在这里,所以它不应该溢出。
  • @interjay 是的。我必须假设问题中显示的代码不完全是溢出的代码。但是,假设一个阶乘函数适用于传递给它的值并返回一些整数类型(问题中未指定),整数乘以2*n+1 是问题中明显的危险信号,并立即转换为浮点是最简单的补救措施。
  • OP 声称“阶乘函数在 20 以内都可以正常工作!”。我对此表示怀疑,因为它甚至会溢出 64 位整数。所以我同意 Pascal - 这不是 SSCCE。所以 +1 答案(即使我的更可爱)。
  • @Bathsheba 20! ~ 2.432902e+18 接近 64 位有符号整数的限制。但是如果factorial 返回一个64 位有符号整数,为什么factorial(5) 会造成任何麻烦?嗯...
  • 关于20!事情:这是一个幼稚的算法,专为没有多少位精度而设计。但是,我检查了 Wolfram 和 20!是正确的。
【解决方案3】:

您几乎肯定会溢出您的整数类型。在 C 中,这在技术上是未定义的行为

对于 32 位无符号整数,13!会溢出。在 64 位上,21!会溢出。

如果您使用浮点 double 类型或像 __uint128 之类的扩展名(我认为最多可以给您 34 个!),如果您的编译器支持,您的算法将存活更长时间。

您遇到的另一个问题是您正在逐步将减少大小的条款添加到您的总数中。在使用浮点类型时,这绝不是一个好主意。如果您以相反的顺序运行for 循环,那么结果会更准确。

【讨论】:

  • 它适用于双精度,尽管精度为 6 位。我怎么能做得更多?
  • 添加到答案中的改进建议
猜你喜欢
  • 2012-02-20
  • 1970-01-01
  • 2015-10-16
  • 2017-04-24
  • 2016-01-12
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多