Karekök Hesaplamak için Hangi Yaklaşım Teknikleri Var?


12

Mikrodenetleyici ile çalıştığım için çok sınırlı kaynağım var. Taylor serisi genişleme, ortak arama tablosu veya özyinelemeli yaklaşım var mı?

Math.h'nin sqrt () kullanmadan bir şey yapmayı tercih ederim

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


5
Bu bağlantıya göz atın: codeproject.com/Articles/69941/…
Matt L.

1
Daha programlama sorusu dışında, neden Matt'i cevaplamasın ki?
jojek

Kayan noktalı veya sabit noktalı giriş? Sabit nokta için yinelemeli bir yöntem tercih edilebilir, ancak gerçekten istemediğiniz sürece açıklamaktan rahatsız olmaz.
Oscar

@Oscar, sabit yazılım yöntemini öğrenmek isterdim çünkü bellenimde şamandıra kullanımını gerektirmemeye çalışıyorum :).
tarabyte

Yanıtlar:


13

ucuz ve kirli optimize edilmiş bir güç serisi genişletme (Taylor serisi için katsayılar yavaş yavaş yakınsama) sqrt()ve bir sürü diğer trancendentals istiyorsanız, uzun zaman önce bazı kodlar var. Bu kodu satıyordum, ama kimse bana neredeyse on yıldır para ödedi. bu yüzden kamu tüketimi için serbest bırakacağımı düşünüyorum. Bu özel dosya işlemci (IEEE-754 tek bir hassasiyet) kayan nokta olan bir uygulama için ve bir Cı derleyicisi ve dev sistemi vardı, ama yaptılar değilStandart matematik fonksiyonlarına sahip olacak stdlib'e sahip olmak (ya da bağlantı kurmak istemediler). mükemmel bir hassasiyete ihtiyaç duymadılar, ama işlerin hızlı olmasını istediler. Kuvvet serisi katsayılarının ne olduğunu görmek ve kendi kodunuzu yazmak için kodu kolayca tersine çevirebilirsiniz. bu kod IEEE-754'ü kabul eder ve mantis ve üs için bitleri maskeler.

SE'nin sahip olduğu "kod biçimlendirmesi", açı karakterleriyle (">" veya "<") bildiğiniz gibi görünmüyor, bu nedenle tümünü görmek için muhtemelen "düzenle" tuşuna basmanız gerekecek.

//
//    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;
    }

kimse bu kod işaretleme SE ile nasıl çalıştığını biliyor mu? "edit" tuşuna basarsanız, istediğim kodu görebilirsiniz, ancak burada gördüğümüz kodun sadece satır sonunda değil , birçok kod satırı atlanmıştır. SE biçimlendirme yardımı tarafından yönlendirilen biçimlendirme referansını kullanıyorum . eğer birisi çözebilirse, lütfen cevabı düzenleyin ve bize ne yaptığınızı söyleyin.
robert bristow-johnson

@Royi ne olduğunu bilmiyorum.
robert bristow-johnson


yani @Royi, bu kodun o macun konumuna gönderilmesi benim için sorun değil. İsterseniz , ikiliyi ondalık sınamaya ve ondalık metni ikiliye dönüştüren bu kodu da gönderebilirsiniz . İçinde istemediğimiz aynı gömülü projede kullanıldı stdlib.
robert bristow-johnson


6

Newton Yöntemi'ni kullanarak karekök işlevine de yaklaşabilirsiniz . Newton'un Yöntemi, bir fonksiyonun köklerinin nerede olduğunu tahmin etmenin bir yoludur. Ayrıca, önceki yinelemeden elde edilen sonucun yakınsamaya kadar bir sonraki yinelemede kullanıldığı yinelemeli bir yöntemdir. Newton'un bir başlangıç ​​tahmini tahmini verildiğinde kök fonksiyonunun nerede olduğunu tahmin etme yöntemi için denklem şöyle tanımlanır:f(x)x0

x1=x0f(x0)f(x0)

x1 , kökün bulunduğu ilk tahmindir. Cevap değişmeyene kadar denklemi geri dönüştürmeye ve önceki iterasyonlardan elde edilen sonuçları kullanmaya devam ediyoruz. Genel olarak, yinelemedeki tahmin verildiğinde yinelemede kök tahminini belirlemek için :(n+1)n

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

Biz numara verilir varsayalım kare kökü yaklaşmak için Newton yöntemi kullanmak için . Bu nedenle, karekök hesaplamak için, ı hesaplamamız gerekir. Bu nedenle, bir cevap bulmaya çalışırız . Her iki tarafı da, kare, ve hareketli denklem verimi diğer tarafına . Bu nedenle, bu denklemin cevabı ve dolayısıyla fonksiyonun köküdür . Bu nedenle, nın kökünü bulmak istediğimiz denklem olsun. Bunu Newton'un yöntemiyle değiştirerek, ve dolayısıyla:aax=aax2a=0af(x)=x2af(x)=2x

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

Bu nedenle, karekökünü hesaplamak için , biz sadece biz yakınsama kadar Newton yöntemi hesaplamamız gerekir. Bununla birlikte, @ robertbristow-johnson tarafından belirtildiği gibi, bölme çok pahalı bir işlemdir - özellikle sınırlı kaynaklara sahip mikrodenetleyiciler / DSP'ler için. Buna ek olarak, bir tahminin 0 olabileceği ve bölünme işlemi nedeniyle 0 hataya bölünmesine neden olacak bir durum olabilir. Bu nedenle, yapabileceğimiz Newton yöntemini kullanmak ve bunun yerine karşılıklı işlev için çözmek , yani . Bu, daha sonra göreceğimiz gibi, herhangi bir bölünmeyi de önler. Her iki tarafın ve sol tarafa taşımak böylece . Bu nedenle, bunun çözümüa1x=aa1x2a=01a . Tarafından çarparak , bizim amaçlanan sonucu elde edersiniz. Yine, Newton'un yöntemini kullanarak, elimizde:a

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

Ancak, yukarıdaki denkleme bakarken dikkate almamız gereken bir uyarı vardır. Kare kökler için, çözüm pozitif olmalı ve bu nedenle iterasyonların (ve sonucun) pozitif olması için aşağıdaki koşul yerine getirilmelidir:

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

Bu nedenle:

(x0)2a<3

Bu nedenle, karekökünü hesaplamak istediğiniz numarayı verilen ilk tahminim gerekir yukarıdaki koşulu karşılayan. Bu sonuçta bir mikrodenetleyici üzerine yerleştirilen olacak gibi biz herhangi bir değere sahip başlayabileceğini (1 say), sonra döngü ve değerini azaltarak tutmak yukarıdaki koşul yerine gelene kadar. Doğrudan değerini hesaplamak için bölme yapmaktanx0x0x0bölünme pahalı bir işlem gibi olmalıdır. İlk tahminimizi yaptıktan sonra, Newton'un yöntemini tekrarlayın. İlk tahmine bağlı olarak yakınsamanın daha kısa veya daha uzun sürebileceğini unutmayın. Her şey gerçek cevaba ne kadar yakın olduğunuza bağlıdır. Yineleme sayısını sınırlayabilir veya iki kök arasındaki göreceli fark bir eşik değerden daha az olana kadar ( gibi) bekleyebilirsiniz .106

Etiketiniz bir algoritma ararken C, hızlı bir şekilde bir tane yazalım:

#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!");
}

Bu, Newton'un yönteminin oldukça basit bir uygulamasıdır. Daha önce bahsettiğimiz koşul tatmin edilinceye kadar ilk tahminin yarısını azaltmaya devam ettiğimi unutmayın. Ben de 5'in karekökünü bulmaya çalışıyorum. Bunun 2.236 ya da daha fazlasına eşit olduğunu biliyoruz. Yukarıdaki kodu kullanmak aşağıdaki çıktıyı verir:

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!

Newton'un yönteminin karşılıklı çözümün çözümü olduğunu ve son cevabımızı almak için sonunda ile çarptığımızı unutmayın . Ayrıca, yukarıda bahsettiğim kriterlerin karşılandığından emin olmak için ilk tahminin değiştirildiğine dikkat edin. Sadece eğlence için 9876'nın karekökünü bulmaya çalışalım.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!

Gördüğünüz gibi, farklı olan tek şey kare kökü hesaplamak için kaç yinelemenin gerekli olduğudur. Hesaplamak istediğiniz şeyin sayısı ne kadar yüksek olursa o kadar çok yineleme yapılır.

Bu yöntemin daha önceki bir yazıda önerildiğini biliyorum, ancak yöntemi türettiğim gibi bazı kodlar sağladığımı düşündüm!


2
ray, amaçladığınız işlevin yerine olduğunu önerebilir miyim . yinelemede bölünmeye gerek yoktur ve tek yapmanız gereken sonucu almak için sonucu ile çarpmaktır . bu yüzden aydınlatılmış ve gerçek dünyadaki uygulamalarda karşılıklı karekök ile ilgili tüm bu şeyleri görüyorsunuz . f(x)=1xxx
robert bristow-johnson

3
sadece DSP'leri ve diğer bazı yongaları kodlayan insanlar için bu bölüm özellikle pahalıdır, oysa bu yongalar sayıları taşıyabilecekleri kadar hızlı çoğaltabilir.
robert bristow-johnson

1
@ robertbristow-johnson - ve başka bir mükemmel nokta. Motorola 6811 ile çalışırken bölmenin birkaç yüz sürerken çarpmanın birkaç döngü yaptığını hatırlıyorum. Güzel değildi.
rayryeng

3
ahh, iyilik 68HC11. 6809 (hızlı bir çarpma gibi) ama bir mikrodenetleyici daha bazı şeyler vardı.
robert bristow-johnson

1
@ robertbristow-johnson - Evet efendim 68HC11 :). Tıbbi ekipmanı kalibre etmek ve tıp öğrencilerini eğitmek için yapay kalp sinyalleri oluşturan bir biyomedikal sinyal üretme sistemi oluşturmak için kullandım. Uzun zaman oldu, ama çok hoş anılar!
rayryeng

6

SE için kod işaretleme bok gibi çalışıyor gibi görünüyor, ben daha doğrudan, özellikle işlevi için cevap çalışacağız .x

evet, bir güç serisi karekök işlevine hızlı ve verimli bir şekilde yaklaşabilir ve sadece sınırlı bir alan üzerinde olabilir. etki alanı ne kadar geniş olursa, hatayı yeterince düşük tutmak için güç serilerinizde o kadar çok terime ihtiyacınız olacaktır.

için1x2

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

nerede

a1 = ,49959804148061

a2 = -0.12047308243453

a3 = 0.04585425015501

a4 = -0.01076564682800

bu katsayılar, eşitlik ve ve aradaki maksimum bağıl hata en aza indirilecek şekilde değiştirilmiş bir Remez değişim algoritması kullanılarak belirlenmiştir .x=1x=2

yani, uygulamanız sabit bir nokta ise, sabit nokta şemanızın ölçeklendirmesini kullanarak değerlerinizi 1 ve 2 arasında olana kadar bitlerinizi kaydırmanız gerekir (kaydırılan bit pozisyonlarının sayısını sayarak). Eğer doğru kayması durumunda [sol] tarafından argüman bit argüman 1 ve 2 arasında olduğu için, sonuç değişimi olmalıdır [hakkı] sol tarafından bit. kaydırma bitlerinin sayısı tekse, fazladan bit kaydırma, kodunuzda sabit olarak saklanabilen ek bir çarpımı ile telafi edilir .2nn2

kayan nokta ise, diğer cevapta C kodumun yaptığı gibi üs ve mantis'i ayırmanız gerekir.



3

Geçmişte beni şaşırtan bir kare kök genişlemesi, karmaşık büyüklükte (veya bir dikdörtgende köşegen) genişlemedir; eğer , o zaman:a>b

a2+b20.96a+0.4b.

% 4 hassasiyet içinde, iyi hatırlarsam. Mühendisler tarafından, logaritmik cetvellerden ve hesap makinelerinden önce kullanıldı. 1923 yılında Notes ve l'ingénieur'da öğrendim , De Laharpe , 1923

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.