Написание вашей собственной функции квадратного корня - PullRequest
68 голосов
/ 26 октября 2009

Как написать собственную функцию для нахождения наиболее точного квадратного корня из целого числа?

После поиска в Google я нашел этот (заархивированный по его исходной ссылке ), но сначала я не получил его полностью, а во-вторых, он также приблизительный. 1007 *

Предполагается, что квадратный корень является ближайшим целым числом (к фактическому корню) или числом с плавающей запятой.

Ответы [ 19 ]

4 голосов
/ 26 октября 2009

Первое, что приходит мне в голову: это хорошее место, чтобы использовать бинарный поиск (вдохновленный этим замечательным учебником .)

Чтобы найти квадратный корень из vaule, мы ищем number в (1..value), где предиктор верно в первый раз. Предсказатель, который мы выбираем: number * number - value > 0.00001.

double square_root_of(double value)
{
     assert(value >= 1);
     double lo = 1.0;
     double hi = value;

     while( hi - lo > 0.00001)
     {
          double mid = lo + (hi - lo) / 2 ;
          std::cout << lo << "," << hi << "," << mid << std::endl;
          if( mid * mid - value > 0.00001)    //this is the predictors we are using 
          {
              hi = mid;
          } else {
              lo = mid;
          }

     }

    return lo;
 }
3 голосов
/ 24 сентября 2013
// Fastest way I found, an (extreme) C# unrolled version of:
// http://www.hackersdelight.org/hdcodetxt/isqrt.c.txt         (isqrt4)

// It's quite a lot of code, basically a binary search (the "if" statements)
// followed by an unrolled loop (the labels).
// Most important: it's fast, twice as fast as "Math.Sqrt".
// On my pc: Math.Sqrt ~35 ns, sqrt <16 ns (mean <14 ns)

private static uint sqrt(uint x)
{
    uint y, z;
    if (x < 1u << 16)
    {
        if (x < 1u << 08)
        {
            if (x < 1u << 04) return x < 1u << 02 ? x + 3u >> 2 : x + 15u >> 3;
            else
            {
                if (x < 1u << 06)
                { y = 1u << 03; x -= 1u << 04; if (x >= 5u << 02) { x -= 5u << 02; y |= 1u << 02; } goto L0; }
                else
                { y = 1u << 05; x -= 1u << 06; if (x >= 5u << 04) { x -= 5u << 04; y |= 1u << 04; } goto L1; }
            }
        }
        else                                             // slower (on my pc): .... y = 3u << 04; } goto L1; }
        {
            if (x < 1u << 12)
            {
                if (x < 1u << 10)
                { y = 1u << 07; x -= 1u << 08; if (x >= 5u << 06) { x -= 5u << 06; y |= 1u << 06; } goto L2; }
                else
                { y = 1u << 09; x -= 1u << 10; if (x >= 5u << 08) { x -= 5u << 08; y |= 1u << 08; } goto L3; }
            }
            else
            {
                if (x < 1u << 14)
                { y = 1u << 11; x -= 1u << 12; if (x >= 5u << 10) { x -= 5u << 10; y |= 1u << 10; } goto L4; }
                else
                { y = 1u << 13; x -= 1u << 14; if (x >= 5u << 12) { x -= 5u << 12; y |= 1u << 12; } goto L5; }
            }
        }
    }
    else
    {
        if (x < 1u << 24)
        {
            if (x < 1u << 20)
            {
                if (x < 1u << 18)
                { y = 1u << 15; x -= 1u << 16; if (x >= 5u << 14) { x -= 5u << 14; y |= 1u << 14; } goto L6; }
                else
                { y = 1u << 17; x -= 1u << 18; if (x >= 5u << 16) { x -= 5u << 16; y |= 1u << 16; } goto L7; }
            }
            else
            {
                if (x < 1u << 22)
                { y = 1u << 19; x -= 1u << 20; if (x >= 5u << 18) { x -= 5u << 18; y |= 1u << 18; } goto L8; }
                else
                { y = 1u << 21; x -= 1u << 22; if (x >= 5u << 20) { x -= 5u << 20; y |= 1u << 20; } goto L9; }
            }
        }
        else
        {
            if (x < 1u << 28)
            {
                if (x < 1u << 26)
                { y = 1u << 23; x -= 1u << 24; if (x >= 5u << 22) { x -= 5u << 22; y |= 1u << 22; } goto La; }
                else
                { y = 1u << 25; x -= 1u << 26; if (x >= 5u << 24) { x -= 5u << 24; y |= 1u << 24; } goto Lb; }
            }
            else
            {
                if (x < 1u << 30)
                { y = 1u << 27; x -= 1u << 28; if (x >= 5u << 26) { x -= 5u << 26; y |= 1u << 26; } goto Lc; }
                else
                { y = 1u << 29; x -= 1u << 30; if (x >= 5u << 28) { x -= 5u << 28; y |= 1u << 28; } }
            }
        }
    }
    z = y | 1u << 26; y /= 2; if (x >= z) { x -= z; y |= 1u << 26; }
Lc: z = y | 1u << 24; y /= 2; if (x >= z) { x -= z; y |= 1u << 24; }
Lb: z = y | 1u << 22; y /= 2; if (x >= z) { x -= z; y |= 1u << 22; }
La: z = y | 1u << 20; y /= 2; if (x >= z) { x -= z; y |= 1u << 20; }
L9: z = y | 1u << 18; y /= 2; if (x >= z) { x -= z; y |= 1u << 18; }
L8: z = y | 1u << 16; y /= 2; if (x >= z) { x -= z; y |= 1u << 16; }
L7: z = y | 1u << 14; y /= 2; if (x >= z) { x -= z; y |= 1u << 14; }
L6: z = y | 1u << 12; y /= 2; if (x >= z) { x -= z; y |= 1u << 12; }
L5: z = y | 1u << 10; y /= 2; if (x >= z) { x -= z; y |= 1u << 10; }
L4: z = y | 1u << 08; y /= 2; if (x >= z) { x -= z; y |= 1u << 08; }
L3: z = y | 1u << 06; y /= 2; if (x >= z) { x -= z; y |= 1u << 06; }
L2: z = y | 1u << 04; y /= 2; if (x >= z) { x -= z; y |= 1u << 04; }
L1: z = y | 1u << 02; y /= 2; if (x >= z) { x -= z; y |= 1u << 02; }
L0: return x > y ? y / 2 | 1u : y / 2;
}
2 голосов
/ 14 июня 2016

использовать бинарный поиск

public class FindSqrt {

    public static void main(String[] strings) {

        int num = 10000;
        System.out.println(sqrt(num, 0, num));
    }

    private static int sqrt(int num, int min, int max) {
        int middle = (min + max) / 2;
        int x = middle * middle;
        if (x == num) {
            return middle;
        } else if (x < num) {
            return sqrt(num, middle, max);
        } else {
            return sqrt(num, min, middle);
        }
    }
}
1 голос
/ 26 октября 2009

Как правило, квадратный корень из целого числа (например, 2) можно только аппроксимировать (не из-за проблем с арифметикой с плавающей запятой, а потому, что это иррациональные числа, которые не могут рассчитано точно).

Конечно, некоторые приближения лучше, чем другие. Я имею в виду, конечно, что значение 1.732 является лучшим приближением к квадратному корню из 3, чем 1.7

Метод, использованный кодом по той ссылке, которую вы дали, работает, беря первое приближение и используя его для вычисления лучшего приближения.

Это называется методом Ньютона, и вы можете повторять вычисления с каждым новым приближением , пока не станет достаточно точным для вас.

На самом деле должен быть каким-то способом решить, когда прекратить повторение, или оно будет работать вечно.

Обычно вы останавливаетесь, когда разница между приближениями составляет меньше, чем значение, которое вы решите.

РЕДАКТИРОВАТЬ: Я не думаю, что может быть более простая реализация, чем две, которые вы уже нашли.

1 голос
/ 02 ноября 2009

Обратное, как следует из названия, но иногда «достаточно близко» - «достаточно близко»; интересно читать в любом случае.

Происхождение быстрого Quake3 InvSqrt ()

0 голосов
/ 11 августа 2016

Ну, есть уже довольно много ответов, но здесь идет мой. Это самый простой кусок кода (для меня), вот алгоритм для него.

И код на python 2.7:

from __future__ import division 
val = 81
x = 10
def sqr(data,x):
    temp = x - ( (x**2 - data)/(2*x))
    if temp == x:
        print temp
        return
    else:
        x = temp
        return sqr(data,x)
    #x =temp 
    #sqr(data,x)
sqr(val,x)
0 голосов
/ 10 апреля 2015

Допустим, мы пытаемся найти квадратный корень из 2, и у вас есть оценка 1,5. Скажем а = 2, а х = 1,5. Чтобы вычислить лучшую оценку, мы разделим a на x. Это дает новое значение у = 1,333333. Однако мы не можем просто принять это как нашу следующую оценку (почему бы и нет). Нам нужно усреднить это с предыдущей оценкой. Таким образом, наша следующая оценка, xx будет (x + y) / 2, или 1.416666.

Double squareRoot(Double a, Double epsilon) {
    Double x = 0d;
    Double y = a;
    Double xx = 0d;

    // Make sure both x and y != 0.
    while ((x != 0d || y != 0d) && y - x > epsilon) {
        xx = (x + y) / 2;

        if (xx * xx >= a) {
            y = xx;
        } else {
            x = xx;
        }
    }

    return xx;
}

Эпсилон определяет, насколько точным должно быть приближение. Функция должна вернуть первое приближение x, которое она получает, удовлетворяющее abs (x * x - a) square_root(2, 1e-6) Output: 1.4142141342163086

0 голосов
/ 25 октября 2013

Для вычисления квадратного корня числа с помощью встроенной функции

# include"iostream.h"
# include"conio.h"
# include"math.h"
void main()
{
clrscr();
float x;
cout<<"Enter the Number";
cin>>x;

 float squreroot(float);  
 float z=squareroot(x);
 cout<<z;


float squareroot(int x)
    {


 float s;
 s = pow(x,.5)  
 return(s);
 }    
0 голосов
/ 27 марта 2014

Простое решение, которое может работать с квадратным корнем с плавающей точкой и произвольной точностью, используя бинарный поиск

в рубине

include Math

def sqroot_precision num, precision
  upper   = num
  lower   = 0
  middle  = (upper + lower)/2.0

  while true do
    diff = middle**2 - num

    return middle if diff.abs <= precision

    if diff > 0
      upper = middle
    else diff < 0
      lower = middle
    end

    middle = (upper + lower)/2.0
  end 
end

puts sqroot_precision 232.3, 0.0000000001
...