Aby zdefiniować nasz model obliczeniowy, posłużymy się pojęciem programu. Zastosujemy przy tym notację podobną do tej z języka programowania C.
Program składa się z deklaracji, czyli opisu obiektów, których będziemy używać, oraz z poleceń (instrukcji), czyli opisu akcji, które będziemy wykonywać.
Dostępnymi obiektami są stałe i zmienne typu całkowitego (
int
),
rzeczywistego (float
i double
). Typ logiczny
symulujemy tak jak w
C wartościami zero-jedynkowymi typu całkowitego.
Zmienne jednego typu mogą być grupowane w wektory albo tablice.
Widzimy więc, że podstawowe algorytmy numeryczne będą bazować na mało
skomplikowanych typach danych. Również nieskomplikowane będą instrukcje
naszego
modelowego języka. Dążenie do prostoty (ale nie za wszelką cenę) jest
charakterystyczne dla numeryki. Typowe jest zastępowanie skomplikowanych
tablic rekordów prostszymi macierzami, eleganckich rekurencji ---
zwykłymi pętlami działającymi na danych w miejscu. Jedną z myśli
przewodnich numeryki jest bowiem szybkość, a rezygnacja z barokowych konstrukcji językowych jest zgodna z filozofią architektury procesora RISC: efektywność przez prostotę.
(Na pewno zastanawiasz się teraz, jaka jest druga myśl przewodnia numeryki. To dokładność.)
Podstawienie
Najprostsza z instrukcji, bez której nie można się obejść:z = <math>\displaystyle {\cal W}</math>;
Wyrażeniem jest pojedyncza stała lub zmienna, albo złożenie skończonej liczby operacji elementarnych na wyrażeniach. Operacje elementarne to:
- arytmetyczno--arytmetyczne
- , ,
- arytmetyczno--logiczne
- ,
- logiczno--logiczne
- ,
Dla niektórych zadań wygodnie jest uzupełnić ten zbiór o dodatkowe operacje, takie jak obliczanie wartości niektórych standardowych funkcji matematycznych ( itp.), czy nawet funkcji bardziej skomplikowanych. Na przykład, zastosowanie "szkolnych" wzorów na obliczanie pierwiatków równania kwadratowego byłoby niemożliwe, gdyby pierwiastkowanie było niemożliwe.
Uwaga
Należy pamiętać, że w praktyce funkcje standardowe (o ile są
dopuszczalne) są obliczane przy użyciu czterech podstawowych operacji
arytmetycznych. Dokładniej, jednostka arytmetyczna procesora potrafi wykonywać
jedynie operacje ,
przy czym dzielenie zajmuje kilka razy
więcej czasu niż pozostałe operacje arytmetyczne. Niektóre procesory
(np. Itanium 2) są w stanie wykonywać niejako jednocześnie operację
dodawania i mnożenia (tzw.
FMADD
, fused multiply and add).
Praktycznie wszystkie współczesne procesory mają także wbudowany
koprocesor matematyczny, realizujący asemblerowe polecenia wyznaczenia
wartości standardowych funkcji matematycznych ( itp.), jednak wykonanie takiej instrukcji wymaga mniej więcej kilkadziesiąt razy więcej czasu
niż wykonanie operacji dodawania.
Uwaga
Mamy trzy podstawowe polecenia złożone: warunkowe, powtarzania i kombinowane.
Niestety, aby nasz model obliczeniowy wiernie odpowiadał rzeczywistości, musimy
w nim uwzględnić fakt, że nawet podstawowe działania arytmentyczne (i, tym bardziej,
obliczanie wartości funkcji matematycznych) nie są wykonywane dokładnie.
Czasem
uwzględnienie tego faktu wiąże się ze znaczącym wzrostem komplikacji analizy
algorytmu i dlatego "w pierwszym przybliżeniu" często pomija się to
ograniczenie przyjmując model, w którym wszystkie (lub prawie wszystkie)
działania arytmetyczne wykonują się dokładnie. Wiedza o tym, kiedy i
jak zrobić to tak, by wciąż wyciągać prawidłowe wnioski
odnośnie faktycznej realizacji algorytmów w obecności błędów zaokrągleń
jest częścią sztuki i wymaga intuicji numerycznej, popartej
doświadczeniem.
Warunkowe
if(<math>\displaystyle \cal W</math>) <math>\displaystyle {\cal A}_1</math>; else <math>\displaystyle {\cal A}_2</math>;
Powtarzane
while(<math>\displaystyle {\cal W}</math>) <math>\displaystyle {\cal A}</math>;
Kombinowane
{ <math>\displaystyle {\cal A}_1;\displaystyle {\cal A}_2;\displaystyle \ldots\displaystyle {\cal A}_n;</math> }
Na podstawie tych trzech poleceń można tworzyć inne, takie jak pętle
for()
, czy instrukcje wariantowe switch()
, itd.
Mamy też dwa szczególne polecenia, które odpowiadają za "wejście" i "wyjście".
Wprowadzanie danych
<math>\displaystyle {\cal IN}</math>(x,t);
Polecenie to pozwala zdobyć informację o danej . Jeśli to zwykle mamy i , co w praktyce odpowiada wczytaniu -tej współrzędnej wektora danych. W szczególności, ciąg poleceń , , pozwala uzyskać pełną informację o . Jeśli zaś jest pewną klasą funkcji , to możemy mieć np. i . W tym przypadku, wykonanie polecenia odpowiada w praktyce skorzystaniu ze specjalnej procedury (albo urządzenia zewnętrznego) obliczającej (mierzącego) wartość funkcji w punkcie .
Wyprowadzanie wyników
<math>\displaystyle {\cal OUT}</math>(<math>\displaystyle {\cal W}</math>);
Zakładamy, że na początku procesu obliczeniowego wartości wszystkich zmiennych są nieokreślone, oraz że dla dowolnych danych wykonanie programu wymaga wykonania skończonej liczby operacji elementarnych. Wynikiem obliczeń jest skończony ciąg liczb rzeczywistych (albo ), którego kolejne współrzędne pokazywane są poleceniem
Brak komentarzy:
Prześlij komentarz