[英]C - Square root function not working properly
我编写了一个名为“mysqrt(double r)”的函数来计算“r”的平方根。 但是,结果与 math.h 库中的标准 sqrt() 函数给出的结果不同。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double mysqrt (double r);
int main()
{
double r1, r2;
r1 = sqrt (2.0);
r2 = mysqrt (2.0);
if (r1 == r2)
{
printf ("OK! Result = %.40lf\n", r1);
}
else
{
printf ("!? r1 = %.40lf, r2 = %.40lf\n", r1, r2);
}
return EXIT_SUCCESS;
}
double mysqrt (double r)
{
double n1, n2;
n1 = r;
n2 = 1.0;
while (n1 - n2 > 0)
{
n1 = (n1 + n2) / 2.0;
n2 = r / n1;
}
return n1;
}
输出是: ?. r1 = 1,4142135623730951454746218587388284504414. r2 = 1.4142135623730949234300169337075203657150
?. r1 = 1,4142135623730951454746218587388284504414. r2 = 1.4142135623730949234300169337075203657150
我试过将类型从 double 更改为 long double,但没有用。
您想要使用 IEEE-754 二进制 64 表示来近似无理数sqrt(2)
。 你有两种可能性:
approx1 double: 0 01111111111 0110101000001001111001100110011111110011101111001100
approx2 double: 0 01111111111 0110101000001001111001100110011111110011101111001101
这些数字是多少? 让我们将它们转换回十进制:
approx1 (exact): 1.41421356237309492343001693370752036571502685546875
sqrt(2) : 1.4142135623730950488016887242096980785696718753769480731766797379...
approx2 (exact): 1.4142135623730951454746218587388284504413604736328125
他们都非常接近。 事实上,它们是您可以使用 binary64 获得的最接近的两个数字。 哪个更好?
abs(sqrt(2)-approx1): 0.0000000000000001253716717905021777128546450199081980731766797379...
abs(sqrt(2)-approx2): 0.0000000000000000966729331345291303718716885982558644268233202620...
似乎approx2
比approx1
更接近实际值。 在大多数情况下,它们是相当等价的。
我使用这个网站进行转换,使用WolframAlpha进行比较。
浮点数学很难。 注意这一点:
int main(void)
{
double r1, r2;
r1 = sqrt (2.0);
r2 = mysqrt (2.0);
printf ("sqrt(2):\nr1 = %.40lf\nr2 = %.40lf\n", r1, r2);
r1 *= r1;
r2 *= r2;
printf ("Square them:\nr1 = %.40lf\nr2 = %.40lf\n", r1, r2);
r1 = fabs(r1 - 2.0);
r2 = fabs(r2 - 2.0);
printf ("Subtract 2 (abs):\nr1 = %.40lf\nr2 = %.40lf\n", r1, r2);
return EXIT_SUCCESS;
}
输出是:
sqrt(2):
r1 = 1.4142135623730951454746218587388284504414
r2 = 1.4142135623730949234300169337075203657150
Square them:
r1 = 2.0000000000000004440892098500626161694527
r2 = 1.9999999999999995559107901499373838305473
Subtract 2 (abs):
r1 = 0.0000000000000004440892098500626161694527
r2 = 0.0000000000000004440892098500626161694527
因此, sqrt(2)
的两个近似值的平方版本与 2 的距离相等。例如,对于sqrt(8)
也是如此。
浮点数学真的很难。 您的函数针对某些输入进入无限循环。 尝试例如7.0
。 您可以按如下方式修复它:
double mysqrt(double r)
{
double n1 = r;
double n2 = 1.0;
double old = n2;
while (old != n1 && n1 - n2 > 0) {
old = n1;
n1 = (n1 + n2) / 2.0;
n2 = r / n1;
}
return n1;
}
我像这样重写了mysqrt函数:
double mysqrt (double r)
{
double n1, n2;
n1 = r;
n2 = 1.0;
while (absolute_value(n1 - n2) > EPSILON)
{
n1 = (n1 + n2) / (double) 2;
n2 = r / n1;
}
return n1;
}
double absolute_value (double n)
{
if (n < 0)
{
n *= -1;
}
return n;
}
和
#define EPSILON 1e-15
通过这样做,输出变为:
OK. Result = 1.4142135623730951454746218587388284504414
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.