【问题标题】:C++ Finding square root without sqrt function loop glitchingC++ 在没有 sqrt 函数循环故障的情况下查找平方根
【发布时间】:2017-02-16 00:01:37
【问题描述】:

所以我把这个作为家庭作业。我知道有很多方法可以让这段代码更高效、更准确,但这是我的教授希望它完成的方式。

我遇到了循环问题。当我要求 67 的平方根时,它确实找到了它,但它循环正确答案 3 次。

Enter a value to be square rooted: 
67
33.5
guess = 17.75
guess = 10.7623
guess = 8.49387
guess = 8.19096
guess = 8.18535
guess = 8.18535
guess = 8.18535
The program took 7 guess to find an estimation. 

当我试图找到 5 的平方根时,它找到但继续无限循环

using namespace std;

int main()
{
double guess2;
double squarenumber;
double guess1;
int numofguess = 0;

cout << "Enter a value to be square rooted: " << endl;
cin >> squarenumber;
guess1 = squarenumber/2;
cout << guess1 << endl;

do 
{

guess2 = (guess1 - (((guess1 * guess1) - squarenumber)/(2* guess1)));
guess1 = guess2;

cout << "guess = " << guess2 << endl;

numofguess = numofguess + 1;

} while ((guess2 * guess2) > squarenumber);

cout<< "The program took "<< numofguess <<" guess to find an estimation.";

return 0;
}

【问题讨论】:

  • 在调试器中逐行执行代码时,您观察到了什么?
  • 尝试每次循环打印guess2 * guess2。确保以大量的精度打印它。
  • 双精度数包含超过 6 个十进制数字,因此您未显示的数字可能存在差异。查看此帖子Is floating point math broken?
  • 打印精度是这里的问题

标签: c++ loops square-root


【解决方案1】:

我认为您缺少的是正确的退出条件。 您的代码被编写为无限循环,直到猜测“完美”。 您应该有一个退出条件来检查当前猜测是否与之前的猜测相同,这显然意味着您不会做得更好。 这是我根据您的代码提出的建议:

using namespace std;

int main()
{
double guess2;
double squarenumber;
double guess1;
int numofguess = 0;

cout << "Enter a value to be square rooted: " << endl;
cin >> squarenumber;
guess2 = guess1 = squarenumber/2;
cout << guess1 << endl;

const double epsilon = squarenumber * 1E-6;
do 
{
 guess1 = guess2;
guess2 = (guess1 - (((guess1 * guess1) - squarenumber)/(2* guess1)));


cout << "guess = " << guess2 << endl;

numofguess = numofguess + 1;

} while ((guess2 * guess2) > squarenumber && fabs(guess2-guess1) > epsilon);

cout<< "The program took "<< numofguess <<" guess to find an estimation.";

return 0;
}

【讨论】:

  • 这显然不起作用,因为在guess1=guess2; 行之后,fabs(guess2-guess1) 始终为零
  • 你是对的...我编辑了代码来修复这个愚蠢的错误。
  • 我会使用 if (fabs(...)&lt;epsilon) break; ,或者将 guess1=guess2 移动到循环的开头,所以你不需要另一个变量
  • epsilon 需要是squarenumber 的一小部分(squarenumber * 1E-6,取决于您希望根的准确程度),而不是常数。考虑当squarenumber 非常大 (2E30) 或非常小 (5E-20) 时会发生什么。
  • 是的,我没有考虑所有可能值范围内的 epsilon 值...我修复了答案(还考虑了 @user31264 改进以删除不需要的变量)
【解决方案2】:

Mickaël C. Guimarães 的答案基本上是正确的,请检查 Episolon 值(与正确答案和您的答案的绝对差异)。但是“(guess2 *guess2)> squarenumber”应该完全删除。那是因为理论上该值可能会过冲并且太低。如果值太低,算法实际上会向上。例如如果您想要 SQRT(25) 并且您的“guess1”预测在 2 时太低,那么 guess2 将等于

(2 - (((2 * 2) - 25)/(2* 2))) = 7.25;

然后在下一次迭代中下降到 6.725624,所以朝着正确的方向前进。低值实际上得到提升并最终接近目标。如果值低于真正的 SQRT 则停止,那么您可能会得到“误报”,因为太低的值被认为足够准确。

系统“卡住”的时代基本上就像阿基里斯和乌龟的故事一样。在每一步,系统都会将剩余的距离除以一定的量,但每一步的变化因此更小,理论上永远不会收敛到确切的值,因此你决定你想要多少准确度,以便它完成一个固定的时间。

另外,系统收敛的步骤似乎太多的问题是因为浮点数以更高的精度存储,但 cout 的显示精度有限。您可以通过在打印命令之前向 cout 发送设置值来控制它:

std::cout << std::fixed; // force all values to show to the same decimals
std::cout << std::setprecision(6); // set how many places to show

这些代码也可以在要打印的值之前在一个命令中流式传输到 cout:

std::cout << std::fixed << std::setprecision(6) << "guess = " << guess2 << endl;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2023-01-29
    相关资源
    最近更新 更多