Česky
Kamil Dudka

Tiny programs (C, C++, C#, ...)

File detail

Name:Downloadproj2.c [Download]
Location: tiny > IZP > proj2
Size:8.3 KB
Last modification:2009-12-21 17:54

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