int scanf(const char * formatukatea, argumentu1, argumentu2, ...);
Ezaguna zaigu scanf() funtzioa scanf(), lehen hurbilketa artikuluan azaldu zelako eta sarritan erabili dugulako. Badakigu scanf()funtzioa helburu orokorreko errutina dela eta teklatutik datua irakurtzeko ENTER tekla sakatu beharra dagoela.
ENTER tekla ASCII taulako 10. karakterea da eta ez du arazorik emanten scanf(), lehen hurbilketa artikuluan erakutsitako programetan datuak zenbakizkoak direlako. Baina, eta irakurri beharreko datua karaktere bat bada? Nola jokatzen du ENTER karaktereak?
Programa hau aztertu, non teklatuaren bufferra garbitzeko fflush(stdin) funtzioa erabili beharra dagoen. Nahi izanez gero, fflush(stdin) funtzioaren ordez getchar() funtzioa erabil daiteke.
/* SCANF_2-hurbilketa.cbp proiektua, scanf() funtzioaren bigarren hurbilketa: karaktereak. */
// Programa honetan scanf() funtzioa ikasiko dugu, karaktereekin lan eginez.
// Programa honetan hiru scanf() daude eta bakoitzak karaktere bana irakurtzen du.
// Ikusi teklatuaren bufferra garbitzen duen fflush(stdin) funtzioa behar dugula.
// Hiru fflush(stdin) deiak iruzkintzean hau gertatzen da:
// ------------------------------------------------------
// Lehen irakurketan: karakterea + ENTER, ondorioz karakterea 'cLetra1' aldagaian
// eta ENTER teklatuaren bufferrean geratzen da.
// Bigarren irakurketan: teklatuaren bufferreko ENTER karakterea 'cLetra2' aldagaian
// eta teklatuaren bufferra hutsik.
// Hirugarren irakurketan: karakterea + ENTER, ondorioz karakterea 'cLetra3' aldagaian
// eta ENTER teklatuaren bufferrean.
// Aurrekoa frogatzeko, karaktereen ordinalak pantailaratzen dira, non ENTER
// karakterearen ordinala 10 den.
// Hiru fflush(stdin) deiak indarrean direnean hau gertatzen da:
// ------------------------------------------------------------
// Lehen irakurketan: karakterea + ENTER, ondorioz karakterea 'cLetra1' aldagaian
// eta teklatuaren bufferrean geratu den ENTER karakterea galtzen da.
// Bigarren irakurketan: teklatuaren bufferreko ENTER karakterea 'cLetra2' aldagaian
// eta teklatuaren bufferrean geratu den ENTER karakterea galtzen da.
// Hirugarren irakurketan: karakterea + ENTER, ondorioz karakterea 'cLetra3' aldagaian
// eta teklatuaren bufferrean geratu den ENTER karakterea galtzen da.
// fflush(stdin) funtzioa ez dabil Mac eta Unix sisteman,
// bere ordez fpurge(stdin) erabili behar da.
#include <stdio.h>
int main()
{
char cLetra1, cLetra2, cLetra3;
printf("\n");
printf("Lehen karakterea eman (adib. 'A'): ");
scanf("%c", &cLetra1);
fflush(stdin); // froga egiteko agindu hau iruzkindu
printf("Bigarren karakterea eman (adib. 'B'): ");
scanf("%c", &cLetra2);
fflush(stdin);
printf("Hirugarren karakterea eman (adib. 'C'): ");
scanf("%c", &cLetra3);
fflush(stdin);
printf("Balioak: '%c', '%c' eta '%c'.\n", cLetra1, cLetra2, cLetra3);
printf("Balioak: '%d', '%d' eta '%d'.\n", cLetra1, cLetra2, cLetra3);
return 0;
}
Hauxe da aurreko programak eskaintzen duen irteera 39. lerroko fflush(stdin) funtzioa iruzkindu ondoren, proiektua konpilatu eta egikaratu egiten bada:
Lehenscanf()funtzioanAkaraktereacLetra1aldagaian. Bigarrenscanf()funtzioan bufferreko ENTER karaktereacLetra2aldagaian. Hirugarrenscanf()funtzioanCkaraktereacLetra3aldagaian.
Goiko irudiaren azalpena:
Lehen scanf() funtzioaren bitarteko irakurketan A karakterea eman da eta ENTER karakterea sartuz bukatzen da; ondorioz, A karakterea cLetra1 aldagaian gordetzen da eta ENTER karakterea (sistema hamaseitarrean \x10 segidaz adieraz daitekeen karakterea, bere ASCII taulako posizioa 10 baita) teklatuaren buffer delako memoria zatian kokatzen da.
Bigarren scanf() funtzioak bufferrean dagoen ENTER karakterea hartu eta cLetra2 aldagaian gordez aurrera egiten du erabiltzaileari itxaron gabe. Ondorioz, bufferra dagoeneko hutsik dago, baina ez balego fflush() funtzioak hustuko luke, horregatik...
Hirugarren scanf() funtzioak bufferra hutsik aurkitzen du eta itxaron egiten du erabiltzaileak daturen bat sartu arte cLetra3 aldagairako, irudian erabiltzaileak C karakterea eman du eta ENTER karakterearekin bukatzen du datuaren sartzea (ENTER karaktere hau teklatuaren buferretik kenduko du fflush() funtzioak).
ZER DAKIDAN: Funtzio batek sarreraren bat hartzen du eta emaitza bakar itzultzen du. Dagoeneko funtzio estandar hauek erabili ditut (denek math unitatea sartzea behar dute):
fabs()
sin(), cos() eta tan()
asin(), acos() eta atan()
sqrt()
pow()
ZER IKASIKO DUDAN: Funtzioekin jarraituz rand() funtzio estandarra ikasiko dut eta hori erabiltzeko srand() funtzio estandarra ikasiko dut. Funtzioekin aurrera eginez, log(), log2(), log10(), exp() eta modf() funtzioak ikasiko ditut ere.
Zerrenda honetan azpiprograma estandar batzuk deskribatzen dira, gogoratu #include <math.h> derrigorrezkoa dela:
double fabs(double x); // x zenbaki errealaren kopuruari dagokion balio absolutua kalkulatzen du
double sin(double x); // x angeluaren (radianetan neurtuta) sinua itzultzen du
double cos(double x); // x angeluaren (radianetan neurtuta) kosinua itzultzen du
double tan(double x); // x angeluaren tangentea itzultzen du
double asin(double x); // x angeluaren (-PI/2 eta +PI/2 tartekoa) arku sinua itzultzen du
double acos(double x); // x angeluaren (0.0 eta +PI/2 tartekoa) arku kosinua itzultzen du
double atan(double x); // x angeluaren (-PI/2 eta +PI/2 tartekoa) arku tangentea itzultzen du
double pow(double x, double y); // x zenbaki errealaren kopurua ber y kalkulatzen du
double sqrt(double x); // x erro karratuaren emaitza itzultzen du
double exp(double x); // e ber x kalkulatzen du
double log(double x); // logaritmo naturala itzultzen du
double log2(double x); // bi oinarriko logaritmoa itzultzen du
double log10(double x); // hamar oinarriko logaritmoa itzultzen du
double fmod(double dbZatikizu, double dbZatitzai); // zatikizuna eta zatitzailea emanik, zatiketa osoaren hondarra itzultzen du
double modf(double dbBalio, double *dbZatiOsoa); // dbBalio argumentua zati oso batean eta hamartar bestean bitan zatitzen du, eta bakoitzak argumentuaren zeinu bera du. Zati hamartarra da funtzioak itzultzen duena eta zati osoa double bat bezala gordetzen du dbZatiOsoa argumentuak adierazitako objektuan
Eta zerrenda honetan beste azpiprograma estandar batzuk deskribatzen dira, ez ahaztu #include <stdlib.h> derrigorrezkoa dela:
int abs(int x); // x zenbaki osoaren kopuruari dagokion balio absolutua kalkulatzen du
int rand(void); // zenbaki oso sasi-aleatoria kalkulatzen du 0tik RAND_MAX=2147483647 bitartean
// RAND_MAX inplementazioaren araberakoa da baina gutxienez RAND_MAX=32767
void srand(unsigned int iHazia); // iHazia argumentua sasi-ausazko zenbakien sekuentzia berri baterako hazi gisa
// erabiltzen du rand() funtzioak ondorengo deietan balioak itzultzeko
rand() funtzioak kopuru osoak itzultzen ditu, baina zenbaki erreal aleatorioak lor daitezke ere laster ikusiko dugun bezala.
rand() eta srand()
Zenbaki aleatorioak eskuratzeko rand() funtzio estandarra estandarra beharko dugu eta horrekin batera srand() funtzio estandarra ere.
Dado bat 3 aldiz jaurti dela simulatuko dugu. Dadoak 6 posibilitate ditu: 1, 2, 3, 4, 5 eta 6. Gure programak 3 jaurtiketa aleatorien emaitzak batuko ditu eta baturaren arabera mezu hau pantailaratuko du:
3 jaurtiketen baturak 13 edo gehiago balio badu, pantailaraketa Oso ondo izango da
3 jaurtiketen batura 10 eta 12 artekoa bada, pantailaraketa Nahiko ondo izango da
3 jaurtiketen batura 7 eta 9 artekoa bada, pantailaraketa Txarto izango da
3 jaurtiketen baturak 6 edo gutxiago balio badu, pantailaraketa Oso txarto izango da
Zenbaki osoekin jarraituz, kopuru aleatorioak 1 eta 6 artekoak izan ordez, 2 eta 4 bi mugen artekoak eskuratzeko horrela joko dugu:
/* Ariketa-19a1_FuntzioEstandarrak: zenbaki sasi-aleatorioak lortzen (kopuru osoak) */
// rand() ikasiko dugu, baina srand() funtzioarekin lotuta dago.
// Zenbaki aleatorioen segida lortzeko hazi bat behar da eta time() funtzioa erabiliko da NULL parametroarekin.
// rand() bitartez lortuko diren zenbaki aleatorioak kopuru osoak izango dira.
// Dado baten hiru jaurtiketa simulatuko da eta batura lortuz programak adieraziko digu
// jokaldia nolakoa izan den: oso txarra, txarra, ona ala oso ona.
#include <stdio.h> // printf() funtzioarako
#include <stdlib.h> // rand() eta srand() funtzioetarako
#include <math.h> // fmod() funtzioarako
#include <time.h> // time() funtzioarako
int main()
{
int iBatura = 0;
int iJaurtiketarenBalioa;
printf("\n");
printf("\n Dadoa hiru aldiz jaurti ondoren");
printf("\n -------------------------------");
srand(time(NULL)); // srand() zenbaki aleatorioak berriro hasiarazteko, hazia behar du
// Hazia, adibidez, time(NULL) funtzioa izan daiteke zeinek igarotako
// segundoak itzultzen ditu 1970-01-01 datatik hasita
iJaurtiketarenBalioa = rand(); // 0 eta RAND_MAX=32767 arteko balioa
iJaurtiketarenBalioa = iJaurtiketarenBalioa % 6 + 1; // 1 eta 6 arteko balioa
// edo iJaurtiketarenBalioa = fmod(iJaurtiketarenBalioa, 6) + 1; 1 eta 6 arteko balioa
printf("\n 1. jaurtiketan %d atera da", iJaurtiketarenBalioa);
iBatura = iBatura + iJaurtiketarenBalioa;
iJaurtiketarenBalioa = rand(); // 0 eta RAND_MAX=32767 arteko balioa
iJaurtiketarenBalioa = iJaurtiketarenBalioa % 6 + 1; // 1 eta 6 arteko balioa
// edo iJaurtiketarenBalioa = fmod(iJaurtiketarenBalioa, 6) + 1; 1 eta 6 arteko balioa
printf("\n 2. jaurtiketan %d atera da", iJaurtiketarenBalioa);
iBatura = iBatura + iJaurtiketarenBalioa;
iJaurtiketarenBalioa = rand(); // 0 eta RAND_MAX=32767 arteko balioa
iJaurtiketarenBalioa = iJaurtiketarenBalioa % 6 + 1; // 1 eta 6 arteko balioa
// edo iJaurtiketarenBalioa = fmod(iJaurtiketarenBalioa, 6) + 1; 1 eta 6 arteko balioa
printf("\n 3. jaurtiketan %d atera da", iJaurtiketarenBalioa);
iBatura = iBatura + iJaurtiketarenBalioa;
printf("\n");
switch(iBatura)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6: printf("\n OSO TXARTO hiru jaurtiketen batura %d izan delako", iBatura);
break;
case 7:
case 8:
case 9: printf("\n TXARTO hiru jaurtiketen batura %d izan delako", iBatura);
break;
case 10:
case 11:
case 12: printf("\n NAHIKO ONDO hiru jaurtiketen batura %d izan delako", iBatura);
break;
default: printf("\n OSO ONDO hiru jaurtiketen batura %d izan delako", iBatura);
break;
}
printf("\n\n");
return 0;
}
rand() eta srand()
Zenbaki osoekin jarraituz, kopuru aleatorioak 1 eta 6 artekoak izan ordez, 2 eta 4 bi mugen artekoak eskuratzeko horrela joko dugu:
/* Ariketa-19a2_FuntzioEstandarrak: zenbaki sasi-aleatorioak lortzen (kopuru osoak) */
// Ariketa-19a1_FuntzioEstandarrak bezalakoa, baina 2 eta 4 mugen arteko kopuruekin.
#include <stdio.h> // printf() funtzioarako
#include <stdlib.h> // rand() eta srand() funtzioetarako
#include <time.h> // time() funtzioarako
#define BEHEMUGA 2
#define GOIMUGA 4
int main()
{
int iKont;
printf("\n");
printf("\n Manipulatutako dadoa %d eta %d artean", BEHEMUGA, GOIMUGA);
printf("\n -----------------------------------");
srand(time(NULL)); // zenbaki aleatorioak hasiarazteko
for (int iKont = 1; iKont <= 10; iKont++)
{
// random zenbakiak GOIMUGA=4 eta BEHEMUGA=2 artekoak (biak barne)
// rand()%(GOIMUGA-BEHEMUGA+1) rand()%3 (0, 1 edo 2)
// rand()%(GOIMUGA-BEHEMUGA+1)+BEHEMUGA rand()%3+2 (2, 3 edo 4)
iJaurtiketarenBalioa = rand() % (GOIMUGA - BEHEMUGA + 1) + BEHEMUGA;
printf("\n %5d. jaurtiketan %d atera da", iKont, iJaurtiketarenBalioa);
}
printf("\n\n");
return 0;
}
Manipulatu den dadoaren programa honetan for agindu errepikakorra agertzen da. Aurrerago azalduko da modu xehean, baina orain jakin dezagun for aginduak balio duela ekintzak errepikatzeko kopuru jakin batean, adibidean ekinza 10 aldiz errepikatzen da.
rand() eta srand()
Zenbaki errealekin lan eginez, balio aleatorioak lortzen dituen programa
idatziko dugu. Ikusi dugun rand() funtzioak 0 eta RAND_MAX=32767 arteko kopuru osoa itzultzen duenez kode gehiago gehituko zaio programari zenbaki errealekin lan egiteko, zatiketa bat eta datu-mota beharketa bat. Honelaxe:
fZenbakia = (float)rand()/RAND_MAX; // 0.0 eta 0.999 arteko balioa
printf("fZenbakia = %f\n", fZenbakia);
Programa osoa hemen. Non lehen for aginduan 15 iterazio egiten diren 0 eta RAND_MAX=32767 arteko zenbaki sasi aleatorio osoak lortuz, eta bigarren for aginduan beste 15 iterazio egiten diren auzazko zenbaki sasi aleatorio osoak 0.0 eta 0.999 esparrura mugatuz:
/* Ariketa-19b1_FuntzioEstandarrak: zenbaki sasi-aleatorioak lortzen (kopuru errealak) */
// rand() ikasiko dugu, baina srand() funtzioarekin lotuta dago.
// Zenbaki aleatorioen segida lortzeko hazi bat behar da eta time() funtzioa erabiliko da
// NULL parametroarekin zeinek igarotako segundoak itzultzen ditu 1970-01-01 datatik hasita.
// rand() bitartez lortuko diren zenbaki aleatorioak 0 eta RAND_MAX=32767 arteko kopuru
// osoak izango dira. Zenbaki erreala lortzeko zatiketa+beharketa egin daiteke.
#include <stdio.h> // printf() funtzioarako
#include <stdlib.h> // rand() eta srand() funtzioetarako
#include <time.h> // time() funtzioarako
#define BEHEMUGA 2
#define GOIMUGA 4
int main()
{
float fZenbakia;
int iKopurua;
printf("\n");
srand(time(NULL)); // srand() zenbaki aleatorioak berriro hasiarazteko, hazia behar du
// Hazia, adibidez, time(NULL) funtzioa izan daiteke zeinek igarotako
// segundoak itzultzen ditu 1970-01-01 datatik hasita
iKopurua = rand();
printf("Zenbaki sasi aleatorioen hazia %d da\n", iKopurua);
printf("\n \t 0 eta RAND_MAX=%d artekoak", RAND_MAX);
printf("\n \t -----------------------------\n");
for (int iKont = 1; iKont <= 15; iKont++)
{
iKopurua = rand(); // 0 eta RAND_MAX=32767 arteko kopuru osoa
printf("%10d \t iKopurua = %d\n", iKont, iKopurua);
}
printf("\n \t 0.0 eta 0.999 arteko balioak");
printf("\n \t ----------------------------\n");
for (int iKont = 1; iKont <= 15; iKont++)
{
fZenbakia = (float)rand()/RAND_MAX; // 0.0 eta 0.999 arteko balio erreala
printf("%10d \t fZenbakia = %f\n", iKont, fZenbakia);
}
printf("\n");
return 0;
}
rand() eta srand()
Zenbaki errealekin lan eginez, balio aleatorioak lortzen dituen programa
idatziko dugu. Ikusi dugun rand() funtzioak kopuru osoa itzultzen duenez kode gehiago gehituko zaio programari zenbaki errealekin lan egiteko, hauxe:
#define BEHEMUGA1 70.5 // abiadura aleatorioaren minimoa
#define GOIMUGA1 100.6 // abiadura aleatorioaren maximoa
fAbiadura = ((float)rand()/(float)(RAND_MAX)) * (GOIMUGA1-BEHEMUGA1); // 0.0 eta 0.999 artekoa bider (GOIMUGA1-BEHEMUGA1)
printf("\n %10f (0.0 eta %.1f artekoa)", fAbiadura, GOIMUGA1-BEHEMUGA1); // 0.0 eta 30.1 artekoa
fAbiadura= fAbiadura + BEHEMUGA1;
printf("\n %10f (%.1f eta %.1f artekoa)", fAbiadura, BEHEMUGA1, GOIMUGA1); // 70.5 eta 100.6 artekoa
Auto baten abiadura adierazten duen zenbaki erreal bat aleatorioki lortuko da, baina zenbaki aleatorio horren balioa bi mugen artekoa izan beharko da: behemuga 70.5 km/h eta goimuga 100.6 km/h.
Auto horren denbora adierazten duen zenbaki erreal bat aleatorioki lortuko da, eta bigarren zenbaki aleatorio horren balioa bi mugen artekoa izan beharko da ere: behemuga 0.5 segundo eta goimuga 2.0 segundo.
Aurreko bi datuekin (abiadura eta denbora) distantziaren kalkulua burutuko da. Eskatzen den programaren exekuzio-adibide bat jarraian erakusten da:
Eta hemen azalpena:
Goiko irudian Ariketa-19b2_FuntzioEstandarrak programaren bigarren for aginduaren pantailaraketak iruzkindu dira, adibideko 1.961043 denbora aleatorioa (0.5 segundo eta 2.0 segundo artekoa) lau urratsetan lortzen da:
rand() funtzioa aplikatu auzazko balio osoa eskuratzeko (31916 adibidean)
Lortutako balio osoa normalizatu 0.0 eta 0.999 esparrura (0.974029 adibidean)
Balio erreala eskalatu (GOIMUGA-BEHEMUGA2) esparrura (1.461043 adibidean)
Aurreko urratsean lortutakoari BEHEMUGA2 oinarria gehitu (1.961043 adibidean)
rand() eta srand()
Demagun azterketa baten notak auzaz lortu nahi direla, jakinik kalifikaziorik txikiena 0.00 dela eta kalifikaziorik handiena 9.99 dela. Nahiz eta notak zenbaki errealak diren, balio aleatorioak lortzean 0 eta 9 arteko kopuru osoak erabiliko ditugu:
/* Ariketa-19b3_FuntzioEstandarrak: zenbaki sasi-aleatorioak lortzen (kopuru errealak) */
// rand() ikasiko dugu, baina srand() funtzioarekin lotuta dago.
// Zenbaki aleatorioen segida lortzeko hazi bat behar da eta time() funtzioa erabiliko da
// NULL parametroarekin zeinek igarotako segundoak itzultzen ditu 1970-01-01 datatik hasita.
// rand() bitartez lortuko diren zenbaki aleatorioak 0 eta RAND_MAX=32767 arteko kopuru
// osoak izango dira. Hamartar bakarra duen zenbaki erreala lortzeko osoekin lan egin daiteke.
// Demagun azterketa baten nota adierazten duten 0.00 eta 9.99 arteko hainbat zenbaki erreal
// ditugula eta nota guztien batezbesteko aritmetikoa kalkulatu nahi dela.
#include <stdio.h> // printf() funtzioarako
#include <stdlib.h> // rand() eta srand() funtzioetarako
#include <time.h> // time() funtzioarako
#define iZENBAT 20
int main()
{
float fNota;
int iUnitatea;
int iHamarrekoa;
int iEhunekoa;
float fBatukaria = 0.0;
srand(time(NULL)); // srand() zenbaki aleatorioak berriro hasiarazteko, hazia behar du
// Hazia, adibidez, time(NULL) funtzioa izan daiteke zeinek igarotako
// segundoak itzultzen ditu 1970-01-01 datatik hasita
printf("\n");
printf(" %d kalifikazio: 0.00 eta 9.99 arteko balio sasi-aleatorioak\n", iZENBAT);
printf(" -----------------------------------------------------------\n");
for (int iKont = 1; iKont <= iZENBAT; iKont++)
{
iUnitatea = rand() % 10; // 0 eta 9 arteko balioak
iHamarrekoa = rand() % 10; // 0 eta 9 arteko balioak
iEhunekoa = rand() % 10; // 0 eta 9 arteko balioak
fNota = iUnitatea + 0.1*iHamarrekoa + 0.01*iEhunekoa;
fBatukaria = fBatukaria + fNota;
printf("%4d iUnitatea=%d iHamarrekoa=%d iEhunekoa=%d fNota=%.2f\n", iKont, iUnitatea, iHamarrekoa, iEhunekoa, fNota);
}
printf(" -----------------------------------------------------------\n");
printf("\n Bataztesteko aritmetikoa %.2f da\n", fBatukaria/iZENBAT);
printf("\n");
return 0;
}
log() eta exp()
5.2x=7.9 bezalako ekuazio esponentziala ebazteko logaritmoa erabil behar da, hots, logaritmo nepertarra kalkulatzen duen log() funtzio estandarra. Modu beretsuan, 7.13.4=x bezalako ekuazioak ebazteko exp() funtzio estandarra aplika dezakegu.
Eskatzen den programaren exekuzio-adibide bat ikusi:
log(), log2(), log10() eta beste oinarriko logaritmoak
Zenbaki errealekin lan eginez, balio positibo bat teklatuz irakurri eta programak zenbakiaren logaritmo hamartarra kalkula dezala log10() funtzio estandarra erabili gabe. Logaritmo bitarra eskuratzeko funtzio estandarrik ez dagoenez, logaritmo nepertarraren funtzioa aplikatu beharko da formula hauen arabera:
log10(x) = log(x)/log(10)
log2(x) = log(x)/log(2)
exp() eta beste oinarriko potentziak
Zenbaki errealekin lan eginez, exponentea izango den balio positibo edo negatibo bat teklatuz irakurri (adibidez Z=4.001), ondoren oinarria izango den balio positibo edo negatibo bat teklatuz irakurri (adibidez Y=2.001). Programak datuen potentzia kalkula dezala (emaitza X=2.0014.001). Horrelako lana burutzeko adibidez pow()funtzio estandarra izan arren, logaritmo nepertarraren log() funtzioa eta e zenbakiari dagokion exp() potentziaren funtzioa aplikatuko dira esleipen hau eginez:
fEmaitza = exp(fZenbakia*log(fOinarria));
Goiko esleipenaren justifikazioa jarraian ematen da:
Z datua den zenbaki erreala (exponentea)
Y datua den zenbaki erreala (oinarria)
X lortu nahi den potentzia
X = Y^Z logaritmo nepertarrak hartuz:
log(X) = log(Y^Z) ---> log(X) = Z·log(Y)
log(X) = Z·log(Y)
exp() funtzioa aplikatuz:
log(X) = Z·log(Y)
exp(log(X)) = exp(Z·log(Y))
X = exp(Z·log(Y))
fmod() eta modf()
Funtzio guztiz desberdinak dira, baina izenak oso antzekoak direlako nahasteko arriskua dago. Funtzio biek bi parametro dituzte, baina parametroen esanahia eta funtzioaren emaitzak oso bestelakoak dira.
fmod() funtzioaren helburua da zatiketa osoaren hondarra itzultzea. Bere ohiko deia honelako zerbait da, non parametroen datu-motak float izan daitezke eta int izan daizteke.
modf() funtzioaren helburua da zenbaki erreal baten zati hamartarra eta zati osoa eskuratzea, kasu honetan datua bakarra da (zenbaki errealaren balioa) eta emaitzak bi dira (zati hamartarra eta zati osoa), hona hemen modf() funtzioaren balizko dei bat:
dbZatiHamartarra = modf(dbBalioa, &dbZatiOsoa);
Ikusten denez bigarren parametroa helbide bat da, zati osoa gordeko duen zenbaki errealaren helbidea hain zuzen ere. Ikusten da ere zati hamartarra modf() funtzioak itzultzen duen emaitza dela.
Hauxe izan daiteke eskatzen den programaren irteera:
Zenbaki errealekin lan eginez, angelu baten sinua adierazten duen balio bat teklatuz irakurri (-1.0 eta +1.0 arteko balioa) eta programak angelua lortuko du radianetan:
fAngelua = asin(fSinuarenDatua);
Gauza bera egin daiteke datua angeluaren kosinua baldin bada acos funtzioa aplikatuz. Edozein kasutan, asin eta acos funtzio estandarrak erabil ahal izateko math liburutegia kargatu beharko da (berdin atan funtzioarekin, math liburutegia beharrezkoa da).
Hemen asin funtzioaren grafikoa (irudiaren gainean klik egin balioak emateko):
Hauxe izan daiteke eskatzen den programaren irteera:
ZER DAKIDAN: Badakit testu bat pantailan idazten. Badakit aldagaien balioak teklatuz irakurtzen eta zenbakizko datuekin eragiketa matematikoak egiten. Baina, edozein datuekin programaren agindu guzti-guztiak exekutatzen dira.
ZER IKASIKO DUDAN: Erabakiak hartzen ikasiko dut. Horrela, datuaren arabera programaren agindu batzuk exekutatuko dira ala ez. Adibide honetan baldintzazko if agindua ikasiko dut eta do-while agindu errepikakorra ikasiko dut. Bide batez, aldagai baten balio nola behartu (edo derrigortu) ikasiko dut.
ESKATZEN DEN PROGRAMA
ADI!
2. astea | radianak bihurtu gradu-minutu-segundo ariketa hau eta Ariketa 11 | Segundoen kopuruak desberdinak dira, batean abiapuntuko datua float datu-motakoa delako eta bestean short/int datu-motakoa delako.
rRadianak aldagaiak angelu baten radianak gordeko ditu, teklatuaren bitartez irakurriko den angelua hain zuzen ere. Radianetan datutzat aukeratu den angeluari dagozkion gradu, minutu eta segundo kalkulatuko dituen programa idatzi.
Sarrerako datua radianetan0.0etaPI/2artekoa izango da
Sarrerako datua zenbaki erreala izango da, erreala eta positiboa. Graduak eta minutuak zenbaki osoak izango dira, eta segundoak zenbaki erreala izango da (segundoak zenbaki osoa balitz doitasuna gal daiteke).
Hauxe izan daiteke Ariketa-12_RadianakBihurtu.cbp proiektua exekutatzean lortzen den irteeraren bat:
fMinutuakaldagaiaren edukia behartu daiMinutuakaldagaian gordetzera. Horretarako, (int)marka erabili da
Zergatik angeluak neurtzeko gradu-minutu-segundo unitateak erabiltzen dira? Besterik gabe ohitura delako, Orduak banatzerakoan minutuak eta segundoak darabilkigun formatuaren arrazoi historiko beragatik.
/* Ariketa-12_RadianakBihurtu: erreal baten zati osoa eta zati hamartarra */
// Lehen koadranteko angelua radianetan adierazten duen
// zenbaki erreal positiboa gradu-minutu-segundo formatura igaro.
// Zenbaki erreal baten behartzea-derrigortzea aplikatuko dugu osoko bat lortzeko.
#include <stdio.h>
#define PI 3.141592653
int main()
{
float fRadianak; // teklatuz irakurriko den datua radianetan
float fDatuaGradutan; // teklatuz irakurriko den datua graduetan
int iGraduak; // emaitzaren zati bat
float fHondarra; // zenbaki errealaren alde dezimala
float fMinutuak;
int iMinutuak; // emaitzaren zati bat
float fSegundoak; // emaitzaren zati bat
printf("\n");
do
{
printf("\n Eman lehen koadranteko angelua radianetan: ");
scanf("%f", &fRadianak);
if ((fRadianak < 0.0) || (fRadianak >= PI/2))
printf("\n\a Angeluaren behemuga 0.0 radian eta goimuga %f radian", PI/2);
} while ((fRadianak < 0.0) || (fRadianak >= PI/2));
fDatuaGradutan = fRadianak*360/(2*PI);
printf("\n fDatuaGradutan = %9.6f", fDatuaGradutan);
iGraduak = (int)fDatuaGradutan;
printf("\n iGraduak = %2d", iGraduak);
fHondarra = fDatuaGradutan - iGraduak;
printf("\n fHondarra = %9.6f", fHondarra);
fMinutuak = 60*fHondarra;
printf("\n fMinutuak = %9.6f", fMinutuak);
iMinutuak = (int)fMinutuak;
printf("\n iMinutuak = %2d", iMinutuak);
fHondarra = fMinutuak - iMinutuak;
printf("\n fHondarra = %9.6f", fHondarra);
fSegundoak = 60*fHondarra;
printf("\n fSegundoak = %9.6f", fSegundoak);
printf("\n\n %f radian = %02d:%02d:%f gradu-minutu-segundo", fRadianak, iGraduak, iMinutuak, fSegundoak);
printf("\n\n");
return 0;
}
ZER DAKIDAN: Erakarpen grabitatorioa programa egin ondoren, badakit testu bat pantailan idazten. Badakit ere balioak aldagaietan gordetzen eta era desberdineko konstanteak definitzen.
ZER IKASIKO DUDAN: Zenbaki osoen arteko zatiketari zatiketa osoa esaten zaio eta bere operadorea % sinboloa da.
ZATIKETA OSOAREN HONDARRA
Zenbaki osoekin lan eginez, zatiketa osoaren hondarra kalkulatzeko % operadorea aplikatu beharra dago. Ondoko programaren kodea eta pantailako irteera ikusi:
/* Ariketa-11_ZatiketaOsoa: % operadorea */
#include <stdio.h>
int main()
{
printf("\n");
printf("\n 7.0/2 = %.2f eragigai bat erreala (bietariko edozein)", 7.0/2);
printf("\n 7.0/2.0 = %.2f bi eragigaiak errealak", 7.0/2.0);
printf("\n 7/2 = %d bi eragigaiak osoak", 7/2);
printf("\n 7%%2 = %d bi eragigaiak osoak", 7%2);
printf("\n\n");
return 0;
}
ESKATZEN DEN PROGRAMA
Datu-mota
Formatua
Balio kopurua 2N
Balioen heina edo barrutia
char
8bit (+ eta -)
256
-128..127
unsigned char
8 bit (+)
256
0..255
short int
16 bit (+ eta -)
65536
-32768..32767
short
16 bit (+ eta -)
65536
-32768..32767
unsigned short
16bit (+)
65536
0..65535
int int
16bit (+ eta -) 32 bit (+eta-)
65536 4294967296
-32768..32767 -2147483648..2147483647
unsigned int
32bit (+)
4294967296
0..4294967295
long int
32 bit (+ eta -)
4294967296
-2147483648..2147483647
long
32 bit (+eta-)
4294967296
-2147483648..2147483647
Goiko taula aintzakotzat harturik ondoko bi ariketak egin:
Ariketa 11a:
long int datu-motak (edo laburrago esanez long datu-motak) 4 byte hartzen ditu beti eta int datu-motak ordenadore gehienetan 4 byte hartzen ditu. Datutzat liSegundoKopurua kopuru erraldoi bat teklatuz irakurri, non liSegundoKopurua aldagaia long int (edo long) datu-motakoa den. Irakurritako denbora pantailaratu egunak-orduak-minutuak-segundoak bezala (emaitzak diren lau aldagaiak int datu-motakoak izan daitezela).
Ariketa 11b:
short int datu-motak (edo laburrago esanez short datu-motak) 2 byte hartzen ditu beti eta int datu-motak ordenadore gehienetan 4 byte hartzen ditu. Datutzat shSegundoKopurua segundoen kopuru handi bat teklatuz irakurri. Non teklatuz irakurritako shSegundoKopurua aldagaia short int datu-motakoa izanik, positiboa eta SHRT_MAX=32767 baino txikiagoa den. Irakurritako denbora pantailaratu orduak-minutuak-segundoak bezala, non shOrduak, shMinutuak eta shSegundoak aldagaiak short datu-motakoak diren.
Hauxe izan daiteke Ariketa-11b_SegundoenKopuruak.cbp proiektua exekutatzean lortzen den irteeraren bat:
Zatiketa osoaren operadorea%da. Adibidez, honela aplikatzen da:shHondarra = shSegundoKopurua % 3;
Ariketa-11a_SegundoenKopuruak.cbp proiektuaren, Ariketa-11b_SegundoenKopuruak.cbp proiektuaren eta Ariketa-11_ZatiketaOsoa.cbp proiektuaren main() funtzioek gordetzen duten kodea:
/* Ariketa-11a_SegundoenKopuruak: zatiketa osoa */
// Programa honetan "limits.h" fitxategia derrigorrezkoa da bere barruan definiturik
// dagoden LONG_MAX konstantea erabiltzen delako.
// Zatiketa osoa kalkulatu beharko dugu, horrretarako '%' operadorea aplikatzen da.
// liSegundoKop kopuru erraldoi bat teklatuz irakurri, non liSegundoKop aldagaia long datu-
// motakoa den. Irakurritako denbora pantailaratu egunak-orduak-minutuak-segundoak bezala.
#include <stdio.h>
#include <limits.h> // LONG_MAX erabiltzen delako
int main()
{
long liSegundoKop; // segundoen kopurua modu kontrolatuan irakurri
int iEgunak, iOrduak, iMinutuak, iSegundoak, iHondarra;
printf("\n");
printf("\n\t Datuaren behemuga 0 eta goimuga LONG_MAX=%ld", LONG_MAX);
printf("\n\t ---------------------------------------------------\n");
do
{
printf("\n\t Segundoen kopuru osoa eman (2100000000 adibidez): ");
scanf("%ld", &liSegundoKop);
if ((liSegundoKop < 0) || (liSegundoKop > LONG_MAX))
printf("\a\t Positiboa izateaz gain, baliorik handiena %ld izan daiteke", LONG_MAX);
} while (liSegundoKop < 0 || liSegundoKop > LONG_MAX);
iEgunak = liSegundoKop / (3600*24);
iHondarra = liSegundoKop % (3600*24); // iHondarra = liSegundoKop - iEgunak*3600*24;
iOrduak = iHondarra / 3600;
iHondarra = iHondarra % 3600; // iHondarra = iHondarra - iOrduak*3600;
iMinutuak = iHondarra / 60;
iSegundoak = iHondarra % 60; // iSegundoak = iHondarra - iMinutuak*60;
printf("\n\t Egunak=%d \t Orduak=%d \t Minutuak=%d \t Segundoak=%d", iEgunak, iOrduak, iMinutuak, iSegundoak);
printf("\n\t Hasierako datua berkonposatuta ----> %ld segundo", (long)iEgunak*3600*24 + iOrduak*3600 + iMinutuak*60 + iSegundoak);
printf("\n\n");
return 0;
}
ZER DAKIDAN: Datu-moten taula gogoratuz, badakit datu-mota jakin bateko aldagaian ezin daitekeela edozein balio gorde.
ZER IKASIKO DUDAN: Ikasi baino gehiago ikusiko dut prgramak emaitza desegokiak eskainiko dituela aldagai baten muga gainditzen denean.
ESKATZEN DEN PROGRAMA
Ariketa honetan interesatzen zaigu short int datu-motarekin lan egitea 2 byte hartzen dituelako memorian eta, ondorioz, bere balio maximoa nahiko txikia delako: 32.767
Teklatutik zenbaki osoa sartu (shZbk aldagaian gorde) eta zenbakiari dagozkion hurrengo bost zenbakien karratuak eta kuboak kalkulatu eta pantailaratu (karratuak eta kuboak kalkulatzean shKarratu eta shKubo aldagaietan gorde).
Pantailaratzean honako taula honen moduan agertuko da:
Hauek izan daitezke Ariketa-10_KopuruHandiegiak.cbp proiektua exekutatzean lortzen diren bi irteera. Programaren exekuzio bietan emaitzak ikustean, uler daiteke zenbaki osoen mugak gainditu direla eta horregatik erroreak pantailaratzen direla. Lehen exekuzioan, datua 28 denean, erroreak kuboak kalkulatzean ematen dira. Bigarren exekuzioan, datua 179 denean, erroreak karratuetan eta kuboetan ematen dira:
Datua 28denean kuboak kalkulatzeanSHRT_MAX=32767konstantea gainditzen da
Datua 179denean karratuak eta kuboak kalkulatzeanSHRT_MAX=32767konstantea gainditzen da
Hona hemen Ariketa-10_KopuruHandiegiak.cbp proiektuaren main() funtzioa gordetzen duen main.c fitxategiaren edukia:
/* Ariketa-10_KopuruHandiegiak: ordenadorearen mugak */
// Programa honetan "limits.h" fitxategia derrigorrezkoa da bere barruan definiturik
// dauden hainbat konstanteen balioak pantailaratu nahi direlako.
// Ikusi erabilitako formatu-zehaztatzaileen zerrenda:
// %d, %u (edo %ui), %li, %lu, %hd
/*
Teklatutik zenbaki osoa sartu (shZbk aldagaian gorde) eta zenbakiari dagozkion hurrengo
bost zenbakien karratuak eta kuboak kalkulatu eta pantailaratu (karratuak eta kuboak
kalkulatzean shKarratu eta shKubo aldagaietan gorde).
*/
#include <stdio.h>
#include <limits.h>
int main()
{
short shZbk, shKarratu, shKubo;
printf("\n");
printf("\n ------------------------------------------------------------------");
printf("\n 'limits.h' fitxategian definitutako konstante osoak:");
printf("\n \t - CHAR_MAX = %d", CHAR_MAX);
printf("\n \t - CAHR_MIN = %d", CHAR_MIN);
printf("\n \t - SHRT_MAX = %d", SHRT_MAX);
printf("\n \t - SHRT_MIN = %d", SHRT_MIN);
printf("\n \t - USHRT_MAX = %d", USHRT_MAX);
printf("\n \t - INT_MAX = %d", INT_MAX);
printf("\n \t - INT_MIN = %d", INT_MIN);
printf("\n \t - UINT_MAX = %u", UINT_MAX);
printf("\n \t - LONG_MAX = %li", LONG_MAX);
printf("\n \t - LONG_MIN = %li", LONG_MIN);
printf("\n \t - ULONG_MAX = %lu", ULONG_MAX);
printf("\n ------------------------------------------------------------------");
printf("\n\n");
printf("\nEdozein ordenagailutan 'char' batek %d byte hartzen du memorian", (int)sizeof(char));
printf("\nEdozein ordenagailutan 'short' batek %d byte hartzen ditu memorian", (int)sizeof(short));
printf("\n Ordenagailu honetan 'int' batek %d byte hartzen ditu memorian", (int)sizeof(int));
printf("\nEdozein ordenagailutan 'long' batek %d byte hartzen ditu memorian", (int)sizeof(long));
printf("\n");
printf("\n 'char' datu-motako zenbakietan handiena %d da", CHAR_MAX);
printf("\n'short' datu-motako zenbakietan handiena %d da", SHRT_MAX);
printf("\n 'int' datu-motako zenbakietan handiena %d da", INT_MAX);
printf("\n 'long' datu-motako zenbakietan handiena %li da", LONG_MAX);
printf("\n\n\nKopuru osoa eman (28 adibidez): ");
scanf("%hd", &shZbk);
printf("\n ZENBAKIA KARRATUA KUBOA");
printf("\n ------------------------------------------------------------------");
shZbk++;
shKarratu =shZbk*shZbk;
shKubo = shKarratu*shZbk;
printf("\n%15hd%20hd%30hd", shZbk, shKarratu, shKubo);
shZbk++;
shKarratu =shZbk*shZbk;
shKubo = shKarratu*shZbk;
printf("\n%15hd%20hd%30hd", shZbk, shKarratu, shKubo);
shZbk++;
shKarratu =shZbk*shZbk;
shKubo = shKarratu*shZbk;
printf("\n%15hd%20hd%30hd", shZbk, shKarratu, shKubo);
shZbk++;
shKarratu =shZbk*shZbk;
shKubo = shKarratu*shZbk;
printf("\n%15hd%20hd%30hd", shZbk, shKarratu, shKubo);
shZbk++;
shKarratu =shZbk*shZbk;
shKubo = shKarratu*shZbk;
printf("\n%15hd%20hd%30hd", shZbk, shKarratu, shKubo);
printf("\n\n");
return 0;
}
ZER DAKIDAN: Badakit sqrt(), pow() eta fabs() funtzio estandarrak erabiltzeko math.h fitxategiaren sartzea egingo dugula programaren hasieran #include <math.h> idatziz.
ZER IKASIKO DUDAN: Teklatuz irakurritako aldagaiaren egokitasuna ziurtatzen ikasiko dut do-while agindu errepikakoraren bitartez. Bide batez, atan() funtzio estandarra ikasiko dut.
Ikasi beharreko hitzak
Hitza
Deskribapena edo/eta adibidea
Konpiladore
Programa bat da. Labur esanda, programa honen bitartez iturburu-fitxategitik (guk idatzi eta irakur dezakegun testu-fitxategitik) dagokion programa exekutagarriaren fitxategi bitarra lortzen da.
Ihes-sekuentzia
Ihes-sekuentzia (edo karaktere berezi) teklatuaren bitartez ezin daitekeen eman karakterea da, adibidez \n karakterea.
Formatu- zehaztatzaile
Aldagai baten edukia pantailan idaztean nola aurkeztu nahi den aukeratzeko balio du; esate baterako %d bitartez zenbaki osoa ikusiko da pantailan, baina %c bitartez karaktere bat ikusiko da.
Aurreprozesadore
Programa hau konpiladorea baino lehen jarduten da, bere lana kodea prestatzea da (#include eta #define guztiak burutu, iruzkinak kendu, e.a.).
Sartzea
Fitxategia sartzea. #include FitxategiIzen aurre-prozesadorearen jarraibideari esker FitxategiIzen fitxategiaren edukia gure programara gehitzen zaio.
Definitzea
Konstantea definitzea. #define Identifikadore BalioKonstantea bitartez konstanteak defini daitezke.
Funtzio
Kode zati bat da helburu jakin bat betetzen duena. Emaitza itzul dezake eta behar dituen datuei parametro esaten zaie.
Parametro (argumentu)
Funtzio bati ematen zaion datua. Parametroren bat funtzioari pasatzean bi modutan egin daiteke: balioz ala erreferentziaz.
Datu-mota
Programa batean erabiliko ditugun magnitudeak izaera bat daukate: zenbaki osoa, zenbaki erreala, karakterea, e.a. Horiek adierazteko datu-motak erabiltzen dira.
Iruzkin
Programa azaltzen duen testua.
Esleipen- operadorea
C-rako, esleipena operadore bat da, esleipen-operadorea deritzona (=), eta operadore guztien artean lehentasun txikiena du.
Operadore aritmetiko
Operadore edo eragile aritmetikoen adibideak hauek dira: + batuketa-operadorea, - kenketa operadorea, * biderkatzeko operadorea, / zatitzeko operadorea, % zatiketa osoaren hondarra lortzeko operadorea, ...
Operadore logiko
Operadore edo eragile logikoak hiru dira: ! ukapen logikoa (ez/not), && konjuntzioa edo biderketa logikoa (eta/and), || disjuntzioa edo batuketa logikoa (edo/or).
Operadore erlazional
Operadore erlazionalak edo erlaziozko eragileak sei dira: > handiago, >= handiago edo berdin, < txikiago, <= txikiago edo berdin, == berdin, != desberdin.
ESKATZEN DEN PROGRAMA
Zenbaki errealekin lan eginez, puntu baten koordenatu kartesiarrak ezagutzen dira eta dagozkien koordenatu polarrak lortu behar dira.
Ariketa:
Lehen koadrantean dagoen P puntu baten koordenatu kartesiarretan teklatutik irakurri eta P puntuari dagozkion koordenatu polarrak lortu (distantzia metrotan eta angelua radianetan).
Adi!!! P puntuaren Px koordenatua ezin daiteke 0 izan, bestela α angeluaren tangenteak infinitu balioko du.
P puntuaren koordenatu polarraren angelua gradu-minutu-segundotan pantailaratzen laster ikasiko dugu.
Hauxe izan daiteke Ariketa-09_KartesiarPolar.cbp proiektua exekutatzean lortzen den irteeraren bat:
Ariketa honetan sqrt(), pow() eta atan()funtzio estandarrak erabiltzen dira
Hona hemen Ariketa-09_KartesiarPolar.cbp proiektuaren main() funtzioa gordetzen duen main.c fitxategiaren edukia:
/* Ariketa-09_KartesiarPolar: erabakiak hartzen */
// fabs(), sqrt() eta pow() funtzio matematikoak ikasiko ditugu,
// horiek erabiltzeko "math.h" fitxategia derrigorrezkoa da.
// if agindua ikasiko dugu.
// do-while agindua ikasiko dugu
// Programa honetan '\a' karaktere berezia erabiliko dugu.
// XY planoan dagoen P puntu baten koordenatu kartesiarretan (fPx, fPy) teklatutik
// irakurri eta P puntuari dagozkion koordenatu polarrak lortu (distantzia, angelua).
// Tangentea fPy/fPx denez, abzisa den fPx koordenaturako zero balioa ez da onartuko.
// P puntuaren koordenatu polarraren angelua radianetan pantailaratu.
// P puntuaren koordenatu polarraren angelua gradu-minutu-segundotan pantailaratzea
// aurrerago ikusiko dugun ariketa baten helburua izango da.
#include <stdio.h>
#include <math.h>
int main()
{
float fPx, fPy, fDist, fAng;
printf("\n\nZenbaki errealekin lan eginez...\n\n");
do
{
printf("\"P\" puntuaren x koordenatua eman: ");
scanf("%f", &fPx);
if (fPx == 0.0)
printf("\a\"P\" puntuaren abzisa ezin daiteke 0.0 izan\n");
} while (fPx == 0.0);
printf("\"P\" puntuaren y koordenatua eman: ");
scanf("%f", &fPy);
fDist = sqrt(pow(fPx, 2) + pow(fPy, 2));
fAng = atan(fPy/fPx);
printf("\nOP Distantzia = %f unitate", fDist);
printf("\nAlfa angelua = %f radian", fAng);
printf("\n\nKoordenatuak: (%.3f, %.3f) = [%.3f | %.3f]", fPx, fPy, fDist, fAng);
printf("\n\n");
return 0;
}