平方根函数是如何实现的?

时间:2010-08-27 05:25:51

标签: function math square-root

如何实现平方根功能?

16 个答案:

答案 0 :(得分:32)

来源here

问题陈述:给定x> 0,找到y使得y ^ 2 = x => y = x / y(这是关键步骤)。

  1. 猜y的某些值g并测试它。
  2. 计算x / g。
  3. 如果x / g足够接近g,则返回g。否则,请尝试更好的猜测。
  4. double test(double x, double g) {
       if closeEnough(x/g, g)
          return g;
       else
          return test(x, betterGuess(x, g));
    }
    
    boolean closeEnough(double a, double b) {
       return (Math.abs(a - b) < .001);
    }
    
    double betterGuess(double x, double g) {
       return ((g + x/g) / 2);
    }
    

    sqrt(2)         | Guess g  x / g               | New guess, (g + x / g) / 2
    ----------------|------------------------------|-------------------------------
    test(2, 1)      | 1        2 / 1      = 2      | (2      +      1) / 2 = 1.5
    test(2, 1.5)    | 1.5      2 / 1.5    = 1.3333 | (1.3333 +    1.5) / 2 = 1.4167
    test(2, 1.4167) | 1.4167   2 / 1.4167 = 1.4118 | (1.4167 + 1.4118) / 2 = 1.4142
    test(2, 1.4142) | 1.4142   ...                 | ...
    

答案 1 :(得分:10)

使用Binary Search和C ++进行简单实现

double root(double n){
  double lo = 0, hi = n, mid;
  for(int i = 0 ; i < 1000 ; i++){
      mid = (lo+hi)/2;
      if(mid*mid == n) return mid;
      if(mid*mid > n) hi = mid;
      else lo = mid;
  }
  return mid;
}

请注意,while循环在二进制搜索中最常见,但我个人更喜欢在处理十进制数时使用for,它可以节省一些特殊情况处理并从小循环中获得非常准确的结果1000甚至500(两者都会为几乎所有数字提供相同的结果,但只是为了安全)。

修改:查看此Wikipedia article了解各种专门用于计算平方根的方法。

答案 2 :(得分:6)

在Intel硬件上,它通常在硬件SQRT指令之上实现。有些图书馆只是直接使用结果,有些图书馆可能会通过几轮牛顿优化来使其在角落情况下更准确。

答案 3 :(得分:4)

FDLIBM(可自由分发的LIBM)有一个非常好的文档版本的sqrt。 e_sqrt.c

有一个版本使用整数运算和一次修改一位的递推公式。

另一种方法使用牛顿方法。它从一些黑魔法和一个查找表开始,得到前8位,然后应用递推公式

 y_{i+1} = 1/2 * ( y_i + x / y_i)

其中x是我们开始的数字。这是Heron方法的Babylonian method。它可以追溯到公元一世纪的亚历山德拉英雄。

还有另一种称为Fast inverse square root或reciproot的方法。它使用一些“邪恶的浮点位黑客”来找到1 / sqrt(x)的值。 i = 0x5f3759df - ( i >> 1 );它使用mantisse和exponent来利用float的二进制表示。如果我们的数字x是(1 + m)* 2 ^ e,其中m是尾数,e是指数,结果y = 1 / sqrt(x)=(1 + n)* 2 ^ f。记录日志

lg(y) = - 1/2 lg(x)
f + lg(1+n) = -1/2 e - 1/2 lg(1+m)

因此我们看到结果的指数部分是-1/2数字的指数。黑魔法基本上对指数进行逐位移位,并在尾数上使用线性近似。

一旦你有了一个好的第一次近似,你可以使用牛顿的方法来获得更好的结果,最后用一些比特级别来修复最后一个数字。

答案 4 :(得分:2)

这是Newton算法的实现,请参阅https://tour.golang.org/flowcontrol/8

int:  s   ==> Size
int:  w   ==> Width
bool: c   ==> Crop
hex:  c   ==> BorderColor
bool: d   ==> Download
int:  h   ==> Height
bool: s   ==> Stretch
bool: h   ==> Html
bool: p   ==> SmartCrop
bool: pa  ==> PreserveAspectRatio
bool: pd  ==> Pad
bool: pp  ==> SmartCropNoClip
bool: pf  ==> SmartCropUseFace
int:  p   ==> FocalPlane
bool: n   ==> CenterCrop
int:  r   ==> Rotate
bool: r   ==> SkipRefererCheck
bool: fh  ==> HorizontalFlip
bool: fv  ==> VerticalFlip
bool: cc  ==> CircleCrop
bool: ci  ==> ImageCrop
bool: o   ==> Overlay
str:  o   ==> EncodedObjectId
str:  j   ==> EncodedFrameId
int:  x   ==> TileX
int:  y   ==> TileY
int:  z   ==> TileZoom
bool: g   ==> TileGeneration
bool: fg  ==> ForceTileGeneration
bool: ft  ==> ForceTransformation
int:  e   ==> ExpirationTime
str:  f   ==> ImageFilter
bool: k   ==> KillAnimation
int:  k   ==> FocusBlur
bool: u   ==> Unfiltered
bool: ut  ==> UnfilteredWithTransforms
bool: i   ==> IncludeMetadata
bool: ip  ==> IncludePublicMetadata
bool: a   ==> EsPortraitApprovedOnly
int:  a   ==> SelectFrameint
int:  m   ==> VideoFormat
int:  vb  ==> VideoBegin
int:  vl  ==> VideoLength
bool: lf  ==> LooseFaceCrop
bool: mv  ==> MatchVersion
bool: id  ==> ImageDigest
int:  ic  ==> InternalClient
bool: b   ==> BypassTakedown
int:  b   ==> BorderSize
str:  t   ==> Token
str:  nt0 ==> VersionedToken
bool: rw  ==> RequestWebp
bool: rwu ==> RequestWebpUnlessMaybeTransparent
bool: rwa ==> RequestAnimatedWebp
bool: nw  ==> NoWebp
bool: rh  ==> RequestH264
bool: nc  ==> NoCorrectExifOrientation
bool: nd  ==> NoDefaultImage
bool: no  ==> NoOverlay
str:  q   ==> QueryString
bool: ns  ==> NoSilhouette
int:  l   ==> QualityLevel
int:  v   ==> QualityBucket
bool: nu  ==> NoUpscale
bool: rj  ==> RequestJpeg
bool: rp  ==> RequestPng
bool: rg  ==> RequestGif
bool: pg  ==> TilePyramidAsProto
bool: mo  ==> Monogram
bool: al  ==> Autoloop
int:  iv  ==> ImageVersion
int:  pi  ==> PitchDegrees
int:  ya  ==> YawDegrees
int:  ro  ==> RollDegrees
int:  fo  ==> FovDegrees
bool: df  ==> DetectFaces
str:  mm  ==> VideoMultiFormat
bool: sg  ==> StripGoogleData
bool: gd  ==> PreserveGoogleData
bool: fm  ==> ForceMonogram
int:  ba  ==> Badge
int:  br  ==> BorderRadius
hex:  bc  ==> BackgroundColor
hex:  pc  ==> PadColor
hex:  sc  ==> SubstitutionColor
bool: dv  ==> DownloadVideo
bool: md  ==> MonogramDogfood
int:  cp  ==> ColorProfile
bool: sm  ==> StripMetadata
int:  cv  ==> FaceCropVersion

以下是魔术线的数学解释。假设您要查找多项式的根$ f(x)= x ^ 2 - a $。通过Newton的方法,您可以从初始猜测$ x_0 = 1 $开始。下一个猜测是$ x_1 = x_0 - f(x_0)/ f'(x_0)$,其中$ f'(x)= 2x $。因此,您的新猜测是

$ x_1 = x_0 - (x_0 ^ 2 - a)/ 2x_0 $

答案 5 :(得分:1)

SQRT();功能在幕后。

它始终检查图表中的中点。示例:sqrt(16)= 4; SQRT(4)= 2;

现在,如果您在16或4之内提供任何输入,例如sqrt(10)==?

它找到2和4的中点,即= x,然后再次找到x和4的中点(它排除了此输入中的下限)。它一次又一次地重复这个步骤,直到它得到完美答案,即sqrt(10)== 3.16227766017。它位于b / w 2和4.所有这个内置函数都是使用微积分,微分和积分创建的。

答案 6 :(得分:1)

Python实现: 根值的下限是此函数的输出。 示例:8的平方根是2.82842 ...,此函数将给出输出'2'

def mySqrt(x):
        # return int(math.sqrt(x))
        if x==0 or x==1:
            return x
        else:
            start = 0
            end = x  
            while (start <= end):
                mid = int((start + end) / 2)
                if (mid*mid == x):
                    return mid
                elif (mid*mid < x):
                    start = mid + 1
                    ans = mid
                else:
                    end = mid - 1
            return ans

答案 7 :(得分:1)

Formula: root(number, <root>, <depth>) == number^(root^(-depth))

Usage: root(number,<root>,<depth>)

Example: root(16,2) == sqrt(16) == 4
Example: root(16,2,2) == sqrt(sqrt(16)) == 2
Example: root(64,3) == 4

Implementation in C#:

static double root(double number, double root = 2f, double depth = 1f)
{
    return Math.Pow(number, Math.Pow(root, -depth));
}

答案 8 :(得分:1)

到目前为止,解决方案主要是浮点运算……并且还假定除法指令可用且快速。

这是一个简单的简单例程,不使用FP或除法。除了第一个if语句可在输入较小时加快例程运行速度之外,每一行都会在结果中另外计算一位。

constexpr unsigned int root(unsigned int x) {
  unsigned int i = 0;
  if (x >= 65536) {
    if ((i + 32768) * (i + 32768) <= x) i += 32768;
    if ((i + 16384) * (i + 16384) <= x) i += 16384;
    if ((i + 8192) * (i + 8192) <= x) i += 8192;
    if ((i + 4096) * (i + 4096) <= x) i += 4096;
    if ((i + 2048) * (i + 2048) <= x) i += 2048;
    if ((i + 1024) * (i + 1024) <= x) i += 1024;
    if ((i + 512) * (i + 512) <= x) i += 512;
    if ((i + 256) * (i + 256) <= x) i += 256;
  }
  if ((i + 128) * (i + 128) <= x) i += 128;
  if ((i + 64) * (i + 64) <= x) i += 64;
  if ((i + 32) * (i + 32) <= x) i += 32;
  if ((i + 16) * (i + 16) <= x) i += 16;
  if ((i + 8) * (i + 8) <= x) i += 8;
  if ((i + 4) * (i + 4) <= x) i += 4;
  if ((i + 2) * (i + 2) <= x) i += 2;
  if ((i + 1) * (i + 1) <= x) i += 1;
  return i;
}

答案 9 :(得分:0)

计算平方根(不使用内置的math.sqrt函数):

<强> SquareRootFunction.java

public class SquareRootFunction {

    public double squareRoot(double value,int decimalPoints)
    {
        int firstPart=0;


        /*calculating the integer part*/
        while(square(firstPart)<value)
        {
            firstPart++;            
        }

        if(square(firstPart)==value)
            return firstPart;
        firstPart--;

        /*calculating the decimal values*/
        double precisionVal=0.1;
        double[] decimalValues=new double[decimalPoints];
        double secondPart=0;

        for(int i=0;i<decimalPoints;i++)
        {
            while(square(firstPart+secondPart+decimalValues[i])<value)
            {
                decimalValues[i]+=precisionVal;
            }

            if(square(firstPart+secondPart+decimalValues[i])==value)
            {
                return (firstPart+secondPart+decimalValues[i]);
            }

            decimalValues[i]-=precisionVal;
            secondPart+=decimalValues[i];
            precisionVal*=0.1;
        }

        return(firstPart+secondPart);

    }


    public double square(double val)
    {
        return val*val;
    }

}

<强> MainApp.java

import java.util.Scanner;

public class MainApp {

public static void main(String[] args) {

    double number;
    double result;
    int decimalPoints;
    Scanner in = new Scanner(System.in);

    SquareRootFunction sqrt=new SquareRootFunction();   
    System.out.println("Enter the number\n");               
    number=in.nextFloat();  

    System.out.println("Enter the decimal points\n");           
    decimalPoints=in.nextInt();

    result=sqrt.squareRoot(number,decimalPoints);

    System.out.println("The square root value is "+ result);

    in.close();

    }

}

答案 10 :(得分:0)

long long int floorSqrt(long long int x) 
{
    long long r = 0;
    while((long)(1<<r)*(long)(1<<r) <= x){
        r++;
    }
    r--;
    long long b = r -1;
    long long ans = 1 << r;
    while(b >= 0){
        if(((long)(ans|1<<b)*(long)(ans|1<<b))<=x){
            ans |= (1<<b);
        }
        b--;
    }
    return ans;
}

答案 11 :(得分:0)

有些东西叫做巴比伦方法。

static float squareRoot(float n)
{

    /*We are using n itself as 
    initial approximation This 
    can definitely be improved */
    float x = n;
    float y = 1;

    // e decides the accuracy level
    double e = 0.000001;
    while(x - y > e)
    {
        x = (x + y)/2;
        y = n/x;
    }
    return x;
}

有关更多信息的链接:https://www.geeksforgeeks.org/square-root-of-a-perfect-square/

答案 12 :(得分:0)

因此,如果没有关于是否使用内置ceil或round函数的规范,这是Java中的一种递归方法,它使用Newton-Raphson方法来查找无符号数的平方根。 / p>

public class FindSquareRoot {

    private static double newtonRaphson(double N, double X, double oldX) {

        if(N <= 0) return 0;

        if (Math.round(X) == Math.ceil(oldX))
            return X;

        return newtonRaphson(N, X - ((X * X) - N)/(2 * X), X);
    }

    //Driver method
    public static void main (String[] args) {
        System.out.println("Square root of 48.8: " + newtonRaphson(48.8, 10, 0));
    }
}

答案 13 :(得分:0)

我也在做一个sqrt函数,100000000次迭代需要14秒,与sqrt的1秒相比还是没什么

double mysqrt(double n)
{
    double x = n;
    int it = 4;
    if (n >= 90)
    {
        it = 6;
    }
    if (n >= 5000)
    {
        it = 8;
    }
    if (n >= 20000)
    {
        it = 10;
    }
    if (n >= 90000)
    {
        it = 11;
    }
    if (n >= 200000)
    {
        it = 12;
    }
    if (n >= 900000)
    {
        it = 13;
    }
    if (n >= 3000000)
    {
        it = 14;
    }
    if (n >= 10000000)
    {
        it = 15;
    }
    if (n >= 30000000)
    {
        it = 16;
    }
    if (n >= 100000000)
    {
        it = 17;
    }

    if (n >= 300000000)
    {
        it = 18;
    }
    if (n >= 1000000000)
    {
        it = 19;
    }

    for (int i = 0; i < it; i++)
    {
        x = 0.5*(x+n/x);
    }
    return x;
}

但是最快的实现是:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the fuck?
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

float mysqrt(float n) {return 1/Q_rsqrt(n);}

答案 14 :(得分:0)

在Golang中解决我的问题。

package main

import (
   "fmt"
)

func Sqrt(x float64) float64 {
   z := 1.0 // initial guess to be 1
   i := 0
   for int(z*z) != int(x) { // until find the first approximation
      // Newton root algorithm
      z -= (z*z - x) / (2 * z)
      i++
   }
   return z
}

func main() {
   fmt.Println(Sqrt(8900009870))
}

遵循经典/通用解决方案。

package main

import (
"fmt"
"math"
)

func Sqrt(num float64) float64 {
   const DIFF = 0.0001 // To fix the precision
   z := 1.0

   for {
      z1 := z - (((z * z) - num) / (2 * z))
      // Return a result when the diff between the last execution 
      // and the current one is lass than the precision constant
      if (math.Abs(z1 - z) < DIFF) {
         break
      }
      z = z1
   }

   return z
}


func main() {
   fmt.Println(Sqrt(94339))
}

有关更多信息,请检查here

答案 15 :(得分:-1)

用法:root(数字,root,深度)

示例:root(16,2)== sqrt(16)== 4
示例:root(16,2,2)== sqrt(sqrt(16))== 2
示例:root(64,3)== 4

在C#中的实现

double root(double number, double root, double depth = 1f)
{
    return number ^ (root ^ (-depth));
}

用法:Sqrt(数字,深度)

示例:Sqrt(16)== 4
示例:Sqrt(8,2)== sqrt(sqrt(8))

double Sqrt(double number, double depth = 1) return root(number,2,depth);

通过: Imk0tter