我想用这个问题来改进我对计算机工作原理的一般理解,因为我可能永远都没有机会深入而深刻地学习。提前抱歉,如果这个问题很愚蠢,一般没用,但我更喜欢这样学习。
我正在学习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;
}
1e-600
不能代表大多数double
的实现。 std::cin
将无法将您的输入转换为double
并陷入失败状态。这意味着,除非您清除错误状态,否则任何未来的std::cin
也会在不等待用户输入的情况下自动失败。
来自cppreference(自c ++ 17以来):
如果提取失败,则将零写入值并设置
failbit
。如果提取导致值太大或太小而无法拟合值,则会写入std::numeric_limits<T>::max()
或std::numeric_limits<T>::min()
并设置failbit
标志。
如上所述,1e-600
不是有效的double
值。但是,除了超出范围之外,还有更多内容。可能发生的是1扫描到tol
,然后e-600
的一部分被扫描到pnew
,这就是为什么它立即结束,而不是要求输入pnew
。
就像François所说的那样,当你使用64位机器(具有相应的操作系统)和32位机器上的2 ^ 32时,你不能执行2 ^ 64,你可以使用SSE,这是用于浮点表示的4个32字节数据。在你的程序中,函数在每次迭代时都会失败并用“if”跳过你的测试,因此在结束循环之前永远不会返回。