首页 文章

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

提问于
浏览
16

我发现了不使用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的值 . 请为此提供解决方案 .

10 回答

  • 5

    为什么不尝试使用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;
    }
    

    祝好运!

  • 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) 大约相同的金额 . 换句话说,它会很快收敛 .

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

  • -1

    完全删除你的 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;
    }
    

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

  • 1
    //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);
    }
    
  • 2

    这是一个非常棒的代码来查找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;
    }
    
  • 0

    在查看之前的回复之后,我希望这有助于解决任何含糊之处 . 如果以前的解决方案和我的解决方案中的相似之处是虚幻的,或者这种解决根的方法还不清楚,我还做了一个可以找到的图表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)))));
    }
    

    Explanation

    click here for graph

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

    举个例子:

    log A = N
       x
    

    *Note :对于平方根,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] + . . .
    

    *Note :继续系列以提高准确性 . 为简洁起见,在我的函数中使用了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))));
    }
    

相关问题