| Uutiset | Koodikirjasto | Wiki | Keskustelut | FAQ | Info |
Pituus (etäisyys)egaga 22.04.02 21:49 Laskee nopeasti pisteiden (x, y) ja (0, 0) välisen etäisyyden
/* ______________________________________________________________________________________________________ Välimatkan - tai pituuden - laskeminen ilman pythagoraan lausetta pisteestä (0, 0) -> (x, y), kun x>0 ja y>0. HUOM! x:n ja y:n sopivuutta ei tarkisteta algoritmissa. Likimääräisen algoritmin virheellisyys on - kokemuksen perusteella - korkeintaan 1.2 % Alla oleva algoritmi on hyödyllinen esimerkiksi sellaisissa peleissä, jossa tarkkuuden ei tarvitse olla äärimmäisen tarkka. Algoritmini on paljon nopeampi kuin sqrt():n käyttö pythagoraan menetelmässä, varsinkin, kun se on käännetty optimointiasetuksien kanssa. Itse asiassa algoritmini on melkein yhtä nopea kuin Andre LaMothen Inside Peliohjelmointi -kirjan lähdekoodeissa oleva bittioperaatioita käyttävä versio ja omani on paljon LaMothen vastaavaa tarkempi. Menetelmän kuvaus: Lasketaan yhteen suurin kateetti ja lisäys, joka tulee seuraavasti: Lähdetään pidemmän kateetin kulmasta hypotenuusaa pitkin ja kuljetaan pidemmän kateetin pituuden verran. Sitten vain piirretään siihen kohtaan hypotenuusalle normaali ja katsotaan, missä pisteessä normaali leikkaa pidemmän kateetin jatketun janan. Tämän pisteen x-koordinaatti (y-koordinaatti = 0) on likimääräisesti hypotenuusan pituus. MUTTA, koska tämä yllä mainittu systeemi ei onnistu ilmeisesti ilman trigonometristen funktioiden käänteisfunktioita (arkuksia), tein algoritmin hiukan eri tavalla..Huomasin nimittäin, että normaali leikkaa lyhyemmän kateetin noin puolivälissä. Laitoinkin uuden normaalin kulkemaan lyhyemmän kateetin puoliväliä alempaa (siitä tulee kerroin 0.429), ja leikkauskohta jatketun pidemmän kateetin kanssa on suurinpiirtein hypotenuusan pituus eli haluttu etäisyys. Toivottavasti en hämännyt pitkällä selostuksellani liikaa, sillä algoritmi on oikeasti hyvin yksinkertainen mutta tehokas :). Kääntäminen gcc:llä: gcc -o pituus.exe pituus.cc -liostream Copyright 2002, Henrik Huttunen a.k.a. egaga ______________________________________________________________________________________________________ */ #include <fstream.h> #include <math.h> //Laskee (0, 0) ja (x, y) välimatkan pituuden (long) // ~1% virhemarginaali! long Pituus2Dl(const long &x, const long &y){ long min, max; //Laskee suurimman ja pienimmän kahdesta arvosta if(x > y){ max = x; min = y; }else{ max = y; min = x; } //kaava: max + kerroin * min * min / max long temp = ((min * min) * 429) / (1000 * max); return ( temp + max ); } //Laskee (0, 0) ja (x, y) välimatkan pituuden (float) // ~1% virhemarginaali! Suurin virhe - joka löydetty - ~1.05% (kerroin = 0.429) float Pituus2Df(const float &x, const float &y){ float min, max; //Laskee suurimman ja pienimmän kahdesta arvosta if(x > y){ max = x; min = y; }else{ max = y; min = x; } float temp = 0.429 * min * min / max; return ( temp + max ); } int main(){ cout << "Alku.." << endl; ofstream avaa("tulos.txt"); if(avaa.fail()) exit(1); avaa << "_________________________________________________________________________________________" << endl; avaa << " Välimatkan laskeminen ilman pythagoraan lausetta pisteestä (0, 0) -> (x, y)" << endl; avaa << " Likimääräisen algoritmin virheellisyys on - kokemuksen perusteella - korkeintaan 1.2 %" << endl; avaa << " Copyright 2002, Henrik Huttunen a.k.a. eGaga" << endl; avaa << "_________________________________________________________________________________________" << endl << endl; long tx, ty; float oikea, apu; for(tx=10;tx<=1000;tx+=50){ for(ty=10;ty<=1000;ty+=50){ oikea= sqrt(tx*tx+ty*ty); avaa << endl << "____________________________________________________________________________" << endl; avaa << "············································································" << endl; avaa << " (X, Y) = (" << tx << ", " << ty << ")" << endl; avaa << "____________________________________________________________________________" << endl; avaa << "············································································" << endl << endl; avaa << oikea << " <--- OIKEA tulos" << endl; apu=Pituus2Df(tx, ty); //float avaa << apu << " <--- likimääräinen float tulos, virheprosentti: " << 100 * fabs((apu - oikea)) / oikea << "%" << endl; apu=(float)Pituus2Dl(tx, ty); //long avaa << apu << " <--- likimääräinen long tulos, virheprosentti: " << 100 * abs((apu - oikea)) / oikea << "%" << endl; } } avaa.close(); cout << "Loppu.." << endl; return 0; } Sharlin 19:58 18.4.03 Hmm, kiintoisaa. Voisikohan tuota yleistää kolmanteen ulottuvuuteen helpostikin? egaga 08:35 23.4.03 Enpäs ole tullut ajatelleeksi sitä. Pitääpäs pohtia, jos kesällä vaikka huvittaisi. Niin ja tuossa koodissahan puuttuu tarkistus jos y = 0. En vain viitsinyt laittaa sitä hidastamaan :). egaga 08:39 23.4.03 Niin, ja tietenkin x>0 ja y>0. Apina 23:51 14.10.03 "..Tämän pisteen x-koordinaatti (y-koordinaatti = 0) on likimääräisesti hypot.."? Sehän on itse asiassa tasan hypotenuusan pituus. Kolmanteen ulottuvuuteen tuon saisi yleistettyä esim. näin: float Pituus3Df(float a,float b,float c) {return(Pituus2Df(a,Pituus2Df(b,c)));} Tuossa hieman viritelty versio: float p2d(float a,float b) { if(a<0)a=-a; if(b<0)b=-b; // a,b<0 ? if(a<b){float c = a; a = b; b = c;} if(a==0) // Tai esim. a<epsilon return(0); return(0.429*b*b/a+a); } kamistar 17:03 6.12.04 joku voisi sanoa laskee (x, y) ja origon välisen etäisyyden moshe 17:55 28.2.06 jännä : ) en kyllä oikein tajua miten toi toimii... moshe 17:23 2.3.06 nyt mä tajusin : ) (c = hypotenuusa, a = pitempi kateetti, b = lyhyempi kateetti) c = a + (0.429b² / a) c² = a² + 0.858b² + (0.184b^4 / a²) joka muistuttaa aikasen paljon pytagoraan lausetta (toi merkki on sitten potenssiin kaksi jos se ei näy teillä) |
![]() Haku
|