Tiny programs (C, C++, C#, ...)
File detail
Source code
/*
* Soubor: proj2.c
* Datum: 24.11.2004
* Autor: Kamil Dudka, xdudka00@stud.fit.vutbr.cz
* Projekt: IZP c. 2 - Iteracni vypocty
* Popis: viz. Dokumentace
*
* Prosím, neodevzdávejte zdrojové kódy, které jsou zde k dispozici,
* jako Vaše školní projekty. Děkuji :-)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// Vyctovy typ errNum - konstanty predstavuji cislo chyby
typedef enum errN
{
ERR_NOERROR,
ERR_MANYARGS,
ERR_BADARG1,
ERR_BADARG2,
} errNum;
// Vlastni chybove hlasky
const char *err_msg[] =
{
"",
"Prilis mnoho parametru\n",
"Chybny parametr 1\n",
"Chybny parametr 2\n",
};
// Vypise chybovou hlasku na stderr
inline void printError (errNum n)
{
fprintf (stderr,err_msg[n]);
}
// Vypise help na standartni vystup
inline void printHelp()
{
printf (
"Program Iteracni vypocty\n"
"Autor: Kamil Dudka\n"
"Program provadi vypocet zadane matematicke funkce"
" s urcitou presnosti. Nacita\ncisla oddelena bilymi"
" znaky ze standartniho vstupu. Provadi vypocet zvolene\n"
"funkce se zvolenou presnosti a tiskne"
" vysledek na standartni vystup.\n"
"Pouziti: proj2 -h\n"
" proj2 -sqrt|-sin|-ex|-ln EPS\n"
"Popis parametru:\n"
" -h Vypise tuto obrazovku s napovedou.\n"
" -sqrt Spocita druhou odmocninu ze danych cisel.\n"
" -sin Spocita funkci sinus ze danych cisel.\n"
" -ex Spocita funkci e^x ze danych cisel.\n"
" -ln Spocita prirozeny logaritmus ze danych cisel.\n"
" EPS Pozadovana presnost (s radovou teckou nebo"
" v semilogaritmickem tvaru).\n"
);
}
// Konstanty doporucene v zadani projektu
const double IZP_E = 2.7182818284590452354; // e
const double IZP_PI = 3.14159265358979323846; // pi
const double IZP_2PI = 6.28318530717958647692; // 2*pi
const double IZP_PI_2 = 1.57079632679489661923; // pi/2
const double IZP_PI_4 = 0.78539816339744830962; // pi/4
// Prototypy jednotlivych funkci pro vypocet mat. funkci
double odmocnina (double, double);
double sinus (double, double);
double enax (double, double);
double lnx (double, double);
// Typ ukazatele na funkci - vyuziji pri zpracovani 1. parametru
typedef double (*funkce)(double, double);
// Hlavni program - osetreni parametru a cyklus nacitani vstupu
int main (int argc, char *argv[])
{
funkce vypocti;
double hodnota,eps;
if (argc<3)
{ // Zadan nedostatecny pocet parametru - vypisu help
printHelp();
exit (EXIT_FAILURE);
}
if (argc>3)
{ // Zadano prilis mnoho parametru - vypisu chybu
printError (ERR_MANYARGS);
exit (EXIT_FAILURE);
}
// Rozpoznani prvniho parametru
if (strcmp("-sqrt",argv[1])==0) vypocti=odmocnina;
else if (strcmp("-sin",argv[1])==0) vypocti=sinus;
else if (strcmp("-ex",argv[1])==0) vypocti=enax;
else if (strcmp("-ln",argv[1])==0) vypocti=lnx;
else
{ // Parametr 1 nerozpoznan
printError (ERR_BADARG1);
exit (EXIT_FAILURE);
}
// Zpracovani druheho parametru (eps) - prevod na cislo
eps = atof(argv[2]);
if ((eps<=0.0)||isinf(eps))
{ // Chybny parametr 2
printError (ERR_BADARG2);
exit (EXIT_FAILURE);
}
// Cyklus nacitajici data ze stdin,
// provadejici vypocet
// a vystup na stdout
while (scanf("%le",&hodnota)==1)
printf ("%.10le\n", vypocti(hodnota, eps));
// Pokud nedojde k zadne chybe, program skonci normalne
return EXIT_SUCCESS;
}
// Funkce odmocnina pocita odmocninu cisla s presnosti eps
// viz. dokumentace
double odmocnina (double vstup, double eps)
{
double predchozi; // promenna pro ulozeni predchoziho kroku
double aktualni; // promenna pro vysledek aktualniho kroku
// Testuji definicni obor funkce odmocnina
// Pro zaporna cisla a NAN vraci NAN
if ((vstup<0.0)||isnan(vstup))
return NAN;
// Pro nekonecno na vstupu vraci nekonecno
if isinf(vstup)
return INFINITY;
// Pro vstupni hodnotu 0 vraci 0
if (vstup==0.0)
return 0.0;
// Jako prvni mezikrok si ulozim vstupni hodnotu
aktualni = vstup;
// Vlastni iterace - viz dokumentace
do {
predchozi = aktualni;
aktualni = 0.5 * (vstup/predchozi + predchozi);
} while (fabs (aktualni-predchozi) >= eps);
return aktualni;
}
// funkce sinus pocita sinus s presnosti eps
// viz. dokumentace
double sinus (double vstup, double eps)
{
// Nefunguje pro velkou absolutni hodnotu vstupniho cisla !!!
// Hlavni pricina bude nejspis v tom ze konstanta IZP_2PI
// zadana s presnosti na 20 desetinnych mist neni dost presna :-(
double citatel; // promenna, do ktere ukladam mocniny argumentu
double jmenovatel = 1; // promenna, do ktere ukladam faktorial cisla 2i
double aktualni; // aktualni prvek rady
double soucet = 0; // aktualni soucet rady
unsigned int prevratit; // Rovna-li se TRUE bude vystup zaporny
unsigned long i; // Pomocna promenna iteracniho cyklu
// Je-li vstup mimo rozsah vrati NAN
if (isnan(vstup)||isinf(vstup))
return NAN;
// Vychazim z toho ze sinus je fce licha
// Zmenim-li znamenko na vstupu, musim ho zmenit i na vystupu
if ( (prevratit=(vstup<0.0)) )
vstup = -vstup; // ted je cislo vstup kladne
// Upravi vstup na rozsah od 0 do 2PI
vstup = fmod (vstup,IZP_2PI);
// Upravi vstup na rozsah od 0 do PI (licha fce.)
if (vstup>IZP_PI)
{
vstup -= IZP_PI;
prevratit ^= 1; // Otoci znamenko na vystupu
}
// Upravi vstup na rozsah od 0 do PI/2
if (vstup>IZP_PI_2)
vstup = IZP_PI - vstup;
// Inicializace promennych pred prvni iteraci
citatel = vstup;
// Podminka v cyklu FOR zajistuje aby nepretekla ink. promenna
for (i=2; i; i++)
{
// Vypocte aktualni clen rady
aktualni = citatel/jmenovatel;
// Akt.clen je stridave kladny a zaporny
if (i%2==prevratit)
soucet += aktualni;
else
soucet -= aktualni;
// Byla-li dosazena presnost, cyklus skonci
if (aktualni <= eps)
break;
// Vypocet nasledujiciho clenu - odvozeni v dokumentaci
citatel *= vstup * vstup;
jmenovatel *= ((double)(2*i-1))*((double)(2*i-2));
}
// Vysledkem je soucet rady
return soucet;
}
// Funkce enax pocita e na x-tou a presnosti eps
// viz. dokumentace
double enax (double vstup, double eps)
{
double citatel = 1; // promenna, do ktere ukladam mocniny argumentu
double jmenovatel = 1; // promenna, do ktere ukladam faktorial cisla 2i
double aktualni; // aktualni clen rady
double soucet = 1; // aktualni soucet rady
unsigned long i; // Pomocna promenna
double ec; // Nasobitel vysledku
if isnan (vstup)
return NAN;
if (vstup == INFINITY)
return INFINITY;
if (vstup == -INFINITY)
return 0.0;
// Rozdeleni na mantisu a exponent
vstup = modf (vstup, &ec);
if isinf(ec = exp (ec))
return INFINITY;
// Vlastni iterace - viz. dokumentace
// Podminka v cyklu zabrani preteceni inc. promenne
for (i=1; i; i++)
{
citatel *= vstup; // Vypocet mocniny x
jmenovatel *= i; // Vypocet faktorialu
aktualni = citatel/jmenovatel; // Vypocet aktualniho prvku rady
// Soucet rady
soucet += aktualni;
// Zadana presnost byla dosazena
if (fabs(aktualni)<=eps)
break;
}
return soucet*ec;
}
// Funkce lnx pocita prirozeny logaritmus s presnosti eps
// viz. dokumentace
double lnx (double vstup, double eps)
{
double citatel; // citatel aktualniho clena rady
double aktualni; // aktualni clen rady
double soucet = 0; // aktualni soucet rady
long int ec = 0; // ec/2 se nakonec pricte k souctu rady
unsigned long jmenovatel; // jmenovatel aktualniho clena rady
// Konstanty pro prevod na zakladni interval
// iteracniho cyklu
const double SQRT_E = sqrt (IZP_E);
const double SQRT_E_1 = 1.0/SQRT_E;
// Pro cislo <=0 nebo NAN vraci NAN
if ((vstup<0.0)||isnan(vstup))
return NAN;
// Pro hodnotu nula vraci minus nekonecno
if (vstup==0.0)
return -INFINITY;
// Pro hodnotu nekonecno vraci nekonecno
if isinf(vstup)
return INFINITY;
// Prevod na zakladni interval - viz. Dokumentace
while (vstup<SQRT_E_1)
{
vstup *= SQRT_E;
ec --;
}
while (vstup>SQRT_E)
{
vstup /= SQRT_E;
ec ++;
}
// Nastaveni promennych pred zacatkem iterace
vstup --;
citatel = vstup;
// Vlastni iterace - viz. Dokumentace
for (jmenovatel=1; jmenovatel; jmenovatel++)
{
// Vypocet aktualniho clenu
aktualni = citatel/jmenovatel;
// Castecny soucet rady
soucet += aktualni;
// Byla-li dosazena presnost, cyklus skonci
if (fabs(aktualni)<=eps)
break;
// Vypocet citatele pro nasledujici iteraci
citatel *= -vstup;
}
// K souctu rady jeste prictu "cely pocet polovin"
return soucet+((double)ec/2.0);
}