2025(e)ko otsailaren 24(a), astelehena

Ariketa 42 | Taylor azpiprogramaz (edozein angelurako)

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


  • Ariketa-42_TaylorKosinua-EdozeinAngelu.cbp | main.c  


 

iruzkinik ez:

Argitaratu iruzkina