W niniejszym rozdziale dokonujemy rozróżnienia między dwiema ważnymi w praktyce koncepcjami przetwarzania. Porównujemy je pod względem możliwości i ograniczeń. Rozdział ma charakter wstępny, jego celem jest uświadomienie, jakich efektów można — lub nie można — spodziewać się przy zastosowaniu oprogramowania realizującego obliczenia wg tych koncepcji.
Obliczenia numeryczne, rozumiane jako działania na wartościach, są podstawowym środkiem przetwarzania w większości współczesnych języków programowania, arkuszy kalkulacyjnych, środowisk obliczeń naukowych i inżynierskich oraz środowisk prezentacji danych.
Podstawą obliczeń numerycznych jest — jak wskazuje nazwa — wykonywanie operacji arytmetycznych na liczbach, czyli na konkretnych wartościach danych liczbowych. Przy przetwarzaniu tego typu wszystkie dane wejściowe, dane pośrednie i wyniki są liczbami lub ciągami liczb.
Wyrażenia arytmetyczne są w obliczeniach numerycznych traktowane jak instrukcje do wykonania.
Na przykład wyrażenie
fx := 1 + x*sin(2*x)
może zostać zinterpretowane następująco:
weź bieżącą wartość zmiennej
x
,
pomnóż ją przez 2,
wynik przekaż na wejście funkcji o nazwiesin
,
wynik pomnóż przez wartość zmiennejx
,
wynik zwiększ o 1,
a wartość liczbową, która ci wyjdzie, zapamiętaj w zmiennejfx
.
Jednokrotne wykonanie polecenia powoduje nadanie wartości zmiennej
fx
, stosownie do wartości zmiennej x
.
Jeżeli możliwe jest wykorzystanie funkcji (np. sin
),
to tylko jako algorytmu obliczającego pewne wyniki na podstawie
dostarczonych danych liczbowych. Obliczona za jej pomocą
wartość wynikowa jest także tylko zwykłą daną liczbową.
Wynika z tego, że przy programowaniu obliczeń numerycznych opracowanie i przekształcenie wszystkich formuł leży w gestii autora algorytmu i programu.
Środowiska numeryczne na ogół umożliwiają użytkownikowi deklarowanie własnych funkcji, tak jak w poniższych przykładach:
{ pseudojęzyk zbliżony do języka programowania Pascal } function fx(x: double): double; begin x := x/(1.0+sqr(x)); fx := 1.0 + x*sin(2.0*x); end;
/* pseudojęzyk zbliżony do języka programowania C */ double fx(double x) { x = x/(1.0+x^2); return 1.0 + x*sin(2.0*x); }
# pseudojęzyk zbliżony do języka programowania Python def fx(x): x = x/(1.0+x**2) return 1.0 + x*math.sin(2.0*x)
Jedynym sposobem wykorzystania takiej funkcji jest używanie jej do obliczeń. Za każdym użyciem funkcja zwraca dla konkretnej liczbowej wartości argumentu konkretny wynik liczbowy. W ciągu skończonego czasu jesteśmy w stanie uzyskać tym sposobem tylko skończenie wiele takich informacji.
Obliczenia symboliczne, rozumiane jako działania na definicjach obiektów, są środkiem przetwarzania stosowanym w specjalistycznych środowiskach obliczeniowych o orientacji naukowej, inżynieryjnej i dydaktycznej.
W przeciwieństwie do obliczeń numerycznych, obliczenia symboliczne zajmują się przetwarzaniem wyrażeń. Obiektami rozpatrywanymi podczas takich obliczeń są: stałe, wyrażenia, zmienne, funkcje. Istnieje wiele sposobów praktycznej reprezentacji obiektów symbolicznych; najprostszym z nich jest korzystanie z danych typu napisowego.
Przy przetwarzaniu symbolicznym deklarowane wyrażenia są traktowane jak deklaracje związków między danymi.
Na przykład wyrażenie
fx := a + x*sin(2*x)
może zostać zinterpretowane następująco:
utwórz obiekt o nazwie
fx
, którego bieżąca wartość będzie związana z wartością obiektów o nazwachx
ia
za pomocą podanej wyżej zależności.
Jednokrotne wykonanie polecenia spowoduje powołanie nowego obiektu, którego wartość
będzie się zmieniać automatycznie za każdym razem, kiedy zmodyfikujemy wartość
x
. Więcej, do przeprowadzenia obliczeń nie są konieczne konkretne
wartości liczbowe x
i a
— mogą one zawierać np.
formuły arytmetyczne. Jeszcze więcej: z tak określonej zależności będzie się
dało korzystać w celu przekształcania użytych w niej wyrażeń.
W środowiskach przetwarzania symbolicznego możliwe jest deklarowanie funkcji, które nie tylko opisują algorytm, ale same mogą podlegać przetwarzaniu jako dane. Rozpatrzmy poniższy przykład:
/* pseudojęzyk zbliżony do notacji programu Maxima */ fx(x) := (u : x/(1 + x^2), 1 + u*sin(2*u));
Zadeklarowanej funkcji można używać jako algorytmu odpowiedzialnego
za fragment obliczeń, ale dane wejściowe nie muszą być danymi liczbowymi.
Da się też zrobić dużo więcej: funkcja fx
jako obiekt może być
analizowana i przekształcana przez inne algorytmy. Na przykład można
zadeklarować funkcję, która będzie równa pochodnej funkcji fx
,
a następnie obliczać jej wartości:
/* pseudojęzyk zbliżony do notacji programu Maxima */ fxprim(x) := ''diff(fx(x), x); g(t) := fx(t) * sqrt(1 + fxprim(t)^2);
System nie wymaga nawet faktycznego istnienia funkcji fx
w momencie złożenia powyższej deklaracji.
Oczywiście za tak szerokimi możliwościami użytkowymi stoją zaawansowane techniki reprezentacji i przetwarzania danych.