Legjobb válasz
64 7 1 ⇒︎ 8 ︎77
8.8² = (9-.2) ² = 81–2 (9) (. 2) +. 2² = 81–3.6 + .04 = 77.44, jó vendéglátás mondanám!
8.7² = (9-.3) ² = 81–2 (9) (. 3) +. 3² = 81–5.4 + .09 = 75.69, ismét nagyon közel!
8.7 ︎77 .8
Így lehet kissé közelebb kerülni ceruzával és papírral, x> y> 1 xy> √︎x-√︎y esetén, tehát a 77 és x közötti különbség nagyobb, mint √︎77 és √︎x, hogy tudd A 77-x a becslés hibájának felső határa, ahol x az annak a négyzete, amelyet √︎77-nek tulajdonítasz.
Próbáljuk meg a 8.75-öt szórakozásból:
(9 –1/4) ² = 81–2 (9) (1/4) +1/16 = 81–4,5 + 1/16 =
76.5625
8.75 ≤︎ √ ︎77 ≤︎ 8,8
Válasz
A legtöbb modern CPU natívan biztosít egy négyzetgyökös műveletet. Tehát tipikus modern hardvereken alkalmazott tipikus programozási nyelv mellett a művelet végső soron pontosan ez lesz.
Tehát beszéljünk arról a módszerről, amelyet szinte az összes modern általános célú CPU használ.
Számábrázolás
Első dolog, amit meg kell értenünk, hogy a számítógép valójában hogyan ábrázolja azokat a számokat, amelyekről beszélünk. Egyfajta tudományos jelölésben vannak tárolva.
Most az a fajta tudományos jelölés, amelyet ismerhet, ahol a -134,5-ös számot -1,345 \-szer 10 ^ {2} -ként ábrázolják.
Bármely szám, amely nem nulla, ábrázolható ebben a formában, amelynek fogalmilag három része van: a jel (azaz a szám pozitív vagy negatív), a mantissa (1 és 10 közötti szám, köztük 1, de 10 nélkül, ebben az esetben 1.345), és a kitevő (az a teljesítmény, amelyre a radix emelkedik, ebben az esetben 2; vegye figyelembe, hogy a kitevő lehet negatív vagy általában nulla).
A reprezentáció hogy szinte minden modern számítógép használata nagyon hasonló, azzal a különbséggel, hogy a számot bináris ábrázolással tároljuk, nem pedig tizedesre. Tehát a jelbit és a nulla figyelmen kívül hagyásával (mivel a nulla négyzetgyök megtalálása triviális, és a negatív szám négyzetgyöke nem valós szám), a pozitív számokat valójában m \ szor 2 ^ {e} alakban tároljuk, ahol m 1 és 2 közötti szám (beleértve az 1-et, de a 2-et nem tartalmazza).
Ezt az ábrázolást lebegőpontnak nevezzük, a bináris pont mozgatásának módja miatt (analóg módon a tizedesjegy, amelyet ismerhet) az exponens beállításával.
Mindez azért fontos, mert a CPU az ábrázolást használja a négyzetgyök kiszámításához. Tegyük fel, hogy a kitevő egyenletes. Ezután:
\ sqrt {m \ szor 2 ^ {2 \ epsilon}} = \ sqrt {m} \ szor 2 ^ {\ epsilon}
Hasonlóképpen, ha a kitevő páratlan, akkor:
\ sqrt {m \ times 2 ^ {2 \ epsilon + 1}} = \ sqrt {2} \ sqrt {m} \ times 2 ^ {\ epsilon}
Ne feledje, hogy m az [1,2) tartományban van. Ez azt jelenti, hogy a problémát bármely szám négyzetgyökének kiszámítására csökkentettük, és kiszámítottuk az adott tartományban lévő szám négyzetgyökét. Vagy ha nem akarjuk előre kiszámítani a \ sqrt {2} számot, akkor az [1,4] tartományba eső számot. Akárhogy is, drámai módon leegyszerűsítettük a problémát, mert most már használhatunk olyan módszereket, amelyek jól működnek ebben a számtartományban.
Szorzás és osztás
Tehát most, hogy idáig eljutottunk, azt gondolhatja (ha megnézte a többi választ), hogy a megoldás most egy olyan módszer használata, mint a Newton-Raphson iteráció a négyzet kiszámításához gyökér. Az n négyzetgyökének kiszámításához válasszon ki egy kezdeti kitalálást x\_0 és ismételje meg:
x\_ {i + 1} = \ frac {1} {2} \ left (x\_i + \ frac {n} {x\_i } \ right)
Ez a válasz helytelen . Nos, ez nem baj abban, hogy helyes választ ad. De ez téves abban, hogy egyetlen önmagát tisztelő CPU-tervező (vagy bármelyik könyvtáríró, ha szoftverbe kellene telepítenie) nem valósítana meg lebegőpontos négyzetgyököt.
A kettő által történő felosztás nagyon olcsó bináris művelet (ami, emlékezzünk, a 2. alap, tehát csak egy ponttal tolja el a bináris pontot). A másik osztás azonban nagyon drága művelet, és ebben az esetben többször is el kell végeznie a műveletet.
A divízió annyira drága, hogy a modern CPU-k hasonló iteratív algoritmust használnak a Newton-Raphson iterációhoz (de valójában nem) az osztás elvégzéséhez! Nyilvánvaló, hogy nem akarjuk ezt hardverben, belső hurokban megtenni.
A modern számítógépes hardvereken sokkal olcsóbb elvégezni szorzási művelet, mint osztási művelet. Az okot kissé bonyolult megmagyarázni; ez azzal a ténnyel függ össze, hogy sokkal több tranzisztort tudunk elhelyezni egy chipen, mint korábban tudtunk, és a szorzás olyan probléma, hogy sok tranzisztorra hatékonyan rá lehet lépni. Keresse fel a Wallace fákat , ha érdekli a részleteket.
Mindenesetre az a lényeg, hogy a szorzás viszonylag olcsó művelet. Tehát, ha a négyzetgyök műveletet nem szorzás, hanem szorzás szempontjából tudjuk megvalósítani, az jobb lenne.
Newton-Raphson, vegyen kettőt
Most következik az első kulcsfontosságú betekintés: A négyzetgyök kiszámítása helyett számítsa ki a négyzetgyök reciprok -át. Vagyis a \ sqrt {n} helyett számítsa ki a \ frac {1} {\ sqrt {n}} értéket. Kiderült, hogy ezt sokkal könnyebb kiszámítani, és ha szüksége van a négyzetgyökre, szorozza meg ezt a számot n-vel, és kész.
A Newton-Raphson módszer a kölcsönös négyzetgyökre így néz ki . Ha az x\_0 kezdeti becslés \ frac {1} {\ sqrt {n}} értékre, akkor ismételje meg:
x\_ {i + 1} = \ frac {1} {2} x\_i \ left (3 – n {x\_i} ^ 2 \ jobbra)
Ismét meglehetősen olcsó a kettővel való felosztás, és minden más szorzás és összeadás / kivonás.
Ez nagyszerű módja a megvalósításnak szoftverben. Sőt, érdemes kiemelni, hogy sok gyakorlati helyzetben (például egy vektor normalizálása Pythagoras tételével) a reciprok négyzetgyök valóban hasznosabb, mint a négyzetgyök, mivel a négyzetgyökkel való osztás kevésbé hatékony, mint a szorzás reciprok négyzettel root.
Ez azonban általában nem így valósul meg a hardverben.
Goldschmidt algoritmusa
Most megnézhetjük Goldschmidt algoritmusát, amely a négyzetgyököt és a kölcsönös négyzetgyököt együtt számolja ki. Y\_0} ^ 2 {Y\_1} ^ 2 \ cdots {Y\_ {n-1}} ^ 2 megközelíti az 1-et, majd y\_n = {Y\_0} {Y\_1} \ cdots {Y\_ {n-1}} megközelíti a \ frac {1} Az {\ sqrt {b\_0}} és az x\_n = b\_0 {Y\_0} {Y\_1} \ cdots {Y\_ {n-1}} megközelíti az \ sqrt {b\_0} szót.
Az általunk használt sorozat lényegében a Newton-Raphson frissítési lépés:
\ begin {align *} b\_i & = b\_ {i-1} {Y\_ {i-1}} ^ 2 \\ Y\_i & = \ frac {1} {2 } (3 – b\_i) \ end {align *}
És akkor nyomon követhetjük a négyzetgyöket:
\ begin {align *} x\_0 & = n Y\_0 \\ x\_ {i} & = x\_ {i-1} Y\_i \ end {align *}
És a kölcsönös négyzetgyök:
\ begin {align *} y\_0 & = Y\_0 \\ y\_ {i} & = y\_ {i-1} Y\_i \ end {align *}
Ha mégis figyelemmel kísérjük az x\_i és az y\_i értékeket, vegye figyelembe, hogy b\_i = x\_ {i-1} y\_ {i-1}. Tehát soha nem kell nyomon követnünk a b\_i-t:
\ begin {align *} Y\_i & = \ frac {1} {2} \ left (3 – b\_i \ right) \\ & = 1 + \ frac {1} {2} \ bal (1 – b\_i \ jobb) \\ & = 1 + \ frac {1} {2} \ bal (1 – x\_ {i-1} y\_ {i-1} \ jobb ) \ end {align *}
És most sem kell nyomon követnünk Y\_i-t:
\ begin {align *} x\_i & = x\_ {i-1} \ balra (1 + \ frac {1} {2} \ balra (1 – x\_ {i-1} y\_ {i-1} \ jobbra) \ jobbra) \\ & = x\_ {i-1} + x\_ {i- 1} \ frac {1} {2} \ balra (1 – x\_ {i-1} y\_ {i-1} \ jobbra) \\ y\_i & = y\_ {i-1} \ balra (1 + \ frac {1 } {2} \ bal (1 – x\_ {i-1} y\_ {i-1} \ jobb) \ jobb) \\ & = y\_ {i-1} + y\_ {i-1} \ frac {1} { 2} \ left (1 – x\_ {i-1} y\_ {i-1} \ right) \ end {align *}
Itt van néhány felesleges számítás, amelyet eltávolíthatunk, a következőket javasolva algoritmus. Ha Y-t közelítjük a \ frac {1} {\ sqrt {n}} értékre, állítsuk be:
\ begin {align *} x\_0 & = n Y \\ y\_0 & = Y \ end {align * }
Ezután ismételje meg:
\ kezdje el {align *} r\_i & = \ frac {1} {2} \ balra (1 – x\_i y\_i \ jobbra) \\ x\_ {i +1} & = x\_i + x\_i r\_i \\ y\_ {i + 1} & = y\_i + y\_i r\_i \ end {align *}
Noha a kettes osztás olcsó, ezt is elkerülhetjük a h\_i = \ frac {1} {2} y\_i nyomon követésével y\_i helyett. Ez Goldschmidt algoritmusa.
Tegyük fel, hogy Y közelítő értéke \ frac {1} {\ sqrt {n}}. Beállítás:
\ begin {align *} x\_0 & = n Y \\ h\_0 & = \ frac {Y} {2} \ end {align *}
Ezután ismételje meg:
\ begin {align *} r\_i & = \ frac {1} {2} – x\_i h\_i \\ x\_ {i + 1} & = x\_i + x\_i r\_i \\ h\_ {i + 1} & = h\_i + h\_i r\_i \ end {align *}
Ezután az x\_i konvergál az \ sqrt {n}, a h\_n pedig a \ frac {1} {2 \ sqrt {n}}.
Ennek megvalósítása hardverben
Eddig nagyon jó. Ez bizony nagyon egyszerű algoritmus. De miért jobb?
A modern CPU-knak gyakran van egy gyors áramköre, amely optimalizált szorzás-felhalmozás műveletet hajt végre , amelyet gyakran egyesített szorzó- add, vagy röviden FMA. Ha korábban kereste a Wallace-fákra való hivatkozást, akkor tisztában kell lennie azzal, hogy az FMA hogyan lehet majdnem olyan hatékony, mint az egyenes szorzási művelet.
Az FMA az egyik leghasznosabb primitív, amellyel rendelkezhetünk. Ha például ki kell értékelnie egy polinomot:
p (x) = a\_0 + a\_1 x + a\_2 x ^ 2 + \ cdots a\_n x ^ n
használhatja a Horner-t szabály, amely lényegében egy csomó FMA:
\ begin {align *} p\_ {n-1} & = a\_ {n-1} + x a\_n \\ p\_ {n-2} & = a\_ {n-2} + x p\_ {n-1} \\ & \ vdots \\ p\_1 & = a\_1 + x p\_2 \\ p\_0 & = a\_0 + x p\_1 \ end {igazítás *}
Goldschmidt algoritmusának belső hurka három FMA és semmi más.Éppen ezért előny: csak egyfajta áramkörre van szükség (esetleg csak egy áramkörre; vegye figyelembe, hogy a második két FMA független, és így hasznot húzhat a csővezeték gyártásából), valamint valamilyen vezérlési logikát minden megvalósításához. És ez egy olyan áramkör, amely sok más műveletnél hasznos, így nem pazarol sok hardvert csak a négyzetgyökű műveletre.
A puzzle második utolsó része az, hogy miként lehet jó kezdőbetűt szerezni. becslés, és a rövid válasz az, hogy a legjobb módszer a táblázatkeresés használata. Még egy szerény méretű asztal is, mivel csak ilyen kis tartományban keresünk négyzetgyökereket, meglehetősen hatékony.
A puzzle utolsó darabja: Honnan tudhatjuk, ha végeztünk iterálás? Erre pedig az a válasz, hogy tudjuk az általunk használt számok pontosságát, és hogy mennyire jó a kezdeti becslés. Ebből ki tudjuk dolgozni az előre szükséges maximális iterációk számát. Tehát valójában nem hurkolunk, mint olyan, csak rögzített számú alkalommal végezzük az iterációt.