在不使用sqrt函数的情况下查找平方根?

问题描述 投票:16回答:10

我发现了不使用sqrt函数找出平方根的算法,然后尝试进入编程。我最终使用C ++中的这个工作代码

    #include <iostream>
    using namespace std;

    double SqrtNumber(double num)
    {
             double lower_bound=0; 
             double upper_bound=num;
             double temp=0;                    /* ek edited this line */

             int nCount = 50;

        while(nCount != 0)
        {
               temp=(lower_bound+upper_bound)/2;
               if(temp*temp==num) 
               {
                       return temp;
               }
               else if(temp*temp > num)

               {
                       upper_bound = temp;
               }
               else
               {
                       lower_bound = temp;
               }
        nCount--;
     }
        return temp;
     }

     int main()
     {
     double num;
     cout<<"Enter the number\n";
     cin>>num;

     if(num < 0)
     {
     cout<<"Error: Negative number!";
     return 0;
     }

     cout<<"Square roots are: +"<<sqrtnum(num) and <<" and -"<<sqrtnum(num);
     return 0;
     } 

现在问题是初始化声明中的迭代次数nCount(这里是50)。例如,为了找出36的平方根,它需要22次迭代,所以没有问题,而找到15625的平方根需要超过50次迭代,所以它会在50次迭代后返回temp的值。请为此提供解决方案。

c++ algorithm math sqrt
10个回答
33
投票

有一个更好的算法,最多需要6次迭代才能收敛到双倍数的最大精度:

#include <math.h>

double sqrt(double x) {
    if (x <= 0)
        return 0;       // if negative number throw an exception?
    int exp = 0;
    x = frexp(x, &exp); // extract binary exponent from x
    if (exp & 1) {      // we want exponent to be even
        exp--;
        x *= 2;
    }
    double y = (1+x)/2; // first approximation
    double z = 0;
    while (y != z) {    // yes, we CAN compare doubles here!
        z = y;
        y = (y + x/y) / 2;
    }
    return ldexp(y, exp/2); // multiply answer by 2^(exp/2)
}

算法从1开始作为平方根值的第一近似值。然后,在每一步,它通过取当前值yx/y之间的平均值来改进下一近似。如果y = sqrt(x),它将是相同的。如果y> sqrt(x),那么x/y <sqrt(x)大约相同的数量。换句话说,它会很快收敛。

更新:为了加速非常大或非常小的数字的收敛,更改sqrt()函数以提取二进制指数并从[1, 4)范围中的数字计算平方根。它现在需要来自frexp()<math.h>来获得二进制指数,但是可以通过从IEEE-754数字格式中提取位而不使用frexp()来获得该指数。


-1
投票

在查看之前的回复之后,我希望这有助于解决任何含糊之处。如果以前的解决方案和我的解决方案中的相似之处是虚幻的,或者这种解决根的方法还不清楚,我还做了一个图表,可以找到here

这是一个能够解决任何第n个根的工作根函数

(为了这个问题,默认是平方根)

#include <cmath> 
// for "pow" function

double sqrt(double A, double root = 2) {
    const double e = 2.71828182846;
    return pow(e,(pow(10.0,9.0)/root)*(1.0-(pow(A,-pow(10.0,-9.0)))));
}

说明:

click here for graph

这通过泰勒级数,对数性质和一些代数来工作。

举个例子:

log A = N
   x

*注意:对于平方根,N = 2;对于任何其他根,您只需要更改一个变量N.

1)更改基数,将基本'x'日志函数转换为自然日志,

log A   =>   ln(A)/ln(x) = N
   x

2)重新排列以隔离ln(x),最后只是'x',

ln(A)/N = ln(x)

3)将两边都设为'e'的指数,

e^(ln(A)/N) = e^(ln(x))  >~{ e^ln(x) == x }~>  e^(ln(A)/N) = x

4)泰勒系列将“ln”表示为无限级数,

ln(x) = (k=1)Sigma: (1/k)(-1^(k+1))(k-1)^n

           <~~~ expanded ~~~>

[(x-1)] - [(1/2)(x-1)^2] + [(1/3)(x-1)^3] - [(1/4)(x-1)^4] + . . .

*注意:继续系列以提高准确性。为简洁起见,在我的函数中使用了10 ^ 9,它表示自然对数的系列收敛,大约7位数,或者千万位数,用于精度,

ln(x) = 10^9(1-x^(-10^(-9)))

5)现在,只需插入此公式即可自然登录到步骤3中获得的简化方程式。

e^[((10^9)/N)(1-A^(-10^-9)] = nth-root of (A)

6)这种实施可能看起来有点过分;然而,它的目的是展示如何在不必猜测和检查的情况下解决根。此外,它将使您能够使用自己的pow函数替换cmath库中的pow函数:

double power(double base, double exponent) {
    if (exponent == 0) return 1;
    int wholeInt = (int)exponent;
    double decimal = exponent - (double)wholeInt;
    if (decimal) {
        int powerInv = 1/decimal;
        if (!wholeInt) return root(base,powerInv);
        else return power(root(base,powerInv),wholeInt,true);
    }
    return power(base, exponent, true);
}

double power(double base, int exponent, bool flag) {
    if (exponent < 0) return 1/power(base,-exponent,true);
    if (exponent > 0) return base * power(base,exponent-1,true);
    else return 1;
}

int root(int A, int root) {
    return power(E,(1000000000000/root)*(1-(power(A,-0.000000000001))));
}

6
投票

为什么不尝试使用Babylonian method来寻找平方根。

这是我的代码:

double sqrt(double number)
{
    double error = 0.00001; //define the precision of your result
    double s = number;

    while ((s - number / s) > error) //loop until precision satisfied 
    {
        s = (s + number / s) / 2;
    }
    return s;
}

祝好运!


2
投票

完全删除你的nCount(因为有一些根源,这个算法将需要多次迭代)。

double SqrtNumber(double num)
{
    double lower_bound=0; 
    double upper_bound=num;
    double temp=0;

    while(fabs(num - (temp * temp)) > SOME_SMALL_VALUE)
    {
           temp = (lower_bound+upper_bound)/2;
           if (temp*temp >= num)
           {
                   upper_bound = temp;
           }
           else
           {
                   lower_bound = temp;
           }
    }
    return temp;
 }

1
投票

如果你需要在不使用sqrt()的情况下找到平方根,请使用root=pow(x,0.5)

其中x是您需要找到的平方根的值。


1
投票

我发现这个问题很老,有很多答案,但我的答案很简单,效果很好..

#define EPSILON 0.0000001 // least minimum value for comparison
double SquareRoot(double _val) {
    double low = 0; 
    double high = _val;
    double mid = 0; 

    while (high - low > EPSILON) {
            mid = low + (high - low) / 2; // finding mid value
            if (mid*mid > _val) {
                high = mid;
            } else {
                low = mid;
            }    
    }   
    return mid;
}

我希望它对未来的用户有所帮助。


0
投票
//long division method.
#include<iostream>
using namespace std;
int main() {
int n, i = 1, divisor, dividend, j = 1, digit;
cin >> n;
while (i * i < n) {
    i = i + 1;
}
i = i - 1;
cout << i << '.';

divisor  = 2 * i;
dividend = n - (i * i );
while( j <= 5) {
    dividend = dividend * 100;
    digit = 0;
    while ((divisor * 10 + digit) * digit < dividend) {
        digit = digit + 1;
    }
    digit = digit  - 1;
    cout << digit;
    dividend = dividend - ((divisor * 10 + digit) * digit);
    divisor = divisor * 10 + 2*digit;
    j = j + 1;
}
cout << endl;
return 0;
}

0
投票

这是一种非常简单但不安全的方法来查找数字的平方根。不安全,因为它只能通过自然数来运行,你知道基数和指数都是自然数。我不得不将它用于我不允许使用#include <cmath> -library的任务,也不允许我使用指针。

效力=基数^指数

// FUNCTION: square-root
int sqrt(int x)
{
    int quotient = 0;
    int i = 0;

    bool resultfound = false;
    while (resultfound == false) {
        if (i*i == x) {
          quotient = i;
          resultfound = true;
        }
        i++;
    }
    return quotient;
}

0
投票

这是一种非常简单的递归方法。

double mySqrt(double v, double test) {
    if (abs(test * test - v) < 0.0001) {
        return test;
    }

    double highOrLow = v / test;
    return mySqrt(v, (test + highOrLow) / 2.0);
}
double mySqrt(double v) {
    return mySqrt(v, v/2.0);
}

-1
投票

这是一个非常棒的代码来查找sqrt甚至比原始sqrt函数更快。

float InvSqrt (float x) 
{
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f375a86 - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f - xhalf*x*x);
    x = x*(1.5f - xhalf*x*x);
    x = x*(1.5f - xhalf*x*x);
    x=1/x;
    return x;
}
© www.soinside.com 2019 - 2024. All rights reserved.