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

Ariketa 41 | Taylor azpiprogramaz (angelu txikietarako)

ZER DAKIDAN:
Agindu errepikakorretan do-while, while eta for ezagutzen ditut. Bestalde, funtzioak programatzen ikasi dut.



ZER IKASIKO DUDAN:
Kosinua eta sinua kalkulatzeko Taylor algoritmoa programatuko dut, lehenik angelu txikiekin lan eginez eta gero lehen bi koadranteko angeluekin lan eginez.


Brook Taylor


Brook Taylor britainiar matematikaria 1685ean jaio eta 1731ean hil zen. Zientziaren arazo asko aztertu zituen eta 1715. urtean idatzi zuen Methodus incrementorum directa et inversa, bere lan garrantzitsuena, non kalkulu diferentziala eta funtzio deribatua definitu zituen. Liburu berean agertu ziren Taylorren seriea, diferentzia finituen bidezko kalkulua, ekuazio diferentzialen soluzio bereziak, zatikako integrazio-metodoa, etab.

Taylor serie bidezko hurbilpena

Taylor seriea funtzio batek x puntuaren inguruan hartzen duen baliora hurbiltzeko erabil daiteke, seriearen batugai zenbait bakarrik erabiltzen direnean; era honetan, errore bat sortzen da, funtzioaren balioarekin bat datorren seriea ez baita modu osotuan garatzen:
(a=0 balioa denean, serieari MacLaurin serie deritzo)

Funtzio esponentzialaren eta logaritmikoaren serieak



Funtzio trigonometrikoen serieak




Non Bs Bernouilliren zenbakiak diren.

Ariketa hau egiteko, ikusitako hauek gogoratu Ariketa 23 | for: Faktorialen batukariak eta Ariketa 24 | for: Potentzien batukariak artikuluetako programak. Klikatu irudi honen gainean eta grafikoki ikusiko duzu Taylor polinomioa kosinu funtzioarentzat:




Angelu baten kosinua Taylor-ren arabera honela kalkula daiteke:
Non x radianetan emaniko angelua den.

Programa bat idatzi kosinua kalkulatuko duena aurreko segidaren N batugai erabiliz. Batugaien N kopurua ez da ezaguna, batugaiak aintzat hartuko dira azken batugaiaren balio absolutua 0.00001 baino txikiagoa izan arte adibidez (doikuntza hori teklatuaren bitartez emango du programaren erabiltzaileak, edo bestela balio konstante bat izan dadila).

Algoritmoa:

  1. Erabiliko den fDoikuntza prezisioa teklatuz irakurri (edo konstante ezagun bat izan dadila)
  2. Lehenego koadranteko fAng angelua graduetan, teklatuz irakurri
  3. Lehenego koadranteko fAng angelua radianetara igaro fX lortuz
  4. fX angeluari dagokion fKos kosinua lortu Taylor bitartez (azken batugaia fDoikuntza baino txikiagoa)
  5. Taylor bitartez lortu den fKos emaitza eta cos(fX) balioa pantailan erakutsi eta bi balioak elkar alderatu


Demagun lehen kasu honetan batukaria kalkulatzen duen azpiprogramak emaitza bakarra itzuli behar duela, kosinua. Hori dela eta, funtzio baten bitartez programatuko dugu. Diogunez, azpiprograma hori funtzio bat izango da bere prototipoa hau delarik:
float fKosinuaKalkulatu(float fX);

Sarrera: fX radianak (teklatuz irakurritako rAngelua graduak radianetara igarota)
Irteera: float, emandako angeluari dagokion kosinua Taylor bitartez

Hauxe izan daiteke lehen bertsioaren programa:

/* Ariketa-41a1_TaylorKosinua_1_koadrantea: kosinua Taylor bitartez. */

// 1. koadranteko angelu bat teklatuz eman eta dagokion kosinua
// kalkulatuko da Taylor segida jarraituz.

// Erabilitako funtzioak eta itzulitako datu-motak:
//   liFaktoriala() --------> long int
//   fBerreketa() ----------> float
//   fKosinuaKalkulatu() ---> float

#include <stdio.h>
#include <math.h>    // M_PI konstanterako

#define EPSILON 0.0005  // bost hamarmilaren

float fBerreketa(float fOinarria, int iAldiak);
long int liFaktoriala(int iMuga);
float fKosinuaKalkulatu(float fX);


int main()
{
    float fAng, fX, fKosinua;

    printf("1. koadranteko angelu baten kosinua kalkulatu %.4f prezisioarekin\n\n", EPSILON);

    do
    {
        printf("1. koadranteko angelua graduetan: ");
        scanf("%f", &fAng);
    } while (fAng < 0.0 || fAng >= 90.0);

    fX = fAng * 2 * M_PI / 360; // graduak radianetara bihurtu
    printf("Angelua radianetan: %8.5f\n", fX);

    fKosinua = fKosinuaKalkulatu(fX);

    printf("\n");
    printf("Gure programaz lortutako kosinua[%.3f gradu] -----> %7.5f\n", fAng, fKosinua);
    printf("cos() funtzioak ematen duena cos(%.3f gradu) -----> %7.5f\n", fAng, cos(fX));

    printf("\nRETURN tekla sakatu programatik irteteko\n");
    getchar();
    return 0;
}


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

// kosinua kalkulatzeko funtzioa Taylor seriea erabiliz
float fKosinuaKalkulatu(float fX)
{
    int iKont = 0;
    float fKosinua = 0.0;
    float fBatugai = 1.0;
    long int liFaktoreak;
    float fBerredura;
    float fZeinua;

    while (fabs(fBatugai) > EPSILON)
    {
        fKosinua += fBatugai;
        iKont += 2;

        liFaktoreak = liFaktoriala(iKont);
        fBerredura = fBerreketa(fX, iKont);
        fZeinua = fBerreketa(-1, iKont / 2);

        fBatugai = fZeinua * fBerredura / liFaktoreak;
        printf("%d. iterazioan, batugaia ===> %8.5f, aldea ===> %8.5f\n", iKont / 2, fBatugai, fabs(fabs(fBatugai) - EPSILON));
    }
    return fKosinua;
}
Programaren lehen hurbilketa honek fX sarrerako angelua 0 eta Π/2 artekoa izan dadila. Gero, programa ongi dabilenean kodifikazioa aberastu edozein koadranteko angelurako, hau da sarrerako fX angelua 0 eta artekoa izan daitekeela. Amaitzeko, programa osatu edozein angelurako, hots, sarrerako fX angelua baino handiagoa denean ere, laguntza hemen: Ariketa 42 | Taylor azpiprogramaz (edozein angelurako).


Demagun orain bigarren bertsio honetan aldaketa bat egingo dugula: programa nagusiak beste emaitza bat agertu behar duela ere (iterazioen kopurua). Beraz, kosinua kalkulatzeko metodo bera erabiliko dugu baina azpiprogramak itzuli beharko dituen emaitzak bi izango dira:
  1. Kosinuaren balioa, eta horrez gain
  2. Zenbat iteraziotan lortu den kalkulatzea
Kasu honetan batukaria kalkulatzen duen azpiprogramak bi emaitza itzuli behar dituelako ezingo da funtzioaren return bitartez biak kanporatu. Funtzio honek parametroak erabiliko ditu emaitzak kanporatzeko, bere prototipoa hau izango da:
void KosinuaKalkulatu(float fX, float *fKosinua, int *iIterazioKopurua);

 Sarrera: rX angelua radianetan (gogoratu bertsio honetan doikuntza konstante bat dela)
 Irteera: fKosinua kosinuaren kalkulua
 Irteera: iIterazioKopurua iterazioen kopurua

Hauxe da bigarren bertsioaren programa:

/* Ariketa-41a2_TaylorKosinua_1_koadrantea: kosinua Taylor bitartez. */

// 1. koadranteko angelu bat teklatuz eman eta dagokion kosinua
// kalkulatuko da Taylor segida jarraituz.

// Erabilitako funtzioak eta itzulitako datu-motak:
//   liFaktoriala() -------> long int
//   fBerreketa() ---------> float
//   KosinuaKalkulatu() ---> void (bi emaitzak parametroen bidez)

#include <stdio.h>
#include <math.h>    // M_PI konstanterako

#define EPSILON 0.0005  // bost hamarmilaren

float fBerreketa(float fOinarria, int iAldiak);
long int liFaktoriala(int iMuga);
void KosinuaKalkulatu(float fX, float *fKosinua, int *iIterazioKopurua);


int main()
{
    float fAng, fX, fKosinua;
    int iIterazioKopurua;

    printf("1. koadranteko angelu baten kosinua kalkulatu %.4f prezisioarekin\n\n", EPSILON);

    do
    {
        printf("Lehenengo koadranteko angelua graduetan: ");
        scanf("%f", &fAng);
    } while (fAng < 0.0 || fAng > 90.0);

    fX = fAng * 2 * M_PI / 360.0; // graduak radianetara bihurtu

    KosinuaKalkulatu(fX, &fKosinua, &iIterazioKopurua);

    printf("\nKalkuluaren iterazioen kopurua (iIterazioKopurua) ----> %d\n", iIterazioKopurua);
    printf("Gure programaz lortutako kosinua[%.3f gradu] -------> %.5f\n", fAng, fKosinua);
    printf("cos() funtzioak ematen duena cos(%.3f gradu) -------> %.5f\n", fAng, cos(fX));

    printf("\nRETURN tekla sakatu programatik irteteko\n");
    getchar();

    return 0;
}


// fOinarria^iAldiak kalkulatzeko funtzioa
float fBerreketa(float fOinarria, int iAldiak)
{
    float fMetagailua = 1.0;
    int i;

    for (i = 0; i < iAldiak; i++)
    {
        fMetagailua *= fOinarria;
    }
    return fMetagailua;
}


// iMuga! kalkulatzeko funtzioa
long int liFaktoriala(int iMuga)
{
    long int liMetagailua = 1;
    int i;

    for (i = 1; i <= iMuga; i++)
    {
        liMetagailua *= i;
    }
    return liMetagailua;
}


// kosinua kalkulatzeko funtzioa Taylor seriea erabiliz
void KosinuaKalkulatu(float fX, float *fKosinua, int *iIterazioKopurua)
{
    int iKont = 0;
    *fKosinua = 0.0;
    float fBatugai = 1.0;
    long int liFaktoreak;
    float fBerredura;
    float fZeinua;

    while (fabs(fBatugai) > EPSILON)
    {
        *fKosinua += fBatugai;
        iKont += 2;

        liFaktoreak = liFaktoriala(iKont); // faktorialaren deia
        fBerredura = fBerreketa(fX, iKont);  // berreketaren deia
        fZeinua = fBerreketa(-1, iKont / 2); // zeinua kalkulatzeko

        fBatugai = fZeinua * fBerredura / liFaktoreak;
        printf("%d. iterazioan, batugaia ===> %8.5f, aldea ===> %7.5f\n", iKont / 2, fBatugai, fabs(fabs(fBatugai) - EPSILON));
    }

    *iIterazioKopurua = iKont / 2;
}
Programaren bigarren bertsio honetan jarraituko dugu fX sarrerako angelua 0 eta Π/2 artekoa izaten. Gero, 90 graduraino ongi dabilenean kodifikazioa aberastu edozein koadranteko angelurako, hau da sarrerako fX angelua 0 eta artekoa izan daitekeela. Amaitzeko, edozein angelurako programa osatu, hots, sarrerako fX angelua baino handiagoa denean ere, laguntza hemen: Ariketa 42 | Taylor azpiprogramaz (edozein angelurako).

Lehen eta bigarren bertsio hauekin erdibideko soluzio bat programa daiteke. Alegia, programaren bi emaitzetatik bat return aginduaren bitartez itzuli eta beste emaitza irteerako parametro bezala kanporatzea. Horrela planteaturiko funtzioari bi prototipo hauek dagozkio:

float fKosinuaKalkulatu(float fX, int *iIterazioKopurua);

Sarrera: fX radianak (teklatuz irakurritako rAngelua graduak radianetara igarota)
Irteera: float, emandako angeluari dagokion kosinua Taylor bitartez
Irteera: iIterazioKopurua Taylor bitartez kosinua lortzeko behar izan diren iterazioak

Bigarren aukeran return bitartez iterazioak itzultzun ditu funtzioak:

int fKosinuaKalkulatu(float fX, float *fKosinua);

Sarrera: fX radianak (teklatuz irakurritako rAngelua graduak radianetara igarota)
Irteera: fKosinua angeluari dagokion kosinua Taylor bitartez
Irteera: int, Taylor bitartez kosinua kalkulatzeko behar izan diren iterazioak



Programaren hirugarren bertsio honek fX sarrerako angelua 0 eta Π artekoa izan dadila. Ikus daiteke 160.8 graduko angeluarekin programa ondo dabilela, baina 160.9 graduko angeluarekin programa txarto dabilela. Beraz, sarrerako x angelua edozein izan dadin programa berezitu bat idazte komeni zaigu, hauxe: Ariketa 42 | Taylor azpiprogramaz (edozein angelurako).

Hauxe da hirugarren bertsioaren programa:

/* Ariketa-41c_TaylorKosinua_1-2_koadranteak: kosinua Taylor bitartez. */

// 1. eta 2. koadranteetako angelu bat teklatuz eman eta 
// dagokion kosinua kalkulatuko da Taylor segida jarraituz.

// Erabilitako funtzioak eta itzulitako datu-motak:
//   liFaktoriala() --------> long int
//   fBerreketa() ----------> float
//   fKosinuaKalkulatu() ---> float

#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);


int main()
{
    float fAng, fX, fKosinua;

    printf("Lehen bi koadranteetako angelu baten kosinua kalkulatu %0.4f prezisioarekin\n", EPSILON);
    printf("KONTUZ! Angeluak 160 gradu baino gehiago balio badu faktorialak alde egiten du\n\n");

    do {
        printf("0 eta 180 arteko angelua graduetan: ");
        scanf("%f", &fAng);
    } while (fAng < 0.0 || fAng >= 180.0);

    fX = fAng * 2 * M_PI / 360; // Graduak radianetara bihurtu
    printf("Angelua radianetan: %.5f\n", fX);

    fKosinua = fKosinuaKalkulatu(fX);

    printf("\nGure programaz lortutako kosinua[%.3f gradu] -----> %.5f\n", fAng, fKosinua);
    printf("cos() funtzioak ematen duena cos(%.3f gradu) -----> %.5f\n", fAng, cos(fX));

    printf("\nRETURN tekla sakatu programatik irteteko\n");
    getchar();
    return 0;
}


// faktoriala kalkulatzeko funtzioa
long int liFaktoriala(int iMuga)
{
    long int liMetagailua = 1;
    int i;

    for (i = 1; i <= iMuga; i++)
    {
        liMetagailua *= i;
    }
    return liMetagailua;
}


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


// Taylor seriea erabiliz kosinua kalkulatzeko funtzioa
float fKosinuaKalkulatu(float fX)
{
    int iKont = 0;
    float fKosinua = 0.0;
    float fBatugai = 1.0;
    long int liFaktoreak;
    float fBerredura;
    float fZeinua;

    printf("\nKONTUZ!!! 160 gradu baino angelu handiagoekin faktorialak alde egiten du\n\n");
    printf("%34s %20s %15s\n", "Faktoriala", "Berredura", "Batugaia");
    printf("%34s %20s %15s\n", "----------", "---------", "--------");

    while (fabs(fBatugai) > EPSILON)
    {
        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;
}







  • Ariketa-41a1_TaylorKosinua_1_koadrantea.cbp | main.c  
  • Ariketa-41a2_TaylorKosinua_1_koadrantea.cbp | main.c  
  • Ariketa-41b1_TaylorSinua_1_koadrantea.cbp | main.c       (do-while)
  • Ariketa-41b2_TaylorSinua_1_koadrantea.cbp | main.c       (while)
  • Ariketa-41c_TaylorKosinua_1-2_koadranteak.cbp | main.c  


 

iruzkinik ez:

Argitaratu iruzkina