Menu |
|
|
| // Plik źródłowy np. Unit1.cpp //-------------------------------- int silnia(int n) { if(n == 0) return 1; return n * silnia(n - 1); } //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Edit1->Text = IntToStr(silnia(12)); } //-------------------------------- |
Występuje jednak problem z tą funkcją, otóż będzie ona działał poprawnie tylko dla n <= 12. Dzieje się tak dlatego, że zmienna typu int może przechowywać maksymalnie liczbę '4294967296', dla n = 12 wynik będzie się równał '479001600', ale dla n = 13 będzie to już '6227020800', czyli tym samym przekroczy pojemność zmiennej int. Żeby zwiększyć zakres możliwości silni należy zastąpić typ int, zmienną typu long double, zmienna ta posiada pojemność '3,36x10-4932 ... 1,18x104932':
| // Plik źródłowy np. Unit1.cpp //-------------------------------- long double silnia(int n) { if(n == 0) return 1; return (double)n * silnia((double)n - 1); } //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Edit1->Text = FloatToStr(silnia(12)); } //-------------------------------- |
| Miesiąc
|
Pary dorosłe |
Pary młode |
Całkowita liczba par |
| 1 | 1 | 1 | 2 |
| 2 | 2 | 1 | 3 |
| 3 | 3 | 2 | 5 |
| 4 | 5 | 3 | 8 |
| 5 | 8 | 5 | 13 |
| 6 | 13 | 8 | 21 |
| 7 | 21 | 13 | 34 |
| 8 | 34 | 21 | 55 |
| 9 | 55 | 34 | 89 |
| 10 | 89 | 55 | 144 |
| 11 | 144 | 89 | 233 |
| 12 | 233 | 144 | 377 |
Liczba par w kolejnym miesiącu to suma: liczby par poprzedniego miesiąca, powiększonej o liczbę par przychówku. Ostatnia liczba jest równa liczbie par sprzed dwóch miesięcy. Liczby Fibonacciego to:
F0 = 0, F1 = F2 = 1, Fn = Fn - 1 + Fn - 2, n ≥ 2
Dodanie dwóch jedynek na
początku można też interpretować przy pomocy królików: jeżeli para została
zamknięta w klatce zaraz po urodzeniu to po miesiącu w klatce ciągle była tylko
ta jedna parka.
Zapisując obliczone wartości w tablicy statycznej, unika się wprost obliczania
tych samych wartości. Podany algorytm wyznacza liczbę Fn
w czasie proporcjonalnym do liczby n, a oto algorytm rozwiązujący
problem z królikami dla dowolnej liczby miesięcy (w przykładzie dla 12
miesięcy):
| // Plik źródłowy np. Unit1.cpp //-------------------------------- #define MAX 65536 int F(int i) { static int K[MAX]; if(K[i] != 0) return K[i]; int t = i + 1; if(i < 0) return 0; if(i > 1) t = F(i - 1) + F(i - 2); return K[i] = t; } //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { ShowMessage("Po roku w klatce będzie: " + IntToStr(F(12)) + " królików."); } //-------------------------------- |
Ten przykład rozwiązuje
problem z królikami, jednak podaje nieprawdziwe wyniki, dla
F0
wynik będzie się równał 1, dla
F1
wyniesie 2, a dla
F2
wyniesie 3, a to się z kolei nie zgadza ze wzorem
F0 = 0, F1
= F2 = 1,
dlatego algorytm powinien mieć taką postać:
| // Plik źródłowy np. Unit1.cpp //-------------------------------- #define MAX 65536 int F(int i) { static int K[MAX]; if(K[i] != 0) return K[i]; int t = i; if(i < 0) return 0; if(i > 1) t = F(i - 1) + F(i - 2); return K[i] = t; } //-------------------------------- |
W języku C++ w tablicy statycznej elementom przypisywane są na początku liczby 0, dlatego chcąc rozwiązać problem z królikami należy podać funkcji F jako argument nie liczbę 12, lecz liczbę większą o 2, czyli 14.
Obliczanie całki metodą Monte Carlo.
Ta funkcja oblicza całkę z funkcji f po
przedziale (x0,x1) przy użyciu funkcji rekurencyjnej. Algorytm działa poprawnie
dla każdej zdefiniowanej przez użytkownika funkcji, lecz dokładność obliczeń
jest zależna od wartości n. Żeby używać funkcji Power należy włączyć do
projektu bibliotekę #include <math.hpp>
| // Plik źródłowy np. Unit1.cpp //-------------------------------- double f(double x) { return(Power(x, 2)); // funkcja tu zdefiniowana może być dowolna, byle ciągła } //-------------------------------- long double suma(long int n, double x0, double dx) { long double s = 0; if(n > 0) s = f(x0+((double)rand()/(double)(RAND_MAX + 1)*dx)) + suma(n-1, x0, dx); return s; } //-------------------------------- long double calka(double x0, double x1) { long double s; double dx; dx = x1 - x0; n = 1000; s = dx * suma(n, x0, dx)/n; return s;
} |
Opracował: Anatholius
Przykładowy
program - pobierz - ZIP 14 KB
Obliczanie Całki przybliżoną metodą Reimanna (pomysł autora):
Poniższa funkcja również oblicza całkę z funkcji
f po przedziale (x0,x1), lecz metodą opartą na ściśle matematycznej całce
Reimanna. Jej dokładność również zależy od wartości n, lecz wynik całki
jest dokładniejszy od wyniku metody Monte Carlo. Czas działania obydwu procedur
jest taki sam. Żeby używać funkcji Power należy włączyć do projektu bibliotekę
#include <math.hpp>
| // Plik źródłowy np. Unit1.cpp // Wersja nie rekurencyjna //-------------------------------- double f(double x) { return(Power(x, 2)); // funkcja tu zdefiniowana może być dowolna, byle ciągła } //-------------------------------- long double cr(double x0, double x1) { long double s; double dx; dx = x1 - x0; s = dx * f(x0 + ((double)rand()/(double)(RAND_MAX + 1)*dx)); return s; } //-------------------------------- long double calka(double x0, double xkon) { long double s = 0; double dx; dx = xkon - x0; n = 1000; long double dt = dx * Power(n,-1); for(long int i = 1; i <= n; i++) s += cr(x0 + i * dt, x0 + (i + 1)*dt); return s; } //-------------------------------- |
| // Plik źródłowy np. Unit1.cpp // Wersja rekurencyjna //-------------------------------- double cr(int i, double x0, double x1, int n) { double s = 0; double dx; dx = x1 - x0; if(i > 0) s = calka(x0, x1) + cr(i - 1, x1, x1 + dx, n); return s; } //-------------------------------- double calkarimm (double x0,double xkon) { double s=0; double dx; dx = xkon - x0; int n = 1000; double dt = dx * Power(n, -1); s = cr(n, x0, x0 + dt, n); return s; } //-------------------------------- |
Ponieważ funkcja zwraca wartość long double
to aby móc tą wartość reprezentować w obiekcie typu np. TLabel lub TEdit
należy ją przypisać do zmiennej typu double i taka wartość da się już
przypisać do odpowiedniego obiektu.
| // Plik źródłowy np. Unit1.cpp // Wersja rekurencyjna //-------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { x0 = 0; //początek przedziału x1 = 1; //koniec przedziału double c = calka (x0, x1); Edit1->Text = (AnsiString)c; } //-------------------------------- |
W programie przykładowym całka jest liczona dla funkcji x2 po przedziale (0,1). Całkę tą da się łatwo wyliczyć:
.
Wynosi ona 1/3, ale w zapisie dziesiętnym 0,3333… można więc porównywać dokładność wyliczanej przez program całki w zależności od metody i od wartości n.
Opracował: Anatholius
Przykładowy program - pobierz - ZIP 14 KB