为什么程序甚至在运行前就结束了?

时间:2019-04-17 18:31:27

标签: c++ numerical-methods arbitrary-precision

我想用这个问题来加深我对计算机工作原理的一般理解,因为我可能永远没有机会以深刻而深刻的方式学习。如果问题很愚蠢并且总体上没有用,请事先抱歉,但是我更喜欢这样学习。

我正在学习c ++,我在网上找到了一个代码,该代码实现了Newton-Raphson方法来查找函数的根。正如您从中可以看到的那样,代码非常简单,一开始它就要求所需的公差,如果我给出一个“不错的”数字,它就可以正常工作。如果相反,当我要求公差时,我写了类似1e-600的程序,程序立即崩溃,输出为Enter starting value x: Failed to converge after 100 iterations

收敛失败的输出应该是循环运行超过100次迭代的结果,但事实并非如此,因为循环甚至没有开始。程序似乎已经知道它不会达到那个公差级别。

为什么会这样?即使程序没有尝试100次循环,程序如何写该输出?

编辑:看来,当我要求容忍的所有无意义的事情(数字,单词太少)产生pnew = 0.25,然后代码运行100次并失败。

代码如下:

#include <iostream>
#include <cmath>
using namespace std;
#define N 100    // Maximum number of iterations


int main() {

    double p, pnew;
    double f, dfdx;
    double tol;
    int i;

    cout << "Enter tolerance: ";
    cin >> tol;
    cout << "Enter starting value x: ";
    cin >> pnew;
    // Main Loop
    for(i=0; i < N; i++){
        p = pnew;
        //Evaluate the function and its derivative
        f = 4*p - cos(p);
        dfdx= 4 + sin(p);
        // The Newton-Raphson step
        pnew = p - f/dfdx;
        // Check for convergence and quit if done
        if(abs(p-pnew) < tol){
            cout << "Root is " << pnew << " to within " << tol << "\n";
            return 0;
        }
    }
    // We reach this point only if the iteration failed to converge
    cerr << "Failed to converge after " << N << " iterations.\n";
    return 1;
}

3 个答案:

答案 0 :(得分:3)

1e-600不能用double的大多数实现来表示。 std::cin将无法将您的输入转换为double并进入失败状态。这意味着,除非您清除错误状态,否则以后的任何std::cin也会自动失败,而无需等待用户输入。

来自cppreference(自c ++ 17起):

  

如果提取失败,则将零写入值并设置failbit。如果提取导致该值太大或太小而无法容纳该值,则写入std::numeric_limits<T>::max()std::numeric_limits<T>::min()并设置failbit标志。

答案 1 :(得分:1)

如上所述,1e-600不是有效的double值。但是,除了超出范围之外,还有其他更多功能。可能发生的情况是先将1扫描到tol,然后将e-600的某些部分扫描到pnew,这就是为什么它立即结束而不是要求输入{{ 1}}。

答案 2 :(得分:0)

就像François所说的那样,当您在64位计算机(具有相应的OS)上工作时,不能超过2 ^ 64;而在32位计算机上,则不能超过2 ^ 32。您可以使用SSE,它们是4个32字节数据,用于浮点表示。在您的程序中,该函数在每次迭代时都会失败,并使用“ if”跳过测试,因此在结束循环之前永远不会返回。