break lines in text

This commit is contained in:
jacekpoz 2024-10-27 22:07:03 +01:00
parent 8a5c33459d
commit 5d82188aca
Signed by: poz
SSH key fingerprint: SHA256:JyLeVWE4bF3tDnFeUpUaJsPsNlJyBldDGV/dIKSLyN8

View file

@ -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]$
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}