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