繁体   English   中英

C - 平方根函数无法正常工作

[英]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...

似乎approx2approx1更接近实际值。 在大多数情况下,它们是相当等价的。

我使用这个网站进行转换,使用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)也是如此。

编辑 2

浮点数学真的很难 您的函数针对某些输入进入无限循环。 尝试例如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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM