break lines in text
This commit is contained in:
parent
8a5c33459d
commit
5d82188aca
1 changed files with 169 additions and 37 deletions
|
@ -14,7 +14,9 @@
|
|||
|
||||
\textbf{Zad. 1}
|
||||
|
||||
Wyznaczanie iteracyjnie epsilonów maszynowych, liczb maszynowych $eta$ i maksymalnych wartości dla wszystkich dostępnych typów zmiennopozycyjnych zgodnych ze standardem IEEE 754
|
||||
Wyznaczanie iteracyjnie epsilonów maszynowych, liczb maszynowych
|
||||
$eta$ i maksymalnych wartości dla wszystkich dostępnych typów
|
||||
zmiennopozycyjnych zgodnych ze standardem IEEE 754
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
|
@ -22,15 +24,26 @@ Wyznaczanie iteracyjnie epsilonów maszynowych, liczb maszynowych $eta$ i maksym
|
|||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Epsilon maszynowy to najmniejsza wartość dla danego typu zmiennopozycyjnego, dla której spełniona jest następująca nierówność: $1.0 + \varepsilon > 1.0$. Innymi słowami, jest to wartość, która po dodaniu do liczby da nam następną liczbę po niej. Epsilon maszynowy jest odwrotnie proporcjonalny do precyzji typu zmiennopozycyjnego, w którym operujemy.
|
||||
Epsilon maszynowy to najmniejsza wartość dla danego typu
|
||||
zmiennopozycyjnego, dla której spełniona jest następująca
|
||||
nierówność: $1.0 + \varepsilon > 1.0$. Innymi słowami,
|
||||
jest to wartość, która po dodaniu do liczby da nam następną
|
||||
liczbę po niej. Epsilon maszynowy jest odwrotnie proporcjonalny
|
||||
do precyzji typu zmiennopozycyjnego, w którym operujemy.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Epsilon liczę zaczynając od wartości $1.0$ dla danego typu i dzieląc ją przez $2.0$ dopóki $1.0 + \frac{\varepsilon}{2.0} > 1.0$. Podzielenie $\varepsilon$ przez $2.0$ w warunku pętli powoduje wyjście z pętli po otrzymaniu najmniejszej wartości, dla której warunek jest spełniony.
|
||||
Epsilon liczę zaczynając od wartości $1.0$ dla danego typu i
|
||||
dzieląc ją przez $2.0$ dopóki $1.0 + \frac{\varepsilon}{2.0} > 1.0$.
|
||||
Podzielenie $\varepsilon$ przez $2.0$ w warunku pętli powoduje
|
||||
wyjście z pętli po otrzymaniu najmniejszej wartości,
|
||||
dla której warunek jest spełniony.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Porównanie wartości $\varepsilon$ liczonych iteracyjnie, za pomocą funkcji $eps()$ z Julii oraz z headera $\langle float.h \rangle$ biblioteki standardowej języka C:
|
||||
Porównanie wartości $\varepsilon$ liczonych iteracyjnie,
|
||||
za pomocą funkcji $eps()$ z Julii oraz z headera
|
||||
$\langle float.h \rangle$ biblioteki standardowej języka C:
|
||||
|
||||
\begin{table}[h]
|
||||
\begin{adjustbox}{max width=\textwidth}
|
||||
|
@ -45,11 +58,14 @@ Porównanie wartości $\varepsilon$ liczonych iteracyjnie, za pomocą funkcji $e
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Brak wartości Float16 dla headera $\langle float.h \rangle$ wynika z braku 16-bitowego typu zmiennopozycyjnego w standardzie języka C.
|
||||
Brak wartości Float16 dla headera $\langle float.h \rangle$
|
||||
wynika z braku 16-bitowego typu zmiennopozycyjnego w standardzie języka C.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Wartości wyliczone iteracyjnie są identyczne do tych z bibliotek standardowych języków Julia i C, więc jeśli ufamy twórcom tych języków, metoda iteracyjna jest wystarczająco dokładna.
|
||||
Wartości wyliczone iteracyjnie są identyczne do tych z
|
||||
bibliotek standardowych języków Julia i C, więc jeśli ufamy
|
||||
twórcom tych języków, metoda iteracyjna jest wystarczająco dokładna.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
|
@ -57,13 +73,21 @@ Wartości wyliczone iteracyjnie są identyczne do tych z bibliotek standardowych
|
|||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Liczba maszynowa eta to najmniejsza zdenormalizowana wartość dla danego typu zmiennopozycyjnego większa od $0.0$.
|
||||
Liczba maszynowa eta to najmniejsza zdenormalizowana
|
||||
wartość dla danego typu zmiennopozycyjnego większa od $0.0$.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Liczbę eta liczę podobnie do liczby maszynowej epsilon – zaczynam od wartości $1.0$ i dzielę ją przez $2.0$ dopóki warunek $\frac{\eta}{2.0} > 0.0$ jest spełniony. Tak samo jak poprzednio podzielenie $\eta$ przez $2.0$ powoduje wyjście z pętli po otrzymaniu najmniejszej wartości, dla której warunek jest spełniony.
|
||||
Liczbę eta liczę podobnie do liczby maszynowej epsilon –
|
||||
zaczynam od wartości $1.0$ i dzielę ją przez $2.0$ dopóki
|
||||
warunek $\frac{\eta}{2.0} > 0.0$ jest spełniony.
|
||||
Tak samo jak poprzednio podzielenie $\eta$ przez $2.0$
|
||||
powoduje wyjście z pętli po otrzymaniu najmniejszej
|
||||
wartości, dla której warunek jest spełniony.
|
||||
|
||||
Porównanie wartości $\eta$ liczonych iteracyjnie, za pomocą $nextfloat(0.0)$ z Julii oraz wartościami zwróconymi przez funkcję $floatmin()$ dla danego typu zmiennopozycyjnego:
|
||||
Porównanie wartości $\eta$ liczonych iteracyjnie, za
|
||||
pomocą $nextfloat(0.0)$ z Julii oraz wartościami zwróconymi
|
||||
przez funkcję $floatmin()$ dla danego typu zmiennopozycyjnego:
|
||||
|
||||
\begin{table}[h]
|
||||
\begin{adjustbox}{max width=\textwidth}
|
||||
|
@ -78,7 +102,12 @@ Porównanie wartości $\eta$ liczonych iteracyjnie, za pomocą $nextfloat(0.0)$
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Wartości wyliczone iteracyjnie są identyczne do tych zwróconych przez funkcję $nextfloat(0.0)$, ale $floatmin()$ zwraca wartości o wiele większe. Jest tak dlatego, że ta funkcja zwraca wartości znormalizowane, a metoda iteracyjna i funkcja $nextfloat(0.0)$ zwracają wartości zdenormalizowane - takie, których cecha składa się z samych bitów 0.
|
||||
Wartości wyliczone iteracyjnie są identyczne do tych
|
||||
zwróconych przez funkcję $nextfloat(0.0)$, ale $floatmin()$
|
||||
zwraca wartości o wiele większe. Jest tak dlatego, że ta
|
||||
funkcja zwraca wartości znormalizowane, a metoda iteracyjna
|
||||
i funkcja $nextfloat(0.0)$ zwracają wartości zdenormalizowane
|
||||
- takie, których cecha składa się z samych bitów 0.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
|
@ -86,15 +115,31 @@ Wartości wyliczone iteracyjnie są identyczne do tych zwróconych przez funkcj
|
|||
|
||||
\vspace{0.5cm}
|
||||
|
||||
Wartość maksymalną dla danego typu zmiennopozycyjnego liczę zaczynając od $1.0$ dla tego typu. Następnie mnożę tą wartość przez $2.0$ dopóki $max \cdot 2.0 < \infty$ (sprawdzam tę nierówność korzystając z funkcji $isfinite()$). Osiągnięta w ten sposób wartość niekoniecznie jest maksymalna, żeby to zmienić tworzę pomocniczą zmienną $x$, której na początku przypisuję wartość $\frac{max}{2.0}$. Następnie, dopóki $max + x < \infty$ dodaję $x$ do $max$ i dzielę $x$ przez $2.0$.
|
||||
Wartość maksymalną dla danego typu zmiennopozycyjnego
|
||||
liczę zaczynając od $1.0$ dla tego typu. Następnie
|
||||
mnożę tą wartość przez $2.0$ dopóki $max \cdot 2.0 < \infty$
|
||||
(sprawdzam tę nierówność korzystając z funkcji $isfinite()$).
|
||||
Osiągnięta w ten sposób wartość niekoniecznie jest maksymalna,
|
||||
żeby to zmienić tworzę pomocniczą zmienną $x$, której na początku
|
||||
przypisuję wartość $\frac{max}{2.0}$. Następnie, dopóki
|
||||
$max + x < \infty$ dodaję $x$ do $max$ i dzielę $x$ przez $2.0$.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
W przypadku gdyby w ostatniej iteracji pierwszej pętli $max$ nie był maksymalny, ale $max \cdot 2.0$ był nieskończony, zostało nam co najwyżej $max \cdot 2.0 - \varepsilon$ do "`dopełnienia"'. Zaczynamy to "`dopełnianie"' od $\frac{max}{2.0}$ – wiemy, że $max + max = max \cdot 2.0$ będzie nieskończone. W każdej iteracji dodajemy $x$ do $max$ i dzielimy $x$ przez $2.0$. W ten sposób "`dopełnimy"' $max$ do końca i otrzymamy rzeczywistą wartość maksymalną.
|
||||
W przypadku gdyby w ostatniej iteracji pierwszej pętli $max$
|
||||
nie był maksymalny, ale $max \cdot 2.0$ był nieskończony,
|
||||
zostało nam co najwyżej $max \cdot 2.0 - \varepsilon$ do
|
||||
"`dopełnienia"'. Zaczynamy to "`dopełnianie"' od $\frac{max}{2.0}$
|
||||
– wiemy, że $max + max = max \cdot 2.0$ będzie nieskończone.
|
||||
W każdej iteracji dodajemy $x$ do $max$ i dzielimy $x$ przez $2.0$.
|
||||
W ten sposób "`dopełnimy"' $max$ do końca i otrzymamy
|
||||
rzeczywistą wartość maksymalną.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Porównanie wartości maksymalnych liczonych iteracyjnie, za pomocą funkcji $floatmax()$ z Julii oraz z headera $\langle float.h \rangle$ biblioteki standardowej języka C:
|
||||
Porównanie wartości maksymalnych liczonych iteracyjnie,
|
||||
za pomocą funkcji $floatmax()$ z Julii oraz z headera
|
||||
$\langle float.h \rangle$ biblioteki standardowej języka C:
|
||||
|
||||
\begin{table}[h]
|
||||
\begin{adjustbox}{max width=\textwidth}
|
||||
|
@ -109,25 +154,33 @@ Porównanie wartości maksymalnych liczonych iteracyjnie, za pomocą funkcji $fl
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Brak wartości Float16 dla headera $\langle float.h \rangle$ wynika z braku 16-bitowego typu zmiennopozycyjnego w standardzie języka C.
|
||||
Brak wartości Float16 dla headera $\langle float.h \rangle$
|
||||
wynika z braku 16-bitowego typu zmiennopozycyjnego w standardzie języka C.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Wartości wyznaczone iteracyjnie są identyczne do tych zwróconych przez $floatmax()$ jak i tych z headera $\langle float.h \rangle$ z biblioteki standardowej języka C.
|
||||
Wartości wyznaczone iteracyjnie są identyczne do tych
|
||||
zwróconych przez $floatmax()$ jak i tych z headera
|
||||
$\langle float.h \rangle$ z biblioteki standardowej języka C.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
\textbf{Zad. 2}
|
||||
|
||||
Eksperymentalne sprawdzenie słuszności twierdzenia Kahana dla wszystkich typów zmiennopozycyjnych dostępnych w języku Julia.
|
||||
Eksperymentalne sprawdzenie słuszności twierdzenia Kahana dla
|
||||
wszystkich typów zmiennopozycyjnych dostępnych w języku Julia.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Twierdzenie Kahana mówi, że epsilon maszynowy można uzyskać w następujący sposób: $\varepsilon = 3(4/3 - 1) / 1$. Aby sprawdzić wyniki korzystam z funkcji $eps()$ z biblioteki standardowej Julii.
|
||||
Twierdzenie Kahana mówi, że epsilon maszynowy można
|
||||
uzyskać w następujący sposób: $\varepsilon = 3(4/3 - 1) / 1$.
|
||||
Aby sprawdzić wyniki korzystam z funkcji
|
||||
$eps()$ z biblioteki standardowej Julii.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Porównanie wartości epsilonu maszynowego liczonego za pomocą twierdzenia Kahana oraz za pomocą funkcji $eps()$:
|
||||
Porównanie wartości epsilonu maszynowego liczonego za
|
||||
pomocą twierdzenia Kahana oraz za pomocą funkcji $eps()$:
|
||||
|
||||
\begin{table}[h]
|
||||
\begin{adjustbox}{max width=\textwidth}
|
||||
|
@ -142,25 +195,46 @@ Porównanie wartości epsilonu maszynowego liczonego za pomocą twierdzenia Kaha
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Dla typu $Float32$ wartości są identyczne, dla typów $Float16$ i $Float64$ wartości różnią się znakiem - twierdzenie Kahana daje nam wartości ujemne. Wynika to z definicji typów zmiennoprzecinkowych i rozwinięcia liczby $4/3$ binarnie – $1.(10)$. Typy $Float16$, $Float32$ i $Float64$ mają odpowiednio 10, 23 i 52 bity mantysy. Rozwijając $4/3$, na indeksach parzystych dostajemy bit 0, na nieparzystych bit 1. W typach o parzystej ilości bitów w mantysie ($Float16$ i $Float64$) na ostatnim indeksie będzie 0. Mnożąc wartość $4/3 - 1$ przez $3$ otrzymamy wartość minimalnie mniejszą od $1$ Przez co wynik jest ujemny. Z kolei dla typu $Float32$ ostatnim bitem będzie 1, co da nam wartość dodatnią.
|
||||
Dla typu $Float32$ wartości są identyczne, dla typów
|
||||
$Float16$ i $Float64$ wartości różnią się znakiem -
|
||||
twierdzenie Kahana daje nam wartości ujemne. Wynika
|
||||
to z definicji typów zmiennoprzecinkowych i rozwinięcia
|
||||
liczby $4/3$ binarnie – $1.(10)$. Typy $Float16$, $Float32$ i
|
||||
$Float64$ mają odpowiednio 10, 23 i 52 bity mantysy.
|
||||
Rozwijając $4/3$, na indeksach parzystych dostajemy bit 0,
|
||||
na nieparzystych bit 1. W typach o parzystej ilości bitów
|
||||
w mantysie ($Float16$ i $Float64$) na ostatnim indeksie będzie 0.
|
||||
Mnożąc wartość $4/3 - 1$ przez $3$ otrzymamy wartość minimalnie
|
||||
mniejszą od $1$ Przez co wynik jest ujemny. Z kolei dla typu
|
||||
$Float32$ ostatnim bitem będzie 1, co da nam wartość dodatnią.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Twierdzenie Kahana poprawnie liczy epsilon maszynowy jednak trzeba pamiętać o wzięciu modułu z wyniku.
|
||||
Twierdzenie Kahana poprawnie liczy epsilon maszynowy
|
||||
jednak trzeba pamiętać o wzięciu modułu z wyniku.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
\textbf{Zad. 3}
|
||||
|
||||
Eksperymentalne sprawdzenie rozmieszczenia liczb zmiennopozycyjnych w arytmetyce $Float64$ w języku Julia.
|
||||
Eksperymentalne sprawdzenie rozmieszczenia liczb
|
||||
zmiennopozycyjnych w arytmetyce $Float64$ w języku Julia.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Aby sprawdzić, czy liczby w przedziale $[1, 2]$ są równomiernie rozmieszczone można zrobić pętlę, w której od $1.0$ do $2.0$ jedną liczbę iterujemy dodając do niej krok $\delta = 2^{-52}$, drugą korzystając z funkcji $nextfloat()$ jednak jest to bardzo nieefektywna metoda.
|
||||
Aby sprawdzić, czy liczby w przedziale $[1, 2]$ są
|
||||
równomiernie rozmieszczone można zrobić pętlę,
|
||||
w której od $1.0$ do $2.0$ jedną liczbę iterujemy
|
||||
dodając do niej krok $\delta = 2^{-52}$, drugą korzystając
|
||||
z funkcji $nextfloat()$ jednak jest to bardzo nieefektywna metoda.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Lepszą metodą jest sprawdzenie pierwszej i ostatniej liczby z przedziału, w naszym przypadku $nextfloat(1.0)$ i $nextfloat(2.0)$. Sprawdzamy cechę obu – jeśli są różne, wyklucza to równomierne rozmieszczenie liczb. W przeciwnym przypadku możemy obliczyć $\delta$ w następujący sposób:
|
||||
Lepszą metodą jest sprawdzenie pierwszej i ostatniej
|
||||
liczby z przedziału, w naszym przypadku $nextfloat(1.0)$
|
||||
i $nextfloat(2.0)$. Sprawdzamy cechę obu – jeśli są różne,
|
||||
wyklucza to równomierne rozmieszczenie liczb. W przeciwnym
|
||||
przypadku możemy obliczyć $\delta$ w następujący sposób:
|
||||
|
||||
\[2^{cecha - 1023} \cdot 2^{-52}\]
|
||||
|
||||
|
@ -179,21 +253,40 @@ gdzie 1023 to przesunięcie cechy typu $Float64$, a 52 to rozmiar mantysy.
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Dla przedziału [1.0, 2.0] rzeczywiście $\delta = 2^{-52}$, z kolei $\delta$ dla przedziałów [0.5, 1.0] i [2.0, 4.0] pokazuje, że jest ona zależna od cechy liczb z zakresu nad którym się skupiamy. Im bliżej zera jesteśmy tym mniejsza jest $\delta$ – zwiększa się dokładność liczb. Analogicznie oddalając się od zera tracimy precyzję części ułamkowej – przy coraz większych liczbach prawdopodobnie bardziej obchodzi nas część całkowita.
|
||||
Dla przedziału [1.0, 2.0] rzeczywiście $\delta = 2^{-52}$,
|
||||
z kolei $\delta$ dla przedziałów [0.5, 1.0] i [2.0, 4.0]
|
||||
pokazuje, że jest ona zależna od cechy liczb z zakresu
|
||||
nad którym się skupiamy. Im bliżej zera jesteśmy tym mniejsza
|
||||
jest $\delta$ – zwiększa się dokładność liczb. Analogicznie
|
||||
oddalając się od zera tracimy precyzję części ułamkowej –
|
||||
przy coraz większych liczbach prawdopodobnie bardziej obchodzi nas część całkowita.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
\textbf{Zad. 4}
|
||||
|
||||
Eksperymentalne znalezienie liczby w arytmetyce $Float64$ w przedziale $(1, 2)$ takiej, że $x \cdot (1/x) \neq 1$ oraz znalezienie najmniejszej takiej liczby.
|
||||
Eksperymentalne znalezienie liczby w arytmetyce $Float64$ w
|
||||
przedziale $(1, 2)$ takiej, że $x \cdot (1/x) \neq 1$ oraz
|
||||
znalezienie najmniejszej takiej liczby.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Implementacja zadania opiera się na funkcji $nextfloat()$ z języka Julia. Zaczynamy od $nextfloat(1.0)$, iterujemy do $2.0$. W każdej iteracji liczymy wynik $x \cdot (1/x)$, jeśli jest różny od $1.0$ zwracamy $x$ jako wynik. Oczywiście jest to również najmniejsza taka liczba.
|
||||
Implementacja zadania opiera się na funkcji $nextfloat()$ z
|
||||
języka Julia. Zaczynamy od $nextfloat(1.0)$, iterujemy do
|
||||
$2.0$. W każdej iteracji liczymy wynik $x \cdot (1/x)$,
|
||||
jeśli jest różny od $1.0$ zwracamy $x$ jako wynik.
|
||||
Oczywiście jest to również najmniejsza taka liczba.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Najmniejsza taka liczba to $1.000000057228997$. Błędny wynik wyrażenia, które zawsze powinno zwracać $1.0$ jest spowodowany oczywiście skończoną mantysą w liczbach zmiennoprzecinkowych – przez co tracimy precyzję – ale również kolejnością wykonywania działań. Gdyby zamienić $x \cdot (1/x)$ na $(x \cdot 1) / x$ zawsze dostalibyśmy odpowiedni wynik – $x \cdot 1$ nie zmieniłoby wartości liczby, a $x / x$ zakładając dobrze napisany interpreter lub kompilator zawsze zwróci $1.0$
|
||||
Najmniejsza taka liczba to $1.000000057228997$. Błędny wynik
|
||||
wyrażenia, które zawsze powinno zwracać $1.0$ jest spowodowany
|
||||
oczywiście skończoną mantysą w liczbach zmiennoprzecinkowych
|
||||
– przez co tracimy precyzję – ale również kolejnością wykonywania
|
||||
działań. Gdyby zamienić $x \cdot (1/x)$ na $(x \cdot 1) / x$
|
||||
zawsze dostalibyśmy odpowiedni wynik – $x \cdot 1$ nie
|
||||
zmieniłoby wartości liczby, a $x / x$ zakładając dobrze
|
||||
napisany interpreter lub kompilator zawsze zwróci $1.0$
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
|
@ -218,11 +311,15 @@ na 4 sposoby:
|
|||
|
||||
\vspace{0.25cm}
|
||||
|
||||
(c) od największego do najmniejszego – liczenie częściowych sum elementów dodatnich i ujemnych w porządku malejącym względem wartości absolutnej liczb, następnie dodanie do siebie sum częściowych
|
||||
(c) od największego do najmniejszego – liczenie częściowych
|
||||
sum elementów dodatnich i ujemnych w porządku malejącym względem
|
||||
wartości absolutnej liczb, następnie dodanie do siebie sum częściowych
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
(d) od największego do najmniejszego – liczenie częściowych sum elementów dodatnich i ujemnych w porządku rosnącym względem wartości absolutnej liczb, następnie dodanie do siebie sum częściowych
|
||||
(d) od największego do najmniejszego – liczenie częściowych
|
||||
sum elementów dodatnich i ujemnych w porządku rosnącym względem
|
||||
wartości absolutnej liczb, następnie dodanie do siebie sum częściowych
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
|
@ -230,11 +327,13 @@ używając typów zmiennopozycyjnych $Float32$ i $Float64$.
|
|||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Oczekiwanym wynikiem iloczynu skalarnego na tych dwóch wektorach jest $-1.00657107000000 \cdot 10^{-11}$.
|
||||
Oczekiwanym wynikiem iloczynu skalarnego na tych
|
||||
dwóch wektorach jest $-1.00657107000000 \cdot 10^{-11}$.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Porównanie wyników iloczynu skalarnego przeprowadzonego za pomocą powyższych czterech sposobów:
|
||||
Porównanie wyników iloczynu skalarnego przeprowadzonego
|
||||
za pomocą powyższych czterech sposobów:
|
||||
|
||||
\begin{table}[h]
|
||||
\begin{adjustbox}{max width=\textwidth}
|
||||
|
@ -250,7 +349,11 @@ Porównanie wyników iloczynu skalarnego przeprowadzonego za pomocą powyższych
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Żaden ze sposobów nie dał wyniku bliskiego oczekiwanemu, choć sposób (b) w arytmetyce $Float64$ dał wynik dość bliski prawdzie. Patrząc na wyniki korzystające z różnych sposobów widzimy również, że kolejność wykonywania działań może znacznie wpłynąć na poprawność wyniku.
|
||||
Żaden ze sposobów nie dał wyniku bliskiego oczekiwanemu,
|
||||
choć sposób (b) w arytmetyce $Float64$ dał wynik dość
|
||||
bliski prawdzie. Patrząc na wyniki korzystające z różnych
|
||||
sposobów widzimy również, że kolejność wykonywania działań
|
||||
może znacznie wpłynąć na poprawność wyniku.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
|
@ -300,13 +403,25 @@ Porównanie wyników dla obu funkcji:
|
|||
\end{adjustbox}
|
||||
\end{table}
|
||||
|
||||
Już przy $x = 8^{-9}$, $f(x)$ przyjmuje wartość $0.0$, którą zachowuje przy mniejszych wartościach. Przy wartościach większych od $8^{-9}$ obie funkcje mają podobne wartości. $f(x)$ szybciej traci precyzję i spada do $0.0$ przez odejmowanie $1.0$ od pierwiastka – im mniejsza wartość $x$ tym bliżej $x^2 + 1$ jest $1.0$. Przez pierwiastek całe wyrażenie zbliża się jeszcze bardziej do $1.0$, od którego również odejmujemy $1.0$. Przekształcenie $f(x)$ w $g(x)$ zwalcza ten problem poprzez pozbycie się problematycznego odejmowania, dzięki czemu tracimy mniej precyzji wykonując działania.
|
||||
Już przy $x = 8^{-9}$, $f(x)$ przyjmuje wartość $0.0$,
|
||||
którą zachowuje przy mniejszych wartościach. Przy
|
||||
wartościach większych od $8^{-9}$ obie funkcje mają
|
||||
podobne wartości. $f(x)$ szybciej traci precyzję i
|
||||
spada do $0.0$ przez odejmowanie $1.0$ od pierwiastka
|
||||
– im mniejsza wartość $x$ tym bliżej $x^2 + 1$ jest $1.0$.
|
||||
Przez pierwiastek całe wyrażenie zbliża się jeszcze bardziej
|
||||
do $1.0$, od którego również odejmujemy $1.0$.
|
||||
Przekształcenie $f(x)$ w $g(x)$ zwalcza ten problem
|
||||
poprzez pozbycie się problematycznego odejmowania,
|
||||
dzięki czemu tracimy mniej precyzji wykonując działania.
|
||||
|
||||
\vspace{0.5cm}
|
||||
|
||||
\textbf{Zad. 7}
|
||||
|
||||
Obliczanie przybliżonej wartości pochodnej funkcji $f(x) = \sin{x} + \cos{3x}$ w punkcie $x_0 = 1$ oraz błędów $|f^{'}(x_0) - \widetilde{f^{'}}(x_0)|$ korzystając ze wzoru
|
||||
Obliczanie przybliżonej wartości pochodnej funkcji
|
||||
$f(x) = \sin{x} + \cos{3x}$ w punkcie $x_0 = 1$ oraz
|
||||
błędów $|f^{'}(x_0) - \widetilde{f^{'}}(x_0)|$ korzystając ze wzoru
|
||||
|
||||
\[f^{'}(x_0) \approx \widetilde{f^{'}}(x_0) = \frac{f(x_0 + h) - f(x_0)}{h}\]
|
||||
|
||||
|
@ -381,11 +496,23 @@ Dokładna wartość pochodnej dla $x_0 = 1$ to $0.11694228168853815$.
|
|||
\hline
|
||||
\end{longtable}
|
||||
|
||||
Najdokładniejszy wynik jest dla $n = 28$, $h = 2^{-28}$, dokładnie po środku wartości testowanych (jeśli zignorujemy 54, dla którego wynik jest identyczny do 53). Idąc w górę lub w dół błąd jest coraz większy, dla $n = 53$ dochodząc do wartości pochodnej.
|
||||
Najdokładniejszy wynik jest dla $n = 28$, $h = 2^{-28}$,
|
||||
dokładnie po środku wartości testowanych (jeśli zignorujemy
|
||||
54, dla którego wynik jest identyczny do 53). Idąc w górę lub w dół
|
||||
błąd jest coraz większy, dla $n = 53$ dochodząc do wartości pochodnej.
|
||||
|
||||
\vspace{0.25cm}
|
||||
|
||||
Wzięcie zbyt dużego $h$ (zbyt małego $n$) powoduje ogromny błąd z definicji pochodnej, którą jest granica wzoru wykorzystanego w tym zadaniu przy h dążącym do 0. Przy coraz mniejszych $h$ (coraz większych $n$) na papierze zbliżamy się do poprawnej wartości, ale w rzeczywistości ograniczona precyzja liczb zmiennopozycyjnych w standardzie IEEE 754 powoduje zwiększanie się błędu, lecz nie do takich rozmiarów jak dla pierwszych kilku $n$. Maksymalny błąd po przekroczeniu $n = 28$ otrzymujemy przy $n = 53$, gdzie $h < \varepsilon$ w precyzji $Float64$. Wtedy
|
||||
Wzięcie zbyt dużego $h$ (zbyt małego $n$) powoduje ogromny
|
||||
błąd z definicji pochodnej, którą jest granica wzoru
|
||||
wykorzystanego w tym zadaniu przy h dążącym do 0. Przy coraz
|
||||
mniejszych $h$ (coraz większych $n$) na papierze zbliżamy się
|
||||
do poprawnej wartości, ale w rzeczywistości ograniczona
|
||||
precyzja liczb zmiennopozycyjnych w standardzie
|
||||
IEEE 754 powoduje zwiększanie się błędu, lecz nie do
|
||||
takich rozmiarów jak dla pierwszych kilku $n$.
|
||||
Maksymalny błąd po przekroczeniu $n = 28$ otrzymujemy
|
||||
przy $n = 53$, gdzie $h < \varepsilon$ w precyzji $Float64$. Wtedy
|
||||
|
||||
\[x_0 + h = x_0 = 1\]
|
||||
|
||||
|
@ -399,6 +526,11 @@ zatem dla $n \geq 53$ błąd będzie zawsze równy dokładnej wartości pochodne
|
|||
|
||||
\textbf{Wnioski z listy}
|
||||
|
||||
Liczby zmiennopozycyjne w standardzie IEEE 754 mają skończoną precyzję, co przy liczbach bliskich zeru powoduje błędy. Pisząc kod operujący na tych liczbach musimy pamiętać o tym fakcie i wybrać odpowiedni typ do trzymania danych lub zastanowić się nad trzymaniem ich w typach całkowitych, np. waluty zamiast we floacie trzymać w dwóch integerach.
|
||||
Liczby zmiennopozycyjne w standardzie IEEE 754 mają skończoną
|
||||
precyzję, co przy liczbach bliskich zeru powoduje błędy. Pisząc
|
||||
kod operujący na tych liczbach musimy pamiętać o tym fakcie
|
||||
i wybrać odpowiedni typ do trzymania danych lub zastanowić
|
||||
się nad trzymaniem ich w typach całkowitych,
|
||||
np. waluty zamiast we floacie trzymać w dwóch integerach.
|
||||
|
||||
\end{document}
|
||||
|
|
Loading…
Reference in a new issue