GNU Octave
kurs elementarny

Funkcje użytkownika

Definiowanie funkcji

W poprzedniej części kursu wyjaśniłem, jak łatwo w Octave można utworzyć własne programy (tzw. skrypty). Funkcje użytkownika najłatwiej można zdefiniować właśnie w formie skryptów.

Załóżmy, że naszym celem jest zdefiniowanie funkcji o nazwie sin5, która dla argumentu x obliczać będzie wartość wyrażenia x - x3/6 + x5/120. Aby zdefiniować taką funkcję:

  1. Tworzymy (w katalogu bieżącym) plik o nazwie sin5.m
  2. W pliku tym wpisujemy:
    function y = sin5(x)
       y = x - x**3/6 + x**5/120;
    endfunction
    

Uwaga! Powyższa definicja nie jest optymalna! Niedługo ją poprawimy!

Funkcje tę wywołujemy w Octave w naturalny sposób:

> sin5 (0.1)
ans =  0.099833

Ogólnie, podczas definiowania funkcji w pliku obowiązują następujące zasady:

Odwzorowania

W wielu językach programowania, w tym w Octave, istnieje możliwość wywoływania funkcji (np. matematycznych) z argumentami wektorowymi lub macierzowymi. Takie funkcje nazywa się odwzorowaniami (ang. maps lub mapping functions). Jedną z takich funkcji w Octave jest cos, czyli funkcja wyznaczająca cosinus kąta:
> cos([0, 0.1, 0.2])
ans =
   1.00000   0.99500   0.98007

Jak widać, jeżeli argumentem funkcji cos jest wektor, wynikiem jest wektor utworzony z wartości tej funkcji dla wszystkich elementów wektora [0, 0.1, 0.2], czyli

cos([0, 0.1, 0.2]) = [cos(0), cos(0.1), cos(0.2)]

Ogólnie, jeżeli f jest odwzorowaniem, a v macierzą n na m, to f(v) też jest macierzą n na m, przy czym jeżeli podstawimy w = f(v), to spełniona będzie zależność w(k,l) = f(v(k,l)). Innymi słowy, w k-tym wierszu i l-tej kolumnie macierzy f(v) znajduje się wartość funkcji f dla argumentu v(k,l).

Informacja o tym, czy dana funkcja Octave jest odwzorowaniem, znajduje się w dokumentacji tej funkcji (help), w której odwzorowania określane są jako mapper function lub mapping function, zwykle już w pierwszym wierszu opisu.

Odwzorowania są w Octave bardzo ważną klasą funkcji, gdyż umożliwiają rozwiązywanie wielu podstawowych problemów numerycznych, takich jak znajdowanie pierwiastków równań z wieloma niewiadomymi, rozwiązywanie równań różniczkowych czy obliczanie pól powierzchni (całek), a także tworzenie wykresów funkcji.

Operatory „z kropką”

Jak można się łatwo przekonać, nasza funkcja sin5 nie jest odwzorowaniem i nie można jej wywoływać z argumentami innymi niż skalary, co znacznie ogranicza jej użyteczność. Można temu jednak łatwo zaradzić. Aby funkcja sin5 stała się odwzorowaniem, wystarczy poprzedzić kropką wszystkie występujące w jej definicji operatory potęgowania:

function y = sin5(x)
   y = x - (x.**3)/6 + (x.**5)/120;
endfunction

Ogólnie, kropką można poprzedzić dowolny operator "iloczynowy", czyli operator mnożenia (.*, dzielenia (./ lub .\) i potęgowania (.** lub .^). To, kiedy stosować tę kropkę, zależy od następujących czynników:

Na zakończenie warto dodać, że jeżeli w pliku zawierającym definicję funkcji umieścimy komentarz (najlepiej przed jej definicją), będzie on wyświetlany przez Octave po wydaniu polecenia help nazwa_funkcji (np. help sin5). Stąd też ostateczna zawartość pliku sin5.m może wyglądać następująco:

# Funkcja sin5 przybliża wartość funkcji sin(x) za pomocą wielomianu stopnia 5.
#
# Przybliżenie to jest całkiem dobre dla małych wartości x, 
# np. dla |x| < 1.  
#

function y = sin5(x)
   y = x - x.**3/6 + x.**5/120; 
endfunction

Quiz

  1. Dlaczego definicje funkcji zwykle umieszcza się w osobnych plikach?
  2. Jaka jest rola słów kluczowych function i endfunction?
  3. Czy funkcja może zwracać wiele wartości?
  4. Dlaczego zapis instrukcji funkcji z reguły kończy się średnikiem?
  5. Co to są odwzorowania?
  6. Jak sprawdzić, czy dana funkcja Octave jest odwzorowaniem?
  7. Jak definiuje się własne odwzorowania?
  8. Jaka jest różnica między x*y i x.*y?
  9. Jaka jest różnica między x/y i x./y?
  10. Jaka jest różnica między x**2 i x.**2?
  11. Jaka jest różnica między x+y i x.+2?

Zadania

  1. Zdefiniuj funkcję f(x) zadaną wzorem:

    f(x) = x * sin2(x) * sqrt (abs (1 - x)) + x*cos(x)

    gdzie sqrt oznacza pierwiastek kwadratowy, a abs to wartość bezwzględna.
  2. Wykonaj wykres f(x) dla 0 ≤ x ≤ 2.5. W tym celu możesz użyć następującego ciągu poleceń:
    > x = 0 : 0.001 : 2.5;
    > y = f(x);
    > plot (x,y)	
    	
    Pierwsze z nich definiuje wektor "x-ów", drugie – wektor wartości w odpowiednich "x-ach", a trzecie powoduje wygenerowanie takiego wykresu jak ten:

    wykres funkcji

  3. Z wykresu wynika, że równanie f(x) = 0 ma pierwiastek z równy w przybliżeniu 2.2. Wyznacz jego wartość za pomocą polecenia fsolve:
    > z = fsolve("f", 2.2)
    
  4. Oblicz pole powierzchni pomiędzy wykresem funkcji f(x) dla 0 ≤ x ≤ z a osią rzędnych (tj. y = 0) (na poniższym rysunku zostało ono zaznaczone kolorem zielonym):

    wykres funkcji

    Możesz posłużyć się następującym poleceniem:

    
    > quad("f", 0, z)
    
  5. Zapoznaj się z dokumentacją funkcji quad i fsolve. Jakie jest znaczenie ich parametrów? Jak można ocenić dokładność rozwiązań?