Jakolalgoritmi on algoritmi , joka laskee kahdelle annetulle kokonaisluvulle ja niiden osamäärän ja/tai jäännöksen jaon tuloksen jäännöksellä . Osa algoritmeista on suunniteltu manuaalisiin laskelmiin, osa on toteutettu digitaalisissa piireissä ja ohjelmistoissa.
Jakoalgoritmit jaetaan kahteen laajaan luokkaan: hidas jako ja nopea jako. Hidas jako-algoritmit tuottavat yhden luvun tuloksesta iteraatiota kohden. Esimerkkejä hitaasta jaosta ovat jakoalgoritmit , joissa on palautus , ei palautusta ja SRT . Nopeat jakomenetelmät alkavat approksimoimalla lopullinen osamäärä ja tuottavat kaksi kertaa niin monta numeroa lopullisessa tuloksessa jokaisella iteraatiolla. Newton-Rapson- ja Goldschmidt - algoritmit kuuluvat tähän luokkaan.
Näiden algoritmien muunnelmat mahdollistavat nopeiden kertolaskualgoritmien käytön . Tämän seurauksena suurilla kokonaisluvuilla jakolaskuon tarvittava laskenta-aika on sama (vakiokertoimeen asti) kuin kertolaskussa tarvittava aika, riippumatta siitä, kumpaa listatuista algoritmeista ei käytetä.
Keskustelussa käytetään merkintää missä
ovat syötetyt numerot ja
ovat tuotos.
Yksinkertaisin algoritmi, joka on historiallisesti rakennettu suurimpaan yhteisen jakaja - algoritmiin ja joka on esitetty Euclidin Principiassa , kirjan VII lauseessa 1, löytää kahden positiivisen kokonaisluvun jaon loppuosan käyttämällä vain vähennyslaskua ja vertailua:
R : = N , kun taas R >= D do R : = R − D - pään palautus RTodiste siitä, että osamäärä ja jäännös ovat olemassa ja ovat ainutlaatuisia (kuvattu artikkelissa Jako jäännösjäännöksellä ), antaa täydellisen jakoalgoritmin, joka perustuu yhteen-, vähennyksiin ja vertailuihin:
funktio jako ( N , D ) jos D = 0 niin virhe ( DivisionByZero ) loppu jos D < 0 niin ( Q , R ) : = jako ( N , − D ); palauttaa ( − Q , R ) lopeta jos N < 0 sitten ( Q , R ) : = jakaa ( − N , D ) jos R = 0 niin palauttaa ( − Q , 0 ) muuten palauttaa ( − Q − 1 , D − R ) ) loppu loppu -- Tässä N >= 0 ja D >= 0 palauttaa jako_allekirjoittamaton ( N , D ) loppu funktio divide_signed ( N , D ) Q : = 0 ; R : = N kun taas R >= D do Q : = Q + 1 R : = R − D loppu paluu ( Q , R ) loppuTämä menettely antaa aina . Koska algoritmi on hyvin yksinkertainen, se vaatii vaiheita ja on siksi eksponentiaalisesti hitaampi kuin algoritmit, kuten pitkäjako. Algoritmi on hyödyllinen, jos (askeleita) tiedetään olevan vähän (riippuen lähtömäärästä).
Pitkä jako on tavallinen moninumeroinen desimaalilukualgoritmi, jota käytetään jakamiseen kynällä ja paperilla. Se siirtyy asteittain vasemmalta oikealle osingosta vähentäen jakajan suurimman mahdollisen kerrannaisen kussakin vaiheessa. Kertoimesta tulee osamäärä, ja lopullisesta erotuksesta tulee jaon jäännös.
Kun algoritmia käytetään kannassa 2, tämä menetelmä muodostaa perustan luonnollisten lukujen jakamiselle jäännöksellä. Lyhyt jako on muunnelma pitkästä jaosta, joka sopii jakamiseen yhdellä numerolla. Vähennysalgoritmi , joka tunnetaan myös murtoosamäärämenetelmänä , on vähemmän tehokas jako sarakkeella, mutta on helpompi ymmärtää. Kun sallitaan suuremman kerrannaisen vähentäminen kuin jokaisessa vaiheessa, antaa enemmän vapautta luoda muunnelmia pitkästä jaosta.
Yllä oleva algoritmi, binääriversio tunnetusta jaosta pituusasteiksi , jakaa luvulla asettamalla osamäärän sisään ja lopun sisään . Kaikki arvot käsitellään etumerkittöminä kokonaislukuina.
jos D = 0 niin virhe ( DivisionByZeroException ) loppu -- Jako nollalla Q : = 0 -- Osamäärän ja jäännöksen alkuarvot ovat 0 R : = 0 i : = n − 1 .. 0 do -- Tässä n on numerobitti NR:ssä : = R << 1 - R:n siirto vasemmalle 1 bitillä R ( 0 ) : = N ( i ) - Aseta R:n vähiten merkitsevä bitti yhtä suureksi kuin jaon bitti i. jos R > = D niin R : = R − D Q ( i ) : = 1 loppupää EsimerkkiOta ( ) ja ( )
Vaihe 1 : Aseta R = 0 ja Q = 0
Vaihe 2 : Ota i = 3 (yksi vähemmän kuin N:n bittien määrä)
Vaihe 3 : R = 00 (siirrä vasemmalle 1)
Vaihe 4 : R = 01 (laita R (0 ) yhtä suuri kuin N(i))
Vaihe 5 : R < D, joten ohita komento
Vaihe 2 : Aseta i = 2
Vaihe 3 : R = 010
Vaihe 4 : R = 011
Vaihe 5 : R < D, ohita komento
Vaihe 2 : Aseta i = 1
Vaihe 3 : R = 0110
Vaihe 4 : R = 0110
Vaihe 5 : R >= D, komento suoritetaan
Vaihe 5b : R = 10 (R−D)
Vaihe 5c : Q = 10 (asetettu Q(i) yhtä kuin 1)
Vaihe 2 : Aseta i = 0
Vaihe 3 : R = 100
Vaihe 4 : R = 100
Vaihe 5 : R >= D, komento suoritetaan
Vaihe 5b : R = 0 (R−D)
Vaihe 5c : Q = 11 (asetettu Q(i) yhtä kuin 1)
Lopeta ( ) ja .
Kaikki hidas jakomenetelmät perustuvat standardiin toistuvuusrelaatioon [1]
missä:
Rekonstruktiivinen jako toimii liukulukujen murtoluvuilla ja riippuu oletuksesta .
Yksityiset numerot muodostetaan joukosta .
Peruspalautusalgoritmi binäärille (kanta 2):
R : = N D : = D << n -- R:n ja D:n on oltava kaksi kertaa pidempiä sanoja kuin N ja Q i : lle : = n − 1 .. 0 do -- Esimerkiksi 31..0 32-bittiselle R :lle : = 2 * R − D -- Koevähennys siirretystä arvosta (kahdella kertominen on binääritulkinnan muutos), jos R >= 0 sitten q ( i ) : = 1 -- Tulos on bitti 1 muuten q ( i ) : = 0 -- Tulos on bitti 0 R : = R + D -- Uusi osajäännös on yhtä suuri kuin (palautettu) siirretyn arvon loppupää -- Tässä: N = osinko, D = jakaja, n = bittien määrä, R = osajäännös, q(i) = osamäärän bitti #iAlgoritmin variantti, joka ei toteuta erikseen , säilyttää sen, eikä sitä siksi tarvitse lisätä takaisin tapauksessa .
Ei-palauttava jako käyttää joukkoa numeroita osamäärän numeroina sijasta . Algoritmi on monimutkaisempi, mutta sen etuna on chipeissä toteutettuna, että osamääräbittiä kohden on vain yksi päätös ja yksi yhteen-/vähennys. Vähennyksen jälkeen ei ole palautusvaihetta, mikä voi vähentää operaatioiden määrää puoleen ja antaa algoritmin toimia nopeammin [2] . Ei-palauttava jakoalgoritmi binäärisille (kanta 2) positiivisille luvuille:
R : = N D : = D << n -- R:n ja D:n on oltava kaksi kertaa pidempiä sanoja kuin N ja Q , jos i = n − 1 .. 0 do -- Esimerkiksi 31..0 32 bitille, jos R > = 0 sitten q [ i ] : = + 1 R : = 2 * R − D else q [ i ] : = − 1 R : = 2 * R + D loppu , jos loppu -- Tässä: N = osinko, D = jakaja, n = bittien määrä, R = osajäännös, q(i) = osamäärän bitti #i.Jos noudatamme tätä algoritmia, saamme osamäärän epästandardissa muodossa, joka koostuu luvuista -1 ja +1. Tämä lomake on muutettava binäärimuotoon. Esimerkki:
Osamäärän muuntaminen numeroiksi : | |
Alkaa: | |
1. Muodostamme positiivisen termin: | |
2. Muodostamme negatiivisen termin: | |
3. Vähennä: : | |
Negatiivinen termi esitetään binäärisenä käänteisenä , ei kahden komplementtina |
Jos −1-merkit tallennetaan nolliksi (0), kuten tavallisessa esityksessä, laskenta on triviaali : se suorittaa bittikohtaisen komplementin (bitti korvataan bitin komplementilla) alkuperäisestä .
Q : = Q − bitti . bnot ( Q ) -- Jos Q:n −1 numerot esitetään nollina.Lopuksi tällä algoritmilla lasketut osamäärät ovat aina parittomat ja jäännös R on sisällä . Esimerkiksi . Jotta se saadaan positiiviseen loppuosaan, otamme yhden palautusvaiheen sen jälkeen, kun se on pienennetty epätyypillisestä lomakkeesta vakiomuotoon:
jos R < 0 niin Q : = Q − 1 R : = R + D loppu josTodellinen loppuosa on R >> n. Kuten palautuksen yhteydessä, vähiten merkitseviä bittejä käytetään samassa järjestyksessä kuin osamääräbitit muodostetaan , ja on järkevää käyttää yhtä rekisterisiirtoa molemmille numeroille samanaikaisesti.
Jako on nimetty tekijöiden nimien ensimmäisten kirjainten mukaan (Sweeney, Robertson, Tocher). SRT-jako on suosittu jakomenetelmä monissa mikroprosessoreissa [3] [4] . Jakaminen on samanlainen kuin jakaminen ilman palautusta, mutta se käyttää osinkoon ja jakajaan perustuvaa hakutaulukkoa osamäärän määrittämiseen.
Merkittävin ero on, että yksityiselle käytetään redundanttia esitystä . Jos esimerkiksi SRT:n 4 kantajako on toteutettu, jokainen osamäärä valitaan viidestä mahdollisuudesta : . Tämän vuoksi osamäärän numeron valinnan ei tarvitse olla tarkka. Myöhemmin osamäärälukuja voidaan korjata. Esimerkiksi numeroparit ja ovat vastaavia, koska . Tämän toleranssin avulla voit valita osamäärän numerot perustuen vain osingon ja jakajan merkittävimpiin muutamaan bittiin sen sijaan, että vähentäisit koko pituutta. Tämä yksinkertaistaminen puolestaan mahdollistaa kantaluvun käytön luvuille, jotka ovat suurempia kuin 2.
Kuten ei-palauttavassa jaossa, viimeiset vaiheet ovat lukujen vähentäminen koko pituudelta, jotta saadaan osamäärän viimeinen bitti, ja osamäärän muuntaminen vakiobinääriksi.
Intel Pentium -suorittimien pahamaineinen kelluva jakovirhe johtui koodatusta hakutaulukosta. Viisi taulukon 1066 solusta jätettiin virheellisesti pois [5] [6] .
Newton–Rapson-jako käyttää Newtonin menetelmää luvun käänteisluvun selvittämiseen ja kertoo sen käänteisluvulla saadakseen tuloksena olevan osamäärän .
Newton-Rapson-jaon vaiheet:
Jotta voit käyttää Newtonin menetelmää luvun käänteisluvun löytämiseen , sinun on löydettävä funktio , jonka pisteessä on nolla . Ilmeisesti tämä funktio on , mutta Newton-Rapson-iteraatiot eivät ole onnistuneet sille, koska niitä ei voida suorittaa tietämättä luvun käänteislukua (lisäksi menetelmä yrittää laskea tarkan käänteisluvun yhdessä vaiheessa, eikä tee iteratiivisia parannuksia ). Toimiva funktio on se , jolle Newton-Rapson-iteraatio antaa
joka voidaan laskea käyttämällä vain kerto- ja vähennyslaskua tai kahta kerto- ja yhteenlaskua .
Laskennallisesta näkökulmasta lausekkeet ja eivät ole vastaavia. Saadaksesi 2n bitin tarkkuuden käyttämällä toista lauseketta, sinun on laskettava tulo väliltä ja kaksinkertaisella tarkkuudella määritettyyn tarkkuuteen ( n bittiä). Tulo sitä vastoin tarvitsee laskea vain n bitin tarkkuudella, koska ensimmäiset n bittiä (binääripisteen jälkeen) ovat nolla.
Jos virhe on määritelty , niin
Tämä neliövirhe kussakin iteraatiovaiheessa (niin sanottu Newton-Rapson-menetelmän neliöllinen konvergenssi ) saa aikaan sen, että tuloksen oikeiden numeroiden määrä noin kaksinkertaistuu jokaisessa iteraatiossa , ominaisuus, joka tulee erittäin tärkeäksi, kun havaitut luvut ovat monta numeroa.. Mutta se tarkoittaa myös sitä, että menetelmän alkuperäinen konvergenssi voi olla suhteellisen hidasta, varsinkin jos arvo on huonosti valittu.
Alkuarvion valinnan aliongelmassa on kätevää käyttää jakajan siirtoa siten, että se on välillä , samalla kun sovelletaan samaa siirtoa osinkoon , jotta osamäärä ei muutu. Sitten voidaan käyttää lomakkeessa olevaa lineaarista approksimaatiota
Newton-Rapson-menetelmän alustamiseksi. Tämän likiarvon maksimi absoluuttisen virheen minimoimiseksi välissä tulisi käyttää
Lineaariset approksimaatiokertoimet määritellään seuraavasti. Virheen itseisarvo on . Virheen maksimiabsoluuttisen arvon minimi määritetään Tšebyševin ekvivalenttivärähtelylauseen mukaan , jota sovelletaan . Paikallinen funktion minimi on kohdassa, jossa , jolla on ratkaisu . Tämän minimin funktiolla tulisi olla arvo, jolla on vastakkainen etumerkki suhteessa välin ääripisteisiin, nimittäin . Kaksi yhtälöä kahdessa tuntemattomassa antavat ainutlaatuisen ratkaisun ja , ja suurin virhe on . Tätä approksimaatiota käytettäessä alkuarvon virheen itseisarvo on pienempi kuin
On mahdollista muodostaa polynomi, jonka aste on suurempi kuin 1, laskemalla kertoimet Remez-algoritmin mukaan . Tällöin alkuperäinen approksimaatio vaatii enemmän laskentaa, joka voidaan kompensoida pienemmällä määrällä Newton–Rapson-iteraatioita.
Koska tämän menetelmän konvergenssi on täsmälleen neliöllinen, se on riittävä
vaiheet arvon laskemiseksi binääripaikkoihin asti. Tämä vastaa 3:a IEEE:n kaksinpelissä ja 4 nelinpelissä ja pidennetyssä nelinpelissä .
PseudokoodiSeuraava pseudokoodi laskee N :n ja D : n osamäärän P binäärinumeroon asti:
Ilmaise D missä (vakioliukulukuesitys) // heitetään arvoon 0,5 ja 1, mikä voidaan tehdä bittisiirrolla / vähentämällä eksponentti // ennalta lasketut vakiot samalla tarkkuudella kuin D- toistoajat // voidaan laskea ennakkoon kiinteään P- päätypalautukseenEsimerkiksi kaksinkertaisessa tarkkuudessa liukulukujaossa tämä menetelmä käyttää 10 kertolaskua, 9 yhteenlaskua ja 2 siirtoa.
Newton–Rapson-divisioonan muunnelmiaNewton-Rapson-jakomenetelmää voidaan muokata hieman nopeammaksi. Kun N ja D on siirretty siten, että D on välillä [0.5, 1.0], alustetaan
.Tämä on paras neliöllinen approksimaatio ja antaa absoluuttisen virhearvon enintään . Parametrit valitaan siten, että valitaan virhe, joka on yhtä suuri kuin ensimmäisen tyypin Chebyshev-polynomin kolmannen kertaluvun arvo . Kertoimet on laskettava etukäteen ja koodattava menetelmään.
Sitten silmukassa käytämme iteraatiota, joka nostaa virheen kuutioksi.
Jos silmukka suoritetaan, kunnes se lähestyy johtavaa bittiä, iteraatioiden määrä on enintään
joka on yhtä monta kertaa 99 kuutiota saada . Sitten
on yhtä suuri kuin osamäärä biteihin asti .
Korkeamman asteen polynomien käyttäminen alustuksissa tai iteraatioissa johtaa suorituskykyongelmiin, koska ylimääräisiä kertolaskuja olisi parempi käyttää lisäämään iteraatioita.
Goldschmidtin jako [7] (Robert Elliott Goldschmidt) käyttää iteratiivista prosessia, jossa osinko ja jakaja kerrotaan toistuvasti samalla kertoimella , joka valitaan siten, että jakaja konvergoi 1:een. Tämä saa osingon konvergoimaan osamäärään :
Goldschmidtin jaon vaiheet:
Oletetaan , että se on skaalattu arvoon , joista jokainen perustuu :
Kerrotaan osinko ja jakaja kertoimella ja saadaan:
Riittävän määrän iteraatioita jälkeen .
Goldschmidt-menetelmää käytetään AMD Athlon -prosessoreissa ja myöhemmin [8] [9] . Se tunnetaan myös nimellä Anderson Earle Goldschmidt Powers (AEGP) -algoritmi, ja se on toteutettu useissa IBM-prosessoreissa [10] [11] . Vaikka menetelmän konvergenssi on sama kuin Newton–Rapmon-toteutuksessa, yksi Goldschmidt-menetelmän eduista on, että kertoimet osoittajassa ja nimittäjässä voidaan tehdä rinnakkain [11] .
BinomiaalilauseGoldschmidtin menetelmää voidaan käyttää tekijöiden kanssa, jotka mahdollistavat yksinkertaistamisen Newtonin binomiaalilla . Oletetaan, että N/D kerrotaan potenssilla kaksi niin, että . Valitsemme ja . Tämä antaa
.Vaiheiden jälkeen nimittäjä voidaan pyöristää ylöspäin suhteellisella virheellä
,jonka suurin arvo on , mikä tarjoaa binäärinumeroiden vähimmäistarkkuuden .
Laitteistossa toteutettaviksi tarkoitetut menetelmät eivät tyypillisesti laske kokonaislukuja, joissa on tuhansia tai miljoonia desimaalilukuja, mikä on yleistä esimerkiksi kryptografian modulo - laskelmissa . Näille suurille lukuille tehokkaammat algoritmit muuntaa ongelman pieneen kertolaskumäärään, mikä voidaan tehdä asymptoottisesti tehokkailla kertolaskualgoritmeilla , kuten Karatsuban algoritmilla , Tum-Cookin kertolaskulla tai Schönhage-Strassenin algoritmilla . Tämän seurauksena jaon laskennallinen monimutkaisuus on samaa luokkaa (vakiolla kertomiseen asti) kuin kertolasku. Esimerkkejä ovat yllä kuvattu pelkistys Newtonin kertolaskuksi [12] sekä hieman nopeampi Bournickel-Ziegler-jako [13] , Baret ja Montgomeryn [14] algoritmit . Etenkin Newtonin menetelmä on tehokas skenaarioissa, joissa täytyy tehdä useita jakoja tietyllä luvulla, koska käänteisluvun alun löytämisen jälkeen kutakin kertolaskua varten tarvitaan vain yksi (pelkistetty) kertolasku.
Jakaminen vakiolla vastaa kertomista sen käänteisarvolla . Koska nimittäjä on vakio, myös käänteisluku on vakio . Sitten voit laskea arvon kerran ja laskelmien aikana teemme kertolaskua jakolaskua . Liukulukuaritmetiikassa käyttö aiheuttaa pienen ongelman liittyen koodin optimointiin [a]-kääntäjien toimesta , mutta kokonaislukuaritmetiikassa jäännös on aina nolla, mikäli .
Ei tarvitse käyttää täsmälleen , voit käyttää mitä tahansa arvoa , joka pienenee arvoon . Esimerkiksi, kun jaat kolmella, voit käyttää murtolukuja , tai . Siksi, kun potenssi on kaksi, jakoaskel voidaan vähentää nopeaksi siirroksi oikealle. Vaikutuksena laskeminen kuinka korvaa jakamisen kerto- ja siirrolla. Huomaa, että juuri tämä menettely on olennainen tässä, koska se johtaa nollaan.
Kuitenkin, jos on jo kahden potenssi, ei ole olemassa ja jotka täyttävät yllä olevat ehdot. Onneksi antaa kokonaislukuaritmetiikassa täsmälleen saman tuloksen kuin , vaikka ei olekaan täsmälleen yhtä suuri kuin , mutta "riittävän lähellä", joten approksimoinnin aiheuttama virhe on bitteissä, jotka poistuvat siirtotoiminnon jälkeen [15] [ 16 ] [17] [b]
Erityisenä esimerkkinä kiinteän pisteen aritmetiikasta 32-bittisten etumerkittömien kokonaislukujen tapauksessa jako kolmella voidaan korvata kertomalla luvulla , eli kertomalla luvulla 2863311531 ( heksadesimaali 0xAAAAAAAB), jota seuraa 33 bitin siirto oikealle. Arvo 2863311531 lasketaan muodossa ja pyöristetään ylöspäin. Vastaavasti jako 10:llä voidaan ilmaista kertomalla luvulla 3435973837 (0xCCCCCCD), jota seuraa jako (tai 35 bitin siirto oikealle) [19] . OEIS antaa vakiojonon kertolaskua varten muodossa A346495 ja oikealle siirrolle muodossa A346496 .
Yhteiselle -bittiselle etumerkittömälle kokonaislukujaolle, jossa jakaja ei ole kahden potenssi, seuraava identiteetti muuntaa jaon kahdeksi -bittiseksi yhteen-/vähennyslaskuksi, yhdeksi kertolaskuksi -bitti bittiluvuilla (jossa vain tuloksen korkea puoli käytetään), ja useita työvuoroja, esilaskentaa ja :
missä
Joissakin tapauksissa jako vakiolla voidaan tehdä jopa lyhyemmässä ajassa korvaamalla "vakiolla kertominen" sarjalla siirtymiä ja yhteen- tai vähennyslaskuja [20] . Erityisen kiinnostava on jako 10:llä, jonka tarkka osamäärä saadaan tarvittaessa jäännöksellä [21] .
Lukuteoreettiset algoritmit | |
---|---|
Yksinkertaisuustestit | |
Alkulukujen löytäminen | |
Faktorisointi | |
Diskreetti logaritmi | |
GCD:n löytäminen |
|
Modulo-aritmetiikka | |
Lukujen kerto- ja jakolasku | |
Neliöjuuren laskeminen |