Zrobiłem program do obliczania sinh za pomocą szeregu z określoną dokładnością i wyliczający błąd względny ze wzoru (wartość obliczona z szeregu - wartość obliczona za pomocą sinh)/wartość obliczona za pomocą sinh:
#include <stdio.h> /*printf, scanf, fgets, putchar*/
#include <math.h> /*sinh*/
int main(void)
{
printf("\nProgram oblicza z zadaną dokładnością wartość sinh i wartość błędu względnego w stosunku do wartości uzyskanej przy pomocy standartowej funkcji języka C");
while(1) /*pętla nieskończona*/
{
double y = 0, /*wynik funkcji obliczonej za pomocą szeregu*/
error, /*stokrotność błędu względnego*/
x, /*argument funkcji*/
z; /*wynik funkcji obliczonej za pomocą funkcji bibliotecznej*/
unsigned int n, /*dokładność*/
k; /*zmienna oznaczająca dany element szeregu*/
char other[2]; /*znak po cyfrze*/
printf("\n\nPodaj wartość, dla której ma być obliczony sinh (inny znak niż cyfra i \".\" zamyka program): "); /*napisz co trzeba podać*/
if (scanf("%lf",&x) == 0) /*pobierz liczbę, a jeśli jej nie ma, to zamknij program*/
{
putchar('\n'); /*pozostaw pusty wiersz po programie*/
return 0;
}
fgets(other, 2, stdin); /*pobierz znak po cyfrze*/
if (other[0] != '\n') /*jeśli to nie jest znak nowego wiersza, zamknij program*/
{
putchar('\n'); /*pozostaw pusty wiersz po programie*/
return 0;
}
printf("Podaj dokładność (0 i inny znak niż cyfra zamyka program): "); /*napisz co trzeba podać*/
if (scanf("%u",&n) == 0 || n == 0) /*pobierz liczbę, a jeśli jej nie ma lub jest nią 0, to zamknij program*/
{
putchar('\n'); /*pozostaw pusty wiersz po programie*/
return 0;
}
fgets(other, 2, stdin); /*pobierz znak po cyfrze*/
if (other[0] != '\n') /*jeśli to nie jest znak nowego wiersza, zamknij program*/
{
putchar('\n'); /*pozostaw pusty wiersz po programie*/
return 0;
}
for (k=1; k<=n; k++) /*obliczanie szeregu*/
{
unsigned long a; /*zmienna do przechowywania wykładnika potęgi,
a potem będąca mianownikiem w elemencie szeregu*/
unsigned int c; /*pomocnicza zmienna do pętli,
najpierw oznaczająca dany stopień przy liczeniu potęgi,
a potem liczbę o 1 mniejszą przy liczeniu silni*/
double b; /*licznik w elemencie szeregu*/
a = 2*k-1; /*zapamiętanie wykładnika potęgi w danym elemencie szeregu*/
b = x; /*przypisanie do licznika argumentu funkcji*/
for(c=1; c<a; c++) /*liczenie potęgi,
wzrastanie zmiennej pomocniczej do wykładnika potęgi*/
{
b = b * x; /*mnożenie licznika przez argument funkcji*/
}
for(--c; c>=2; c--) /*zamiana wykładnika potęgi na jego silnie
wykonywanie aż zmienna pomocnicza zmniejszy się do 1*/
{
a = a * c; /*mnożenie przez liczbę o 1 mniejszą*/
}
y = y + (b/a); /*dodaj element szeregu do wartości funkcji*/
}
printf("sinh(%.16f) = %.16f\n", x, y); /*wyświetl sinh obliczony za pomocą szeregu*/
z = sinh(x); /*oblicz wartość sinh za pomocą funkcji bibliotecznej*/
error = ((y - z)/z)*100; /*oblicz stokrotność błędu względnego*/
printf("Błąd względny: %.16f", error); /*wyświetl błąd względny*/
putchar('%'); /*pokaż znak procent*/
}
}
Działa bez problemu mniej więcej dla dokładności n<17 oraz argumentu -60<x<-66. Dla większych argumentów zwraca -100% jako błąd względny, dla mniejszych -NaN, a dla większych dokładności Infinity jako wartość funkcji obliczona z szeregu i jako błąd względny. Dlaczego? Program dobrze liczy potęgę i silnie. Czy -100% i -NaN oznacza liczbę mniejszą od -99,9999999999999999 a większą od -100. Czy ktoś umiałby dokładnie oszacować liczby, dla których program poprawnie liczy?
Kompiluje w systemach OpenSolaris 2008.11 i Solaris 9 za pomocą gcc -ansi -pedantic -Wall -lm. GCC nie pozwolił mi użyć "%lf" w funkcji "printf". Czy dobrze, że użyłem "%.16"? Wyliczyłem te 16 wpisując do double liczby, a następnie wyświetlając jest licząc ile cyfr po przecinku zostało poprawnie wyświetlonych.