MN01LAB: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Przykry (dyskusja | edycje)
m Zastępowanie tekstu – „,↵</math>” na „</math>,”
 
(Nie pokazano 6 wersji utworzonych przez 3 użytkowników)
Linia 1: Linia 1:
<!--  
<!--  
Konwertowane  z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/&nbsp;pawlik1/latex2mediawiki.php
Konwertowane  z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/&nbsp;pawlik1/latex2mediawiki.php.
Niezb�dne rozszerzenia i modyfikacje oryginalnego latex2mediawiki
wprowadzi� przykry@mimuw.edu.pl
-->
-->
   
   
=Ćwiczenia. Eksperymenty ze środowiskiem obliczeń numerycznych=
=Eksperymenty ze środowiskiem obliczeń numerycznych=


W Linuxie, czas działania programu można zbadać poleceniem <code>time</code>.
{{powrot |Metody numeryczne | do strony głównej
przedmiotu <strong>Metody numeryczne</strong>}}
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Oglądaj wskazówki i rozwiązania __SHOWALL__<br>
Ukryj wskazówki i rozwiązania __HIDEALL__
</div>
 
W Linuxie czas działania programu można zbadać poleceniem <code style="color: #666">time</code>.


<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
Linia 12: Linia 21:
<div class="exercise">
<div class="exercise">


Który program wykona się szybciej:
Który z poniższych programów wykona się szybciej?
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
 
<div style="margin: 1em; padding:1em; color: #000; background-color:#fcfcfc;"><pre>x = 1.0;
x = 1.0;
for( i = 0; i < N; i++)
for( i = 0; i < N; i++)
x = x/3.0;  
x = x/3.0;  
Linia 21: Linia 29:
   
   
czy
czy
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #000; background-color:#fcfcfc;"><pre>x = 1.0; f = 1.0/3.0;
x = 1.0; f = 1.0/3.0;
for( i = 0; i < N; i++)
for( i = 0; i < N; i++)
x = x*f;  
x = x*f;  
Linia 32: Linia 38:
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em">   
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em">   
Oczywiście, szybszy będzie program nie wykorzystujący dzielenia. Optymalizujący
Oczywiście, szybszy będzie program nie wykorzystujący dzielenia. Optymalizujący
kompilator (<code>gcc -O3</code>) strawi, a nawet będzie jeszcze bardziej zadowolony z pozornie
kompilator (<code style="color: #666">gcc -O3</code>) strawi, a nawet będzie jeszcze bardziej zadowolony z pozornie
rozrzutnego kodu  
rozrzutnego kodu  
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #000; background-color:#fcfcfc;"><pre>x = 1.0;  
x = 1.0;  
for( i = 0; i < N; i++)
for( i = 0; i < N; i++)
x = x*(1.0/3.0);  
x = x*(1.0/3.0);  
</pre></div>
</pre></div>
   
   
dlatego, że stałą, przez którą trzeba mnożyć <math>\displaystyle x</math>, wyliczy przed wykonaniem
dlatego, że stałą, przez którą trzeba mnożyć <math>x</math>, wyliczy przed wykonaniem
programu.  
programu.  


Sprawdź, czy z wyłączoną optymalizacją ten kod okaże się najwolniejszy
Sprawdź, czy z wyłączoną optymalizacją ten kod okaże się najwolniejszy ze wszystkich... (okazuje się, że nie!)
ze wszystkich...  
(okazuje się, że nie!)


</div></div></div>
</div></div></div>
Linia 58: Linia 60:
* binarnego
* binarnego
   
   
kolejne wartości <math>\displaystyle \sin(\pi\cdot i\cdot 0.4)</math>, gdzie <math>\displaystyle i=0,\ldots, 1024</math>. Następnie porównaj
kolejne wartości <math>\sin(\pi\cdot i\cdot 0.4)</math>, gdzie <math>i=0,\ldots, 1024</math>. Następnie porównaj
rozmiary plików i możliwości ich odczytania zewnętrznymi narzędziami. Wreszcie,
rozmiary plików i możliwości ich odczytania zewnętrznymi narzędziami. Wreszcie,
wczytaj liczby z pliku i porównaj je z oryginalnymi wartościami sinusa. Czy
wczytaj liczby z pliku i porównaj je z oryginalnymi wartościami sinusa. Czy
Linia 70: Linia 72:
Różnice są skutkiem konwersji liczb zmiennoprzecinkowych do formatu
Różnice są skutkiem konwersji liczb zmiennoprzecinkowych do formatu
dziesiętnego. Oczywiście, zapis w formacie binarnym daje dokładną kopię
dziesiętnego. Oczywiście, zapis w formacie binarnym daje dokładną kopię
zawartości pamięci, więc nie ma żadnych strat.
zawartości pamięci, nie ma więc żadnych strat.
</div></div></div>
</div></div></div>


Linia 77: Linia 79:
<div class="exercise">
<div class="exercise">


Pomyśl, jak obliczać, korzystając jedynie z czterech działań podstawowych: <math>\displaystyle +,\,
Pomyśl, jak obliczać, korzystając jedynie z czterech działań podstawowych: <math>+,\,
-, \, \times, \, \div</math>, wartość funkcji <code>exp(</code><math>\displaystyle x</math><code>)</code> = <math>\displaystyle e^x</math> dla
-, \, \times, \, \div</math>, wartość funkcji <code>exp(</code><math>x</math><code>)</code> = <math>e^x</math> dla
dowolnych <math>\displaystyle x</math> rzeczywistych. Naszym kryterium jest, by <math>\displaystyle |e^x - \exp(x)| \leq
dowolnych <math>x</math> rzeczywistych. Naszym kryterium jest, by <math>|e^x - \exp(x)| \leq
\epsilon</math>, czyli by błąd bezwzględny aproksymacji nie przekroczył zadanego
\epsilon</math>, czyli by błąd bezwzględny aproksymacji nie przekroczył zadanego
<math>\displaystyle \epsilon</math>.
<math>\epsilon</math>.


Wykonaj eksperymenty w C lub w Octave, pokazujące koszt metody w zależności od
Wykonaj eksperymenty w C lub w Octave, pokazujące koszt metody w zależności od
<math>\displaystyle x</math> oraz w zależności od <math>\displaystyle \epsilon</math>. Przeprowadź też sekwencję testów
<math>x</math> oraz w zależności od <math>\epsilon</math>. Przeprowadź też sekwencję testów
potwierdzających Twoje rachunki co do oczekiwanej dokładności (porównując się z
potwierdzających twoje rachunki co do oczekiwanej dokładności (porównując się z
funkcją biblioteczną). W C możesz korzystać ze stałej <code>M_E</code> <math>\displaystyle \approx e =
funkcją biblioteczną). W C możesz korzystać ze stałej <code>M_E</code> <math>\approx e =
\exp(1)</math>, zdefiniowanej w pliku nagłówkowym <code>math.h</code>.
\exp(1)</math>, zdefiniowanej w pliku nagłówkowym <code style="color: #666">math.h</code>.


</div></div>
</div></div>
Linia 94: Linia 96:
W pierwszym odruchu myślimy o szeregu definiującym funkcję wykładniczą,
W pierwszym odruchu myślimy o szeregu definiującym funkcję wykładniczą,


<center><math>\displaystyle
<center><math>
e^x = \sum_{n=0}^\infty \frac{x^n}{n!}
e^x = \sum_{n=0}^\infty \frac{x^n}{n!}
</math></center>
</math></center>
Linia 100: Linia 102:
lub o granicy  
lub o granicy  


<center><math>\displaystyle
<center><math>
e^x = \lim_{n\rightarrow \infty} \left( 1 + \frac{x}{n}\right)^{\frac{n}{x}}.
e^x = \lim_{n\rightarrow \infty} \left( 1 + \frac{x}{n}\right)^{\frac{n}{x}}</math></center>
</math></center>


Drugi pomysł okazuje się niewypałem, między innymi dlatego, że musi korzystać z operacji
Drugi pomysł okazuje się niewypałem między innymi dlatego, że musi korzystać z operacji
potęgowania z wykładnikiem rzeczywistym (którą skądinąd najprościej
potęgowania z wykładnikiem rzeczywistym (którą skądinąd najprościej
implementować korzystając m.in. z funkcji <math>\displaystyle \exp</math>, jako <math>\displaystyle x^y = \exp(y\cdot \log(x))</math>).  
implementować korzystając m.in. z funkcji <math>\exp</math>, jako <math>x^y = \exp(y\cdot \log(x))</math>).  


Przyjrzyjmy się więc pierwszemu.
Przyjrzyjmy się więc pierwszemu.


<center><math>\displaystyle
<center><math>
e^x \approx \sum_{n=0}^N \frac{x^n}{n!},
e^x \approx \sum_{n=0}^N \frac{x^n}{n!}</math>,</center>
</math></center>


a dokładniej, ze wzoru na resztę w postaci Lagrange'a,
a dokładniej, ze wzoru na resztę w postaci Lagrange'a,


<center><math>\displaystyle
<center><math>
|e^x - \sum_{n=0}^N \frac{x^n}{n!} | \leq \frac{|\xi|^{N+1}}{(N+1)!}.
|e^x - \sum_{n=0}^N \frac{x^n}{n!} | \leq \frac{|\xi|^{N+1}}{(N+1)!}</math></center>
</math></center>


Stąd dostajemy oszacowanie, oznaczając wartość szeregu obciętego na <math>\displaystyle N</math>-tym
Stąd dostajemy oszacowanie, oznaczając wartość szeregu obciętego na <math>N</math>-tym
wyrazie,
wyrazie,
<center><math>\displaystyle
<center><math>
\exp(x,N) = \sum_{n=0}^N \frac{x^n}{n!},
\exp(x,N) = \sum_{n=0}^N \frac{x^n}{n!}</math>,</center>
</math></center>
   
   
<center><math>\displaystyle
<center><math>
\left||e^x - \exp(x,N)  \right| \leq \frac{|x|^{N+1}}{(N+1)!},  
\left|e^x - \exp(x,N)  \right| \leq \frac{|x|^{N+1}}{(N+1)!},  
</math></center>
</math></center>


tak więc <math>\displaystyle N</math> musi być takie, że <math>\displaystyle \frac{|x|^{N+1}}{(N+1)!} \leq \epsilon</math>.
tak więc <math>N</math> musi być takie, że <math>\frac{|x|^{N+1}}{(N+1)!} \leq \epsilon</math>.


Poniżej mamy kod, który to realizuje  w Octave (analogiczny program w C napisz
Poniżej mamy kod, który to realizuje  w Octave (analogiczny program w C napisz samodzielnie):
samodzielnie):


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function [y, N] = expa(x, epsilon)
function [y, N] = expa(x, epsilon)
y = skladnik = 1.0; N = 1;
y = skladnik = 1.0; N = 1;
while (abs(skladnik) > epsilon)
while (abs(skladnik) > epsilon)
Linia 145: Linia 140:
end
end
end
end
</pre></div>
</pre></div>  
   
   
Możesz go przetestować pod względem osiąganej dokładności i kosztu, porównując się z
Możesz go przetestować pod względem osiąganej dokładności i kosztu, porównując się z
funkcją biblioteczną:
funkcją biblioteczną:


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function [blad, relblad, koszt] = testexp(expX, x)
function [blad, relblad, koszt] = testexp(expX, x)
dokladnie = exp(x);
dokladnie = exp(x);
[wartosc, koszt] = feval(expX,x,1e-8);
[wartosc, koszt] = feval(expX,x,1e-8);
Linia 173: Linia 166:
plot(zakres, relblada, ';blad wzgledny;');
plot(zakres, relblada, ';blad wzgledny;');
plot(zakres, blada, ';blad bezwzgledny;');
plot(zakres, blada, ';blad bezwzgledny;');
</pre></div>
</pre></div>  
   
   
Zgodnie z oczekiwaniami, błąd jest poniżej zadanej tolerancji, tutaj: <math>\displaystyle 10^{-8}</math>.
Zgodnie z oczekiwaniami, błąd jest poniżej zadanej tolerancji, tutaj <math>10^{-8}</math>.


[[Image:MNbladwzglednyexpa.png|thumb|450px|center|Błąd względny aproksymacji wielomianem Taylora.]]
[[Image:MNbladwzglednyexpa.png|thumb|550px|center|Błąd względny aproksymacji wielomianem Taylora.]]


Jednak koszt aproksymacji rośnie wraz z <math>\displaystyle x</math>:
Koszt aproksymacji rośnie wraz z <math>x</math>:


[[Image:MNkosztexpa.png|thumb|450px|center|Koszt aproksymacji wielomianem Taylora.]]
[[Image:MNkosztexpa.png|thumb|550px|center|Koszt aproksymacji wielomianem Taylora.]]


Niektóre wyniki mogą Cię jednak zaskoczyć:  
Niektóre wyniki mogą Cię jednak zaskoczyć:  
* Błąd bezwzględny przekracza założoną wartość, gdy <math>\displaystyle \epsilon = 2.2\cdot
* Błąd bezwzględny przekracza założoną wartość, gdy <math>\epsilon = 2.2\cdot 10^{-15}</math>, a błąd względny od pewnego momentu <strong>rośnie</strong> z <math>x</math>. [[Image:MNbladbezwzglednyexpaeps.png|thumb|550px|center|Błąd względny aproksymacji wielomianem Taylora dla zadanej bardzo małej tolerancji błędu.]]
10^{-15}</math>, a błąd względny od pewnego momentu <strong>rośnie</strong> z <math>\displaystyle x</math>.  
* Nie daje się tak policzyć <math>e^{2006}</math>.
[[Image:MNbladbezwzglednyexpaeps.png|thumb|450px|center|Błąd względny aproksymacji wielomianem Taylora dla zadanej bardzo małej
* Wartość <code style="color: #006">expa()</code> może być ujemna dla <math>x<0</math>.
tolerancji błędu.]]
* Nie daje się tak policzyć <math>\displaystyle e^{2006}</math>.
* Wartość <code>expa()</code> może być ujemna dla <math>\displaystyle x<0</math>.
   
   
Wyjaśnienie tych szokujących faktów (które nie mają nic wspólnego z błędem w
Wyjaśnienie tych szokujących faktów (które nie mają nic wspólnego z błędem w
implementacji) musisz odłożyć do momentu, gdy bliżej przyjrzymy się temu, <strong>jak</strong>
implementacji) musisz odłożyć do momentu, [[MN03|gdy bliżej przyjrzymy się temu, <strong>jak</strong>
liczy komputer.
liczy komputer]].


</div></div></div>
</div></div></div>
Linia 201: Linia 191:
<div class="exercise">
<div class="exercise">


Spróbuj obniżyć koszt wyznaczania <math>\displaystyle \exp(x)</math> dla dużych <math>\displaystyle x</math>!
Spróbuj obniżyć koszt wyznaczania <math>\exp(x)</math> dla dużych <math>x</math>.


<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka </span><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Wskazówka </span><div class="mw-collapsible-content" style="display:none">
<div style="font-size:smaller; background-color:#efe"> Rzecz w tym, że dla dużych <math>\displaystyle x</math>, trzeba wziąć bardzo dużo wyrazów w szeregu
<div style="font-size:smaller; background-color:#f9fff9; padding: 1em"> Rzecz w tym, że dla dużych <math>x</math>, trzeba wziąć bardzo dużo wyrazów w szeregu
Taylora. Czy można tak wykombinować, by w rezultacie wziąć ich mniej? </div>
Taylora. Czy można tak wykombinować, by w rezultacie wziąć ich mniej? </div>
</div></div>
</div></div>
Linia 212: Linia 202:
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em">   
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"><div style="margin-left:1em">   


Bez zmieniejszenia ogólności, załóżmy, że <math>\displaystyle x\geq 0</math>.
Bez zmieniejszenia ogólności, załóżmy, że <math>x\geq 0</math>.


Jeśli <math>\displaystyle x = k + t</math>, gdzie <math>\displaystyle t \in [0,1)</math>, a <math>\displaystyle k</math> jest całkowite, to oczywiście  
Jeśli <math>x = k + t</math>, gdzie <math>t \in [0,1)</math>, a <math>k</math> jest całkowite, to oczywiście  
<center><math>\displaystyle
<center><math>
e^x = e^{k+t} = e^k e^t = e^k \exp(t).
e^x = e^{k+t} = e^k e^t = e^k \exp(t)</math></center>
</math></center>


Tak więc zadanie redukuje się do wyznaczenia <math>\displaystyle \exp(t)</math> dla <strong>małego</strong> <math>\displaystyle t</math> oraz
Tak więc zadanie redukuje się do wyznaczenia <math>\exp(t)</math> dla <strong>małego</strong> <math>t</math> oraz
do co najwyżej <math>\displaystyle k</math> dodatkowych mnożeń potrzebnych do wyznaczenia całkowitej
do co najwyżej <math>k</math> dodatkowych mnożeń potrzebnych do wyznaczenia całkowitej
potęgi <math>\displaystyle e^k</math> (ile mnożeń <strong>naprawdę</strong> wystarczy?). Pamiętaj, przyjęliśmy, że
potęgi <math>e^k</math> (ile mnożeń <strong>naprawdę</strong> wystarczy?). Pamiętaj, przyjęliśmy, że
znamy reprezentację numeryczną liczby <math>\displaystyle e</math>.
znamy reprezentację numeryczną liczby <math>e</math>.


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre># wersja B
[Wersja B]
function [y, N] = expb(x, epsilon)
function [y, N] = expb(x, epsilon)
k = floor(x); t = x - k;  
k = floor(x); t = x - k;  
Linia 234: Linia 222:
N += (k+2);
N += (k+2);
end
end
</pre></div>
</pre></div>  
   
   
[[Image:MNkosztexpab.png|thumb|450px|center|Wersja B jest istotnie tańsza.]]
[[Image:MNkosztexpab.png|thumb|550px|center|Wersja B jest istotnie tańsza.]]


</div></div></div>
</div></div></div>

Aktualna wersja na dzień 21:51, 11 wrz 2023


Eksperymenty ze środowiskiem obliczeń numerycznych

<<< Powrót do strony głównej przedmiotu Metody numeryczne

Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__

W Linuxie czas działania programu można zbadać poleceniem time.

Ćwiczenie

Który z poniższych programów wykona się szybciej?

x = 1.0;
for( i = 0; i < N; i++)
	x = x/3.0; 

czy

x = 1.0; f = 1.0/3.0;
for( i = 0; i < N; i++)
	x = x*f; 
Rozwiązanie

Ćwiczenie

Napisz program w C, który zapisuje do pliku

  • tekstowego
  • binarnego

kolejne wartości sin(πi0.4), gdzie i=0,,1024. Następnie porównaj rozmiary plików i możliwości ich odczytania zewnętrznymi narzędziami. Wreszcie, wczytaj liczby z pliku i porównaj je z oryginalnymi wartościami sinusa. Czy możesz wyjaśnić przyczyny różnic?

Powtórz to samo w Octave.

Rozwiązanie

Ćwiczenie: Implementacja funkcji matematycznych

Pomyśl, jak obliczać, korzystając jedynie z czterech działań podstawowych: +,,×,÷, wartość funkcji exp(x) = ex dla dowolnych x rzeczywistych. Naszym kryterium jest, by |exexp(x)|ϵ, czyli by błąd bezwzględny aproksymacji nie przekroczył zadanego ϵ.

Wykonaj eksperymenty w C lub w Octave, pokazujące koszt metody w zależności od x oraz w zależności od ϵ. Przeprowadź też sekwencję testów potwierdzających twoje rachunki co do oczekiwanej dokładności (porównując się z funkcją biblioteczną). W C możesz korzystać ze stałej M_E e=exp(1), zdefiniowanej w pliku nagłówkowym math.h.

Rozwiązanie

Ćwiczenie: Ciag dalszy

Spróbuj obniżyć koszt wyznaczania exp(x) dla dużych x.

Wskazówka
Rozwiązanie