Skocz do zawartości

[C] Obliczanie sinh za pomocą szeregu


Kamil Szmit

Polecane posty

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.

Link do komentarza
Udostępnij na innych stronach

Zarchiwizowany

Ten temat jest archiwizowany i nie można dodawać nowych odpowiedzi.

×
×
  • Utwórz nowe...