簡體   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