ZER DAKIDAN: Taylor algoritmoa aplikatuz kosinua eta sinua kalkulatzeko gai naiz, sarrerako angelua txikia denean. ZER IKASIKO DUDAN: Taylor algoritmoa aplikatuz kosinua eta sinua kalkulatzen ikasiko dut, sarrerako angelua edozein delarik. |
Ariketa 41 | Taylor azpiprogramaz (angelu txikietarako) blog-artikuluan ikusi dugu Taylor metodoa nola aplikatzen zaion 0 eta Π/2 artean dagoen sarrerako x angelu bati. Baina eta edozein angelu sartuko bagenu? Ikusitako programak ondo ibiliko lirateke? Kalkulu ahulena zein izan daiteke?
Ariketa 41 | Taylor azpiprogramaz (angelu txikietarako) artikuluko programa aldatzen baduzu sarrerako datua 0.0 gradu eta 360.0 gradu artekoa izan dadin; ikusiko duzu nola 160 graduko angelu batekin ondo dabilela, baina 160.9 graduko angeluarekin programa ez dabilela ikusi dugu ere. Arazoa faktorialaren kalkulu honetan dago:
// faktoriala kalkulatzeko funtzioa, emaitza long in long int liFaktoriala(int iMuga) { long int liMetagailua = 1; int i; for (i = 1; i <= iMuga; i++) { liMetagailua *= i; } return liMetagailua; }Faktorialaren kalkulua ondo dago. Baina iMuga datua handia bada, gerta daiteke liMetatua handiegia izatea longint datu-motarako eta orduan funtzioaren emaitza desegokia izango litzateke.
Izan ere, goiko funtzio horretan, faktoriala lortzean emaitza longint datu-motako aldagai batean gordetzen da, eta angelu handiekin faktorialaren balioak longint datu-motak duen muga gainditzen du. Horregatik, 0.0 gradu eta 360.0 gradu arteko angeluekin lan egin ahal izateko, faktorialaren funtzioa aldatuko dugu bere emaitza float datu-motakoa edo double datu-motakoa izan dadin.
// faktoriala kalkulatzeko funtzioa, emaitza double double dbFaktoriala(int iMuga) { double dbMetagailua = 1.0; int i; for (i = 1; i <= iMuga; i++) { dbMetagailua *= i; } return dbMetagailua; }
Sarrerako angelua oso handia bada, esate baterako 98765.9 graduko angelua sartuko bagenu, hurrengo moldaketa aplikatuko genioke:
Datua den 98765.9 gradu zati 360 egin ondoren, 98765.9/360 eta zatiketaren hondarrarekin geratuko ginateke bere kosinua kalkulatzeko. Zatiketa horren zatidurak adierazten du 98765.9 graduko angeluak zirkuluari zenbat bira ematen dizkion eta kosinuaren kalkulurako garrantzirik ez du. Ez-osoa den zenbaki baten atalak nola lortzen diren gogoratu:
dbHondarra = fmod(dbZatikizuna, dbZatitzailea); // edo...iGraduak = (int)fDatuaGradutan; // kopuru osoa lortu
fHondarra = fDatuaGradutan - iGraduak; // hamartarrak lortu
Doikuntza konstante bat izanik, Taylor serie bidezko hurbilpena dela eta, hauxe izan daiteke edozein angelurako kosinua kalkulatzen duen programa non AngeluaEgokitu() funtzioa balio erantsia da:
/* Ariketa-42_TaylorKosinua-EdozeinAngelu: kosinua Taylor bitartez. */ // Edozein angelu positibo teklatuz eman eta dagokion // kosinua kalkulatuko da Taylor segida jarraituz. // Erabilitako funtzioak eta itzulitako datu-mota: // liFaktoriala() --------> long int // fBerreketa() ----------> float // fKosinuaKalkulatu() ---> float // AngeluaEgokitu() ------> void (bi emaitzak parametroen bidez) #include <stdio.h> #include <math.h> // M_PI konstanterako #define EPSILON 0.0005 // bost hamarmilaren long int liFaktoriala(int iMuga); float fBerreketa(float fOinarria, int iAldiak); float fKosinuaKalkulatu(float fX); void AngeluaEgokitu(float fAng, float *fAngEgokitua, int *iKoadrantea); int main() { float fAng, fAngRadianetan, fX, fKosinua; int iKoadrantea; printf("Edozein angelu positiboaren kosinua kalkulatu %.4f prezisioarekin\n\n", rEPSILON); do { printf("Edozein angelu graduetan (adibidez, 1234 gradu): "); scanf("%f", &fAng); } while (fAng < 0.0); AngeluaEgokitu(fAng, &fX, &iKoadrantea); fAngRadianetan = fAng * 2 * M_PI / 360; fX = fX * 2 * M_PI / 360; printf("Angelua radianetan: %.5f\n", fX); fKosinua = fKosinuaKalkulatu(fX); if (iKoadrantea == 2 || iKoadrantea == 3) fKosinua = -fKosinua; printf("\nGure programaz lortutako kosinua[%.3f gradu] -----> %.5f\n", fAng, fKosinua); printf("cos() funtzioak ematen duena cos(%.3f gradu) -----> %.5f\n", fAng, cos(fAngRadianetan)); printf("\nRETURN tekla sakatu programatik irteteko\n"); getchar(); getchar(); return 0; } // berredura kalkulatzeko funtzioa float fBerreketa(float fOinarria, int iAldiak) { float fMetagailua = 1.0; int i; for (i = 0; i < iAldiak; i++) { fMetagailua *= fOinarria; } return fMetagailua; } // faktoriala kalkulatzeko funtzioa long int liFaktoriala(int iMuga) { long int liMetagailua = 1; int i; for (i = 1; i <= iMuga; i++) { liMetagailua *= i; } return liMetagailua; } // Taylor seriea erabiliz kosinua kalkulatzeko funtzioa float fKosinuaKalkulatu(float fX) { long int liFaktoreak; float fBerredura; float fZeinua; int iKont = 0; float fKosinua = 0.0; float fBatugai = 1.0; printf("\n%34s %20s %15s", "Faktoriala", "Berredura", "Batugaia"); printf("\n%34s %20s %15s", "----------", "---------", "--------"); printf("\n"); while (fabs(fBatugai) > rEPSILON) { fKosinua += fBatugai; iKont += 2; liFaktoreak = liFaktoriala(iKont); fBerredura = fBerreketa(fX, iKont); fZeinua = fBerreketa(-1, iKont / 2); fBatugai = fZeinua * fBerredura / liFaktoreak; printf("%2d. iterazioan =====> %12ld %20.5f %15.5f\n", iKont / 2, liFaktoreak, fBerredura, fBatugai); } return fKosinua; } // angelua egokitzeko funtzioa void AngeluaEgokitu(float fAng, float *fAngEgokitua, int *iKoadrantea) { float fHondar; int iBiraKopurua; printf("%.3f gradu egokitzen\n", fAng); *fAngEgokitua = fAng; printf("Sarrerako angelu positiboa = %.3f gradu\n", *fAngEgokitua); iBiraKopurua = (int)(*fAngEgokitua / 360); printf("Bira osoak = %d bira\n", iBiraKopurua); fHondar = (*fAngEgokitua / 360) - iBiraKopurua; printf("Bira-hondarra = %.3f bira\n", fHondar); *fAngEgokitua = 360 * fHondar; printf("Angelu egokitua = %.3f gradu\n", *fAngEgokitua); if (*fAngEgokitua >= 0 && *fAngEgokitua < 90) { printf("Angelu efektiboa = %.5f gradu (1. koadrantea)\n", *fAngEgokitua); *iKoadrantea = 1; } else if (*fAngEgokitua >= 90 && *fAngEgokitua < 180) { printf("Angelu efektiboa = %.5f gradu (2. koadrantea)\n", 180 - *fAngEgokitua); *fAngEgokitua = 180 - *fAngEgokitua; *iKoadrantea = 2; } else if (*fAngEgokitua >= 180 && *fAngEgokitua < 270) { printf("Angelu efektiboa = %.5f gradu (3. koadrantea)\n", *fAngEgokitua - 180); *fAngEgokitua = *fAngEgokitua - 180; *iKoadrantea = 3; } else if (*fAngEgokitua >= 270 && *fAngEgokitua < 360) { printf("Angelu efektiboa = %.5f gradu (4. koadrantea)\n", 360 - *fAngEgokitua); *fAngEgokitua = 360 - *fAngEgokitua; *iKoadrantea = 4; } }
|
iruzkinik ez:
Argitaratu iruzkina