Những kỹ thuật gần đúng tồn tại để tính toán căn bậc hai?


12

Tôi có nguồn lực rất hạn chế khi tôi làm việc với một vi điều khiển. Có mở rộng sê-ri taylor, bảng tra cứu chung hoặc phương pháp đệ quy không?

Tôi muốn làm một cái gì đó mà không cần sử dụng math.h's sqrt ()

http://www.cplusplus.com/reference/cmath/sqrt/


5
Kiểm tra liên kết này: codeproject.com/Articles/69941/ Kiếm
Matt L.

1
Ngoại trừ thực tế đó là câu hỏi lập trình nhiều hơn, tại sao không biến nó thành câu trả lời Matt?
jojek

Đầu vào điểm nổi hoặc điểm cố định? Đối với điểm cố định, phương pháp lặp có thể thích hợp hơn, nhưng tôi sẽ không bận tâm giải thích nó trừ khi bạn thực sự muốn nó.
Oscar

@Oscar, tôi rất thích tìm hiểu phương pháp điểm cố định vì tôi cố gắng không yêu cầu sử dụng float trong firmware của mình :).
tarabyte

Câu trả lời:


13

nếu bạn muốn mở rộng chuỗi năng lượng được tối ưu hóa rẻ và bẩn (hệ số cho chuỗi Taylor hội tụ chậm) sqrt()và một loạt các trancendentals khác, tôi đã có một số mã từ lâu. tôi đã từng bán mã này, nhưng không ai trả tiền cho tôi trong gần một thập kỷ. Vì vậy, tôi nghĩ rằng tôi sẽ phát hành nó cho tiêu dùng công cộng. tệp đặc biệt này là dành cho một ứng dụng trong đó bộ xử lý có dấu phẩy động (độ chính xác đơn IEEE-754) và chúng có trình biên dịch C và hệ thống dev, nhưng chúng khôngcó (hoặc họ không muốn liên kết) stdlib sẽ có các hàm toán học tiêu chuẩn. họ không cần độ chính xác hoàn hảo, nhưng họ muốn mọi thứ phải nhanh chóng. bạn có thể dễ dàng đảo ngược mã để xem hệ số chuỗi lũy thừa là gì và viết mã của riêng bạn. mã này giả định IEEE-754 và che dấu các bit cho mantissa và số mũ.

có vẻ như "mã đánh dấu" mà SE có không thân thiện với các ký tự góc (bạn biết ">" hoặc "<"), vì vậy bạn có thể phải nhấn "chỉnh sửa" để xem tất cả.

//
//    FILE: __functions.h
//
//    fast and approximate transcendental functions
//
//    copyright (c) 2004  Robert Bristow-Johnson
//
//    rbj@audioimagination.com
//


#ifndef __FUNCTIONS_H
#define __FUNCTIONS_H

#define TINY 1.0e-8
#define HUGE 1.0e8

#define PI              (3.1415926535897932384626433832795028841972)        /* pi */
#define ONE_OVER_PI     (0.3183098861837906661338147750939)
#define TWOPI           (6.2831853071795864769252867665590057683943)        /* 2*pi */
#define ONE_OVER_TWOPI  (0.15915494309189535682609381638)
#define PI_2            (1.5707963267948966192313216916397514420986)        /* pi/2 */
#define TWO_OVER_PI     (0.636619772367581332267629550188)
#define LN2             (0.6931471805599453094172321214581765680755)        /* ln(2) */
#define ONE_OVER_LN2    (1.44269504088896333066907387547)
#define LN10            (2.3025850929940456840179914546843642076011)        /* ln(10) */
#define ONE_OVER_LN10   (0.43429448190325177635683940025)
#define ROOT2           (1.4142135623730950488016887242096980785697)        /* sqrt(2) */
#define ONE_OVER_ROOT2  (0.707106781186547438494264988549)

#define DB_LOG2_ENERGY          (3.01029995663981154631945610163)           /* dB = DB_LOG2_ENERGY*__log2(energy) */
#define DB_LOG2_AMPL            (6.02059991327962309263891220326)           /* dB = DB_LOG2_AMPL*__log2(amplitude) */
#define ONE_OVER_DB_LOG2_AMPL   (0.16609640474436811218256075335)           /* amplitude = __exp2(ONE_OVER_DB_LOG2_AMPL*dB) */

#define LONG_OFFSET     4096L
#define FLOAT_OFFSET    4096.0



float   __sqrt(float x);

float   __log2(float x);
float   __exp2(float x);

float   __log(float x);
float   __exp(float x);

float   __pow(float x, float y);

float   __sin_pi(float x);
float   __cos_pi(float x);

float   __sin(float x);
float   __cos(float x);
float   __tan(float x);

float   __atan(float x);
float   __asin(float x);
float   __acos(float x);

float   __arg(float Imag, float Real);

float   __poly(float *a, int order, float x);
float   __map(float *f, float scaler, float x);
float   __discreteMap(float *f, float scaler, float x);

unsigned long __random();

#endif




//
//    FILE: __functions.c
//
//    fast and approximate transcendental functions
//
//    copyright (c) 2004  Robert Bristow-Johnson
//
//    rbj@audioimagination.com
//

#define STD_MATH_LIB 0

#include "__functions.h"

#if STD_MATH_LIB
#include "math.h"   // angle brackets don't work with SE markup
#endif




float   __sqrt(register float x)
    {
#if STD_MATH_LIB
    return (float) sqrt((double)x);
#else
    if (x > 5.877471754e-39)
        {
        register float accumulator, xPower;
        register long intPart;
        register union {float f; long i;} xBits;

        xBits.f = x;

        intPart = ((xBits.i)>>23);                  /* get biased exponent */
        intPart -= 127;                             /* unbias it */

        x = (float)(xBits.i & 0x007FFFFF);          /* mask off exponent leaving 0x800000*(mantissa - 1) */
        x *= 1.192092895507812e-07;                 /* divide by 0x800000 */

        accumulator =  1.0 + 0.49959804148061*x;
        xPower = x*x;
        accumulator += -0.12047308243453*xPower;
        xPower *= x;
        accumulator += 0.04585425015501*xPower;
        xPower *= x;
        accumulator += -0.01076564682800*xPower;

        if (intPart & 0x00000001)
            {
            accumulator *= ROOT2;                   /* an odd input exponent means an extra sqrt(2) in the output */
            }

        xBits.i = intPart >> 1;                     /* divide exponent by 2, lose LSB */
        xBits.i += 127;                             /* rebias exponent */
        xBits.i <<= 23;                             /* move biased exponent into exponent bits */

        return accumulator * xBits.f;
        }
     else
        {
        return 0.0;
        }
#endif
    }




float   __log2(register float x)
    {
#if STD_MATH_LIB
    return (float) (ONE_OVER_LN2*log((double)x));
#else
    if (x > 5.877471754e-39)
        {
        register float accumulator, xPower;
        register long intPart;

        register union {float f; long i;} xBits;

        xBits.f = x;

        intPart = ((xBits.i)>>23);                  /* get biased exponent */
        intPart -= 127;                             /* unbias it */

        x = (float)(xBits.i & 0x007FFFFF);          /* mask off exponent leaving 0x800000*(mantissa - 1) */
        x *= 1.192092895507812e-07;                 /* divide by 0x800000 */

        accumulator = 1.44254494359510*x;
        xPower = x*x;
        accumulator += -0.71814525675041*xPower;
        xPower *= x;
        accumulator += 0.45754919692582*xPower;
        xPower *= x;
        accumulator += -0.27790534462866*xPower;
        xPower *= x;
        accumulator += 0.12179791068782*xPower;
        xPower *= x;
        accumulator += -0.02584144982967*xPower;

        return accumulator + (float)intPart;
        }
     else
        {
        return -HUGE;
        }
#endif
    }


float   __exp2(register float x)
    {
#if STD_MATH_LIB
    return (float) exp(LN2*(double)x);
#else
    if (x >= -127.0)
        {
        register float accumulator, xPower;
        register union {float f; long i;} xBits;

        xBits.i = (long)(x + FLOAT_OFFSET) - LONG_OFFSET;       /* integer part */
        x -= (float)(xBits.i);                                  /* fractional part */

        accumulator = 1.0 + 0.69303212081966*x;
        xPower = x*x;
        accumulator += 0.24137976293709*xPower;
        xPower *= x;
        accumulator += 0.05203236900844*xPower;
        xPower *= x;
        accumulator += 0.01355574723481*xPower;

        xBits.i += 127;                                         /* bias integer part */
        xBits.i <<= 23;                                         /* move biased int part into exponent bits */

        return accumulator * xBits.f;
        }
     else
        {
        return 0.0;
        }
#endif
    }


float   __log(register float x)
    {
#if STD_MATH_LIB
    return (float) log((double)x);
#else
    return LN2*__log2(x);
#endif
    }

float   __exp(register float x)
    {
#if STD_MATH_LIB
    return (float) exp((double)x);
#else
    return __exp2(ONE_OVER_LN2*x);
#endif
    }

float   __pow(float x, float y)
    {
#if STD_MATH_LIB
    return (float) pow((double)x, (double)y);
#else
    return __exp2(y*__log2(x));
#endif
    }




float   __sin_pi(register float x)
    {
#if STD_MATH_LIB
    return (float) sin(PI*(double)x);
#else
    register float accumulator, xPower, xSquared;

    register long evenIntPart = ((long)(0.5*x + 1024.5) - 1024)<<1;
    x -= (float)evenIntPart;

    xSquared = x*x;
    accumulator = 3.14159265358979*x;
    xPower = xSquared*x;
    accumulator += -5.16731953364340*xPower;
    xPower *= xSquared;
    accumulator += 2.54620566822659*xPower;
    xPower *= xSquared;
    accumulator += -0.586027023087261*xPower;
    xPower *= xSquared;
    accumulator += 0.06554823491427*xPower;

    return accumulator;
#endif
    }


float   __cos_pi(register float x)
    {
#if STD_MATH_LIB
    return (float) cos(PI*(double)x);
#else
    register float accumulator, xPower, xSquared;

    register long evenIntPart = ((long)(0.5*x + 1024.5) - 1024)<<1;
    x -= (float)evenIntPart;

    xSquared = x*x;
    accumulator = 1.57079632679490*x;                       /* series for sin(PI/2*x) */
    xPower = xSquared*x;
    accumulator += -0.64596406188166*xPower;
    xPower *= xSquared;
    accumulator += 0.07969158490912*xPower;
    xPower *= xSquared;
    accumulator += -0.00467687997706*xPower;
    xPower *= xSquared;
    accumulator += 0.00015303015470*xPower;

    return 1.0 - 2.0*accumulator*accumulator;               /* cos(w) = 1 - 2*(sin(w/2))^2 */
#endif
    }


float   __sin(register float x)
    {
#if STD_MATH_LIB
    return (float) sin((double)x);
#else
    x *= ONE_OVER_PI;
    return __sin_pi(x);
#endif
    }

float   __cos(register float x)
    {
#if STD_MATH_LIB
    return (float) cos((double)x);
#else
    x *= ONE_OVER_PI;
    return __cos_pi(x);
#endif
    }

float   __tan(register float x)
    {
#if STD_MATH_LIB
    return (float) tan((double)x);
#else
    x *= ONE_OVER_PI;
    return __sin_pi(x)/__cos_pi(x);
#endif
    }




float   __atan(register float x)
    {
#if STD_MATH_LIB
    return (float) atan((double)x);
#else
    register float accumulator, xPower, xSquared, offset;

    offset = 0.0;

    if (x < -1.0)
        {
        offset = -PI_2;
        x = -1.0/x;
        }
     else if (x > 1.0)
        {
        offset = PI_2;
        x = -1.0/x;
        }
    xSquared = x*x;
    accumulator = 1.0;
    xPower = xSquared;
    accumulator += 0.33288950512027*xPower;
    xPower *= xSquared;
    accumulator += -0.08467922817644*xPower;
    xPower *= xSquared;
    accumulator += 0.03252232640125*xPower;
    xPower *= xSquared;
    accumulator += -0.00749305860992*xPower;

    return offset + x/accumulator;
#endif
    }


float   __asin(register float x)
    {
#if STD_MATH_LIB
    return (float) asin((double)x);
#else
    return __atan(x/__sqrt(1.0 - x*x));
#endif
    }

float   __acos(register float x)
    {
#if STD_MATH_LIB
    return (float) acos((double)x);
#else
    return __atan(__sqrt(1.0 - x*x)/x);
#endif
    }


float   __arg(float Imag, float Real)
    {
#if STD_MATH_LIB
    return (float) atan2((double)Imag, (double)Real);
#else
    register float accumulator, xPower, xSquared, offset, x;

    if (Imag > 0.0)
        {
        if (Imag <= -Real)
            {
            offset = PI;
            x = Imag/Real;
            }
         else if (Imag > Real)
            {
            offset = PI_2;
            x = -Real/Imag;
            }
         else
            {
            offset = 0.0;
            x = Imag/Real;
            }
        }
     else
        {
        if (Imag >= Real)
            {
            offset = -PI;
            x = Imag/Real;
            }
         else if (Imag < -Real)
            {
            offset = -PI_2;
            x = -Real/Imag;
            }
         else
            {
            offset = 0.0;
            x = Imag/Real;
            }
        }

    xSquared = x*x;
    accumulator = 1.0;
    xPower = xSquared;
    accumulator += 0.33288950512027*xPower;
    xPower *= xSquared;
    accumulator += -0.08467922817644*xPower;
    xPower *= xSquared;
    accumulator += 0.03252232640125*xPower;
    xPower *= xSquared;
    accumulator += -0.00749305860992*xPower;

    return offset + x/accumulator;
#endif
    }




float   __poly(float *a, int order, float x)
    {
    register float accumulator = 0.0, xPower;
    register int n;

    accumulator = a[0];
    xPower = x;
    for (n=1; n<=order; n++)
        {
        accumulator += a[n]*xPower;
        xPower *= x;
        }

    return accumulator;
    }


float   __map(float *f, float scaler, float x)
    {
    register long i;

    x *= scaler;

    i = (long)(x + FLOAT_OFFSET) - LONG_OFFSET;         /* round down without floor() */

    return f[i] + (f[i+1] - f[i])*(x - (float)i);       /* linear interpolate between points */
    }


float   __discreteMap(float *f, float scaler, float x)
    {
    register long i;

    x *= scaler;

    i = (long)(x + (FLOAT_OFFSET+0.5)) - LONG_OFFSET;   /* round to nearest */

    return f[i];
    }


unsigned long __random()
    {
    static unsigned long seed0 = 0x5B7A2775, seed1 = 0x80C7169F;

    seed0 += seed1;
    seed1 += seed0;

    return seed1;
    }

Có ai biết cách đánh dấu mã này hoạt động với SE không? nếu bạn nhấn "chỉnh sửa", bạn có thể thấy mã mà tôi dự định, nhưng những gì chúng tôi xem ở đây có nhiều dòng mã bị bỏ qua và không chỉ ở cuối tệp. tôi đang sử dụng tham chiếu đánh dấu mà chúng tôi hướng đến bởi trợ giúp đánh dấu SE . nếu bất cứ ai có thể tìm ra nó, xin vui lòng chỉnh sửa câu trả lời và cho chúng tôi biết bạn đã làm gì.
robert bristow-johnson

tôi không biết đó là gì @Royi.
robert bristow-johnson


Vì vậy, @Royi, điều đó tốt với tôi rằng mã này được đăng lên vị trí pastebin đó. Nếu bạn muốn, bạn cũng có thể đăng mã này để chuyển đổi nhị phân thành kiểm tra thập phân và văn bản thập phân thành nhị phân . nó đã được sử dụng trong cùng một dự án nhúng mà chúng tôi không muốn stdlibtrong đó.
robert bristow-johnson

7

Nếu bạn chưa nhìn thấy nó, "Quake vuông root" chỉ đơn giản là bí ẩn. Nó sử dụng một số phép thuật cấp bit để cung cấp cho bạn một xấp xỉ đầu tiên rất tốt, và sau đó sử dụng một hoặc hai phép tính gần đúng của Newton để sửa đổi. Nó có thể giúp bạn nếu bạn đang làm việc với nguồn lực hạn chế.

https://en.wikipedia.org/wiki/Fast_inverse_sapes_root

http://betterexplained.com/articles/under Hiểu-quakes-fast-inverse-sapes-rot /


6

Bạn cũng có thể tính gần đúng hàm căn bậc hai bằng cách sử dụng Phương pháp của Newton . Phương pháp của Newton là một cách gần đúng nơi gốc rễ của một hàm. Nó cũng là một phương pháp lặp trong đó kết quả từ lần lặp trước được sử dụng trong lần lặp tiếp theo cho đến khi hội tụ. Phương trình của phương pháp Newton để đoán vị trí gốc của hàm với dự đoán ban đầu được định nghĩa là:f(x)x0

x1=x0f(x0)f(x0)

x1 là dự đoán đầu tiên về vị trí của gốc. Chúng tôi tiếp tục tái chế phương trình và sử dụng kết quả từ các lần lặp trước cho đến khi câu trả lời không thay đổi. Nói chung, để xác định dự đoán gốc ở lần lặp , đưa ra dự đoán tại lần lặp được định nghĩa là:(n+1)n

xn+1=xnf(xn)f(xn)

Để sử dụng phương pháp của Newton để tính gần đúng cho căn bậc hai, giả sử rằng chúng ta được cung cấp một số . Như vậy, để tính căn bậc hai, chúng ta cần tính Như vậy, chúng ta tìm cách tìm một câu trả lời sao cho . Bình phương cả hai cạnh và di chuyển sang phía bên kia của phương trình mang lại . Như vậy, câu trả lời cho phương trình này là và do đó là gốc của hàm. Như vậy, hãy để là phương trình chúng ta muốn tìm gốc của. Bằng cách thay thế điều này vào phương pháp của Newton, và do đó:aax=aax2a=0af(x)=x2af(x)=2x

xn+1=xnxn2a2xn
xn+1=12(xn+axn)

Do đó, để tính căn bậc hai của , chúng ta chỉ cần tính toán phương pháp của Newton cho đến khi chúng ta hội tụ. Tuy nhiên, như được lưu ý bởi @ robertbristow-johnson, bộ phận là một hoạt động rất tốn kém - đặc biệt đối với các bộ vi điều khiển / DSP với nguồn lực hạn chế. Ngoài ra, có thể có trường hợp đoán có thể bằng 0, dẫn đến lỗi chia cho 0 do thao tác chia. Như vậy, những gì chúng ta có thể làm là sử dụng phương pháp của Newton và giải quyết cho hàm đối ứng thay vào đó, tức là . Điều này cũng tránh bất kỳ phân chia, như chúng ta sẽ thấy sau. Bình phương cả hai bên và di chuyển sang bên trái, do đó sẽ cho . Do đó, giải pháp cho vấn đề này sẽ làa1x=aa1x2a=01a . Bằng cách nhân với , chúng ta sẽ có được kết quả như mong muốn. Một lần nữa, sử dụng phương pháp của Newton, do đó chúng ta có:a

xn+1=xnf(xn)f(xn)
xn+1=xn1(xn)2a2(xn)3
xn+1=12(3xn(xn)3a)

Tuy nhiên, có một cảnh báo mà chúng ta nên xem xét khi nhìn vào phương trình trên. Đối với căn bậc hai, giải pháp phải dương và vì vậy để các lần lặp (và kết quả) là dương, điều kiện sau phải được thỏa mãn:

3 x n > ( x n ) 3 a ( x n ) 2 a < 3

3xn(xn)3a>0
3xn>(xn)3a
(xn)2a<3

Vì thế:

(x0)2a<3

Do đó, với số lượng chúng tôi muốn tính căn bậc hai, dự đoán ban đầu phải thỏa mãn điều kiện trên. Vì điều này cuối cùng sẽ được đặt trên một vi điều khiển, chúng ta có thể bắt đầu với bất kỳ giá trị nào của (giả sử 1), sau đó tiếp tục lặp và giảm giá trị của cho đến khi điều kiện trên được thỏa mãn. Lưu ý rằng tôi đã tránh thực hiện phép chia để tính trực tiếp giá trị củax 0 x 0 10 - 6x0x0x0nên như phân chia là một hoạt động đắt tiền. Khi chúng ta có dự đoán ban đầu, hãy lặp lại thông qua phương pháp của Newton. Lưu ý rằng tùy thuộc vào dự đoán ban đầu, có thể mất một khoảng thời gian ngắn hơn hoặc dài hơn để hội tụ. Tất cả phụ thuộc vào mức độ gần gũi của bạn với câu trả lời thực tế. Bạn có thể giới hạn số lần lặp hoặc đợi cho đến khi chênh lệch tương đối giữa hai gốc nhỏ hơn một số ngưỡng (như hoặc hơn).106

Vì thẻ của bạn đang tìm kiếm một thuật toán C, hãy viết một cách nhanh chóng:

#include <stdio.h> // For printf
#include <math.h> // For fabs
void main() 
{
   float a = 5.0; // Number we want to take the square root of
   float x = 1.0; // Initial guess
   float xprev; // Root for previous iteration
   int count; // Counter for iterations

   // Find a better initial guess
   // Half at each step until condition is satisfied
   while (x*x*a >= 3.0)
       x *= 0.5;

   printf("Initial guess: %f\n", x);

   count = 1; 
   do { 
       xprev = x; // Save for previous iteration
       printf("Iteration #%d: %f\n", count++, x);                   
       x = 0.5*(3*xprev - (xprev*xprev*xprev)*a); // Find square root of the reciprocal
   } while (fabs(x - xprev) > 1e-6); 

   x *= a; // Actual answer - Multiply by a
   printf("Square root is: %f\n", x);
   printf("Done!");
}

Đây là một triển khai khá cơ bản của phương pháp Newton. Lưu ý rằng tôi tiếp tục giảm một nửa dự đoán ban đầu cho đến khi điều kiện chúng ta nói trước đó được thỏa mãn. Tôi cũng đang cố gắng tìm căn bậc hai của 5. Chúng tôi biết rằng điều này gần bằng với 2.236 hoặc hơn. Sử dụng mã trên cho đầu ra sau:

Initial guess: 0.500000
Iteration #1: 0.500000
Iteration #2: 0.437500
Iteration #3: 0.446899
Iteration #4: 0.447213
Square root is: 2.236068
Done!

Lưu ý rằng phương pháp của Newton là tìm giải pháp của giải pháp đối ứng và chúng tôi nhân với kết thúc để có câu trả lời cuối cùng. Ngoài ra, hãy lưu ý rằng dự đoán ban đầu đã được thay đổi để đảm bảo rằng các tiêu chí tôi đã nói ở trên được thỏa mãn. Để giải trí, chúng ta hãy thử tìm căn bậc hai của 9876.a

Initial guess: 0.015625
Iteration #1: 0.015625
Iteration #2: 0.004601
Iteration #3: 0.006420
Iteration #4: 0.008323
Iteration #5: 0.009638
Iteration #6: 0.010036
Iteration #7: 0.010062
Square root is: 99.378067
Done!

Như bạn có thể thấy, điều duy nhất khác biệt là có bao nhiêu lần lặp được yêu cầu để tính căn bậc hai. Số lượng những gì bạn muốn tính toán càng cao, càng nhiều lần lặp lại.

Tôi biết rằng phương pháp này đã được đề xuất trong một bài viết trước đó, nhưng tôi đoán rằng tôi đã rút ra được phương pháp cũng như cung cấp một số mã!


2
thay vào đó, tôi có thể đề xuất rằng hàm bạn nhắm đến là thay vào đó. sẽ không cần phân chia trong lần lặp và tất cả những gì bạn cần làm là nhân kết quả với để có được . đó là lý do tại sao bạn thấy tất cả những thứ này về căn bậc hai đối ứng trong ánh sáng trong các triển khai trong thế giới thực. xf(x)=1xxx
robert bristow-johnson

3
chỉ có điều, đối với những người mã hóa DSP và một số chip khác, sự phân chia đó đặc biệt đắt đỏ, trong khi những chip này có thể nhân số nhanh như họ có thể di chuyển số.
robert bristow-johnson

1
@ robertbristow-johnson - và một điểm tuyệt vời khác. Tôi nhớ lại khi tôi làm việc với Motorola 6811, việc nhân lên mất vài chu kỳ trong khi việc phân chia mất vài trăm. Không đẹp.
rayryeng - Phục hồi Monica

3
à, tốt '68HC11. có một số thứ từ năm 6809 (như nhân nhanh) nhưng nhiều vi điều khiển hơn.
robert bristow-johnson

1
@ robertbristow-johnson - Vâng thưa ngài 68HC11 :). Tôi đã sử dụng nó để tạo ra một hệ thống tạo tín hiệu y sinh tạo ra tín hiệu tim nhân tạo để hiệu chỉnh thiết bị y tế và đào tạo sinh viên y khoa. Đó là một thời gian dài, nhưng những kỷ niệm rất thích!
rayryeng - Phục hồi Monica

6

bởi vì mã đánh dấu cho SE dường như hoạt động như shit, tôi sẽ cố gắng trả lời trực tiếp hơn, đặc biệt cho hàm .x

có, một chuỗi lũy thừa có thể xấp xỉ nhanh chóng và hiệu quả với hàm căn bậc hai và chỉ trên một miền giới hạn. miền càng rộng, bạn càng cần nhiều thuật ngữ trong chuỗi sức mạnh của mình để giữ cho lỗi đủ thấp.

1x2

x  1+a1(x1)+a2(x1)2+a3(x1)3+a4(x1)4=1+(x1)(a1+(x1)(a2+(x1)(a3+(x1)a4)))

Ở đâu

a1

a2

a3

a4

x=1x=2

2nn2

nếu đó là điểm nổi, bạn cần tách số mũ và số mũ giống như mã C của tôi trong câu trả lời khác.



3

a>b

a2+b20.96a+0.4b.

Trong vòng 4% chính xác, nếu tôi nhớ tốt. Nó được sử dụng bởi các kỹ sư, trước khi các máy tính và máy tính logarit. Tôi đã học nó ở Notes et formules de l'ingénieur, De Laharpe , 1923

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.