06
kwi
08

silnia wyjątkowa

Zadanie:
Zaimplementuj jako metody klasy Testy rekurencyjne wersje funkcji silnia(int n) oraz fib(int n) obliczające silnię oraz n-ty wyraz ciągu Fibonacciego; które wynik przekazują poprzez wyjątek. Chodzi o to, aby zamiast instrukcji return zgłosić wyjątek, którego atrybut lub pole będzie zawierało wynik obliczeń. Zaprogramuj też dla porównania „zwykłe” wersje rekurencyjne tych metod i zbadaj, która wersja jest szybsza.

Warto jakoś zacząć - najlepiej od łatwiejszej silni. Zaimplementujemy więc “zwykłą” rekurencyjną silnię

public int silnia_r(int n) {
if (n <= 1) {
return 1;
}
else {
return n * silnia_r(n-1);
}
}

Zmodyfikujmy sobie trochę treść zadania  i dorzućmy do testów jeszcze iteracyjne wersje:

public int silnia_i(int n) {
int value = 1;
for (; n > 1; n–) {
value *= n;
}
return value;
}

Kolejną rzeczą do zrobienia jest zaprojektowanie naszego wyjątku spełniającego postawiony przed nim cel: przekazanie wartości wyliczonej silni:

class FactorialExc extends Exception {
FactorialExc() { super(); }
public int value = 1;
}

Zostaje nam do napisania klasa Testy której publiczna metodą będzie funkcja wyrzucająca wyjątek FactorialExc. Możemy skorzystać tutaj z faktu ze w rzeczywistości wykonując throw … wyrzucamy tak na prawdę referencje, stąd zamiast tworzyć przy każdym rekurencyjnym wyrzuceniu nowy wyjątek możemy utworzyć go jako pole klasy.

class Testy {
private FactorialExc FacExc = new FactorialExc();

public void silnia (int n) throws FactorialExc {
try {
throw FacExc;
}
catch (MyExc e)
{
if (n > 1)
{
e.silnia *= n;
silnia(n-1);
}
else
{
throw e;
}
}
}
}

Jak nasz kod działa? Wywołując metodę silnia(n) w jej wnętrzu wyrzucamy wyjątek w którego obsłudze liczymy silnie - jeżeli jest co liczyć, w przeciwnym wypadku - gdy zakończymy już nasze obliczenia - wyrzucamy referencje obiektu wyjątku do zewnętrznego bloku, już obsługującego pierwotne wywołanie metody liczącej silnie. Ostatnią rzeczą jaką zostaje nam zrobić to obsłużenie ‘otrzymywania wyniku’, gdzie test jest instancja klasy Testy:

try {
test.silnia_w(5);
}
catch (MyExc e) {
System.out.println(”Silnia: ” + e.value);
}

Implementacja “Fibonacciego wyjątkowo” (czy też “wyjątkowego Fibonacciego”) jest zbliżona do silni, niemniej jest parę ciekawych kwestii. Pierwszą standardową metodą liczenia Fibonacciego dla pewnego n jest oczywiście wywołanie value = fib(n-1) + fib(n-2) (odpowiadające prostej rekurencyjnej funkcji), nie pozwalamy sobie jednak na wykorzystanie returna, co więcej Java implementuje tzn. watki bez nawrotów, czyli po przerwaniu obliczeń i obsłużeniu wątku, nie odtwarzamy stanu obliczeń - przechodzimy do kolejnego kodu (oczywiście możemy samemu emulować wznowienie obliczeń). Naiwna wersja obliczeń odpada. Potrzebujemy więc pewien model obliczeń odpowiadający naszej rekurencyjno-iteracyjnej naturze wyrzucania wątków zastosowanej w obliczeniu silni:

public int fib_i(int i) {
if (i = 2; i–) {
c = a+b;
a = b;
b = c;
}
return c;
}

Iteracyjny Fibonacci jest odpowiedni do naszej koncepcji, zostaje nam dostosować klasę wyjątku:

class FibonacciExc extends Exception {
FibonacciExc() {
super();
}
public int fibM1 = 1, fibM2 = 1, value = 1;
}

fibM1 oraz fibM2 odpowiadają wartością zwracanym przez fib(n-1) oraz fib(n-2) natomiast value reprezentuje obliczony wynik fib(n). Rozszerzając klasę Testy dodajemy do jej definicji następujące połączenie iteracyjnego Fibonacciego oraz ‘wyjątkowej silni’:

FibonacciExc FibExc = new FibonacciExc();
public void fib(int i) throws FibonacciExc {
try {
throw FibExc;
}
catch (FibonacciExc e) {
if (i < 2) {
throw e;
}
else {
e.value = e.fibM1 + e.fibM2;
e.fibM2 = e.fibM1;
e.fibM1 = e.fib;
fib_w(i-1);
}
}
}

Utworzona w ten sposób metoda obsługiwana jest identycznie jak test.silnia(n).

Na koniec garść testów dla silnia(25):

Iteracja
real 0m0.117s
user 0m0.056s
sys 0m0.016s

Rekurencja
real 0m0.117s
user 0m0.060s
sys 0m0.016s

Wyjątki
real 0m0.114s
user 0m0.064s
sys 0m0.004s

oraz dla fib(40):

Iteracja
real 0m0.113s
user 0m0.040s
sys 0m0.028s

Rekurencja
real 0m1.311s
user 0m1.308s
sys 0m0.012s

Wyjątki
real 0m0.116s
user 0m0.052s
sys 0m0.020s


0 Odpowiedzi do “silnia wyjątkowa”


  1. Brak komentarzy

Napisz odpowiedź




λ!

Mój aktualny plan
Moja niby strona
Moja nasza-klasa

Kategorie

 

kwiecień 2008
P W Ś C P S N
« mar   maj »
 123456
78910111213
14151617181920
21222324252627
282930