我想用这个问题来加深我对计算机工作原理的一般理解,因为我可能永远没有机会以深刻而深刻的方式学习。如果问题很愚蠢并且总体上没有用,请事先抱歉,但是我更喜欢这样学习。
我正在学习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;
}
答案 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”跳过测试,因此在结束循环之前永远不会返回。