Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

07. Liczby rzeczywiste. Arytmetyka komputerowa

Treści kształcenia: arytmetyka komputerowa, zero (przykłady w różnych programach). Wartość bezwzględna. Postacie niedziesiętne liczb rzeczywistych. Konsekwencja braku spełniania aksjomatów liczb rzeczywistych w arytmetyce komputerowej.

Efekty kształcenia: student potrafi określić ograniczenia arytmetyki komputerowej w stosunku do pełnej teorii aksjomatycznej liczb rzeczywistych i dobrać odpowiednie metody dla unikania problemów.

Wstęp

Jak już wiemy, tylko pewien zakres liczb da się dokładnie reprezentować w trakcie ich przetwarzania na komputerze. Informacje ‘‘techniczne’’ na ten temat będą podane na innym przedmiocie, a my skoncentrujemy się na wskazaniu różnic pomiędzy operacjami matematycznymi (czyli wykonywanymi przez ludzi) na liczbach rzeczywistych, a tymi, które są wykonywane przez komputer. Sprawdzimy, czy można zawsze ufać otrzymanym wynikom, a zwłaszcza dlaczego jest niekiedy problem...

Arytmetyka komputerowa

Każdą liczbę xx, x≠0x \neq 0 można reprezentować jednoznacznie w postaci wykładniczej

x=s⋅m⋅2c,x = s \cdot m \cdot 2^c ,

gdzie s∈{−1,1}s \in \{-1,1\} jest znakiem liczby, m∈[12,1)m \in [\frac{1}{2}, 1) nazywamy mantysą, a c∈Zc \in \mathbb{Z} nazywamy cechą. W komputerze mm i cc są reprezentowane za pomocą skończonej ilości bitów.

W związku ze skończonym zakresem wartości przyjmowanych przez cechę cmin≤c≤cmaxc_{\text{min}} \leq c \leq c_{\text{max}} w reprezentacji zmiennoprzecinkowej można reprezentować tylko liczby ze skończonego zakresu

122cmin≤∣x∣<2cmax\frac{1}{2} 2^{c_{{min}}} \leq \lvert x \rvert < 2^{c_{{max}}}

oraz 0. W związku ze skończoną ilością tt bitów mantysy reprezentacja zmiennoprzecinkowa może różnić się od wartości ścisłej:

x~t=rd(x)=x(1+ϵ),\tilde{x}_t = rd(x) = x(1 + \epsilon) ,

gdzie ∣ϵ∣≤2−t\lvert \epsilon \rvert \leq 2^{-t}.

Uwaga: wspominaliśmy o braku dokładnej reprezentacji w arytmetyce podwójnej precyzji liczby 0,10,1. Myślenie w kategoriach ułamków dziesiętnych jest jednak mocno zakorzenione, więc część prostych (!) kalkulatorów operuje jednak systemem dziesiętnym z 10c10^c zamiast 2c2^c.

Zero. Przybliżenia. Pewnie większość z Was napotkała w ‘‘C++’’ funkcję epsilon() lub
{FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON} (dla typów zmiennoprzecinkowych). Ta pierwsza wg dokumentacji to różnica między 1 a najmniejszą liczbą większą niż 1 reprezentowalną w podwójnej precyzji’'.
Czyli przy 64-bit IEEE podwójnej precyzji, mamy 52-bitową mantysę i 11-bitową cechę:

1.0000000000000000000000000000000000000000000000000000×20=1.1.0000 00000000 00000000 00000000 00000000 00000000 00000000 \times 2^0 = 1 .

A więc:

1.0000000000000000000000000000000000000000000000000001×20=1+2−52.1.0000 00000000 00000000 00000000 00000000 00000000 00000001 \times 2^0 = 1 + 2^{-52} .

Czyli

epsilon()=(1+2−52)−1=2−52.epsilon() = (1 + 2^{-52}) - 1 = 2^{-52} .

cytat: S.J. Lec ‘‘Nie zgadzam się z matematykami. Uważam, że suma zer daje groźną liczbę.’’

Liczba bitów mantysy = 53; 2.220446049250313e-16

Warto pamiętać: z matematycznego punktu widzenia zbiór liczb całkowitych jest podzbiorem liczb rzeczywistych. Ale w arytmetyce komputerowej typy ‘‘integer’’ i ‘‘real’’ są rozłączne! Musimy albo używać deklaracji typu, albo stosować zasadę, że zapis deklaruje typ (czyli 2 i 2.00) to różne liczby). Więcej - na innym przedmiocie...

Każda operacja ⊗\otimes na liczbach typu ‘‘real’’ jest obarczona błędem

float(a⊗b)=(a⊗b)⋅(1+epsilon).float(a \otimes b) = (a \otimes b)\cdot (1 + epsilon) .

Może po przeczytaniu poprzednich uwag będą osoby, które stwierdzą, że wykonywały obliczenia np. na większych liczbach. Tak - mówimy tu o programach korzystających z reprezentowania liczb na poziomie procesora (słowa maszynowe), czyli w przetwarzaniu danych, a nie ich przechowywaniu.

Jeśli musimy wykonywać dokładniejsze obliczenia, to należy skorzystać z programu, który pomija te ograniczenie (lub napisać własny...), np. pakiety matematyczne czy programy obliczeniowe. Wtedy operacje na liczbach ograniczonych wielkością pamięci - ale oczywiście to wymaga więcej operacji i/lub dłuższych czasów obliczeń (np. szachy i komputer ‘‘Deep Blue’’). To i tak ma pewne ograniczenia, nasze zasady pozostają w mocy, tylko zakres liczbowy czy precyzja ulega zmianie... Oczywiście czym innym jest przechowywanie liczb - można np. obliczać kolejne miejsca po przecinku (np. π\pi) i zapisywać, ale operowanie na takich liczbach to inny problem.

Zadanie samodzielne

Wracamy do ułamków na komputerze (Python)

332.9999999999985
1.4779288903810084e-12

Sprawdzamy. Dla jakich ułamków xx nie będzie tego problemu i dlaczego? Zapisz w systemie dwójkowym ułamek (13)10\left( \frac{1}{3} \right)_{10}.

Nas interesuje, jak kontrolować obliczenia w arytmetyce komputera (czego nie potrafi - które aksjomaty nie są spełnione) i dlaczego to programista odpowiada za obliczenia. Teraz zadania i przykłady.

Pytanie do przemyślenia: w oparciu o swoją wiedzę i doświadczenie z komputerami, proszę określić, jakie z tych aksjomatów nie są spełnione w arytmetyce komputerowej? Musimy się nad tym zastanowić...

Uwaga: w każdym z takich przypadków to programista musi przewidzieć problem i znaleźć jego rozwiązanie.

Zadanie 9

Na początek banalne pytanie ‘‘ile to jest’’ (obliczenia na komputerze)?

13⋅13⋅...⋅13⏟⋅3⋅3⋅...⋅3⏟  =  ??\underbrace{\frac{1}{3} \cdot \frac{1}{3} \cdot ... \cdot \frac{1}{3}} \underbrace{\cdot 3 \cdot 3 \cdot ... \cdot 3} \ \ = \ \ ??
 ⁣ ⁣ ⁣ ⁣ ⁣ ⁣ ⁣ ⁣ ⁣ ⁣ ⁣ n - krotnie n - krotnie\! \! \! \! \! \! \! \! \! \! \! \mbox{ n - krotnie} \quad \mbox{ n - krotnie}

Rozwiązanie. Robimy symulacje w dowolnym programie (może być arkusz kalkulacyjny)

symulacja z arkusza

Liczymy 1/3 do potęgi 645 i (niżej) do 644 i odpowiednio z 3 do tych potęg, oraz ich iloczyny - ale jak różne wyniki uzyskujemy (0 oraz 1)!

Czyli: zero faktycznie jest reprezentowane przez pewien przedział liczbowy, a działania nie są łączne (wynik zależy od kolejności wykonywania działań)...

Zadanie 10

Stosujemy wzory na pierwiastki trójmianu czy wzory Viete’a? Sprawdzić na przykładzie trójmianu

w(x)=x2−k⋅x+1w(x) = x^2 - k\cdot x + 1

dla odpowiednio (do stosowanej arytmetyki zmiennopozycyjnej) dużych kk. Proszę (samodzielnie) przeprowadzić serię symulacji dla różnych liczb kk i zebrać wnioski. A teraz ogólniej:

x2−2px+q=0x^2 - 2px + q = 0

Rozwiązanie. Na ogół stosowaliśmy algorytm (naiwny) zakładający obliczanie pierwiastków wzorami:

x1=p+p⋅p−qx_1 = p + \sqrt{p\cdot p-q}
x2=p−p⋅p−qx_2 = p - \sqrt{p\cdot p-q}
'x1 = -1.4142135623730951, x2 = 1.4142135623730951'

No to zobaczmy też w arkuszu kalkulacyjnym:

zero maszynowe w arkuszu kalkulacyjnym

Wybraliśmy p=150000p = 150000, q=0,000001q= 0,000001 i jako wynik otrzymaliśmy x1=300000x_1 = 300000 oraz x2=0x_2 = 0. I teraz pytanie: czy powinniśmy wierzyć w obliczenia komputerowe? Zawsze? Czy te wyniki są możliwe? Jakie są poprawne wyniki?

To klasyczny problem: czy wszystkie powszechnie używane matematyczne metody rozwiązywania zagadnień mogą być stosowane bez dodatkowego dokładnego zbadania, jeśli wyniki mają być otrzymane za pomocą komputera? Nie!

Sprawdzamy, czy zachodzą wzory Viete’a (a wiemy ze szkoły średniej, że są prawdziwe): uzyskujemy m.in. x1⋅x2=0≠qx_1 \cdot x_2 = 0 \not= q. Nie są prawdziwe! A więc obliczenia w arkuszu kalkulacyjnym (algorytmem naiwnym) mogą prowadzić do błędnych wyników - uwaga na ‘‘zero maszynowe’’!

A jak to naprawić? Okazuje się, że informatyk musi znać wzory Viete’a, czyli w tym przypadku (samodzielnie powtórzyć wzory ogólne!)

x1⋅x2=q,x1+x2=2p.x_1 \cdot x_2 = q \quad , \quad x_1 + x_2 = 2p \quad .

Szukamy problemu: jeden z pierwiastków trójmianu jest niepoprawny, po prostu jest za mały i został potraktowany jako zero (maszynowe). Unikamy zera biorąc z poprzedniego wzoru większy z pierwiastków, a drugi wyliczmy ze wzorów Viete’a!

Jeżeli p≥0p\ge 0, to

x1=p+p⋅p−qx2=q/x1,\begin{align*} x_1 &= p+\sqrt{p\cdot p-q} \\ x_2 &= q/x_1 \nonumber , \end{align*}

jeżeli p<0p < 0, to

x2=p−p⋅p−qx1=q/x2\begin{align*} x_2 &= p-\sqrt{p\cdot p-q} \\ x_1 &= q/x_2 \nonumber \end{align*}

Ćwiczenie: proszę samodzielnie sprawdzić poprawne pierwiastki w arkuszu! Kiedy algorytm naiwny jest niepoprawny? Może on generować znaczny błąd w chwili gdy np. p⋅p≫qp\cdot p\gg q (≫\gg czytamy: ‘‘znacznie większe’’), czyli wtedy p−p2−q≈p−p2=0p-\sqrt{p^2-q} \approx p - \sqrt{p^2} = 0.

Zadanie 10a

Może to dobry moment, by zwrócić uwagę, dlaczego stosuje się wiele różnych algorytmów do rozwiązania tego samego problemu. Wróćmy np. do trójmianu kwadratowego

ax2+bx+c=0.ax^2 + bx + c = 0 .

Mamy

x1=−b+b2−4ac2a,x2=−b−b2−4ac2a.x_1 = \frac{-b + \sqrt{b^2 - 4ac}}{2a} \quad , \quad x_2 = \frac{-b - \sqrt{b^2 - 4ac}}{2a} .

Powiedzmy, np. że bb jest dodatnie i b2b^2 jest znacznie większe niż 4ac4ac (np. b=62.10b = 62.10, a=c=1a = c = 1). Wtedy x1x_1 jest ‘‘małe’’.

I teraz zadanie: przekształćmy wzór

x1=−b+b2−4ac2a⋅(−b−b2−4ac−b−b2−4ac)=b2−(b2−4ac)2a(−b−b2−4ac),x_1 = \frac{-b + \sqrt{b^2 - 4ac}}{2a} \cdot \left( \frac{-b - \sqrt{b^2 - 4ac}}{-b - \sqrt{b^2 - 4ac}} \right) = \frac{b^2 - (b^2 - 4ac)}{2a(-b -\sqrt{b^2 - 4ac})} ,

czyli

x1=−2cb+b2−4ac.x_1 = \frac{-2c}{b+\sqrt{b^2 - 4ac}} .

Co się zmieniło? W mianowniku jest suma liczb dodatnich i nie ma zagrożenia zerem maszynowym...

Proszę zrobić symulację (może być arkusz) i porównać zmodyfikowany algorytm naiwny w oparciu o nowy wzór (uwaga: jak sprawdzić, który z pierwiastków jest ‘‘mały’’?). Przemyśleć (symulacje?), czy taka technika może być zastosowana dla x2x_2 i b<0b < 0?

Pytanie problemowe

Proszę zastanowić się, czy (i jak) komputer może wygenerować liczbę losową rzeczywistą?

Zadanie 11

Gdzie jeszcze informatyk musi uważać na występowanie liczb rzeczywistych? Kolejny przykład: równania wielomianowe (i wiele innych, ale te są najistotniejsze).

Znalezione miejsce zerowe wynosi -6.626415967941284

Czy (i kiedy) taki program da zadawalające wyniki? To oczywiście zagadnienie na metody numeryczne, ale proszę wykonać wykres tej funkcji (dowolny program)

f(x)=x4−4⋅x3+6⋅x2−4⋅x+1f(x) = x^4 - 4\cdot x^3 + 6\cdot x^2 -4\cdot x +1

oraz

g(x)=x5−x4+x3−2⋅x+1g(x) = x^5 - x^4 +x^3 -2\cdot x + 1

i wyciągnąć wnioski o wartościach miejsc zerowych uzyskanych metodą graficzną na komputerze.

Zadanie 12

A teraz powinniśmy przypomnieć sobie znaną ze szkoły operację na liczbach rzeczywistych: wartość bezwzględna liczby

∣a∣=a(a≥0)∣a∣=−a(a<0).|a| = a \quad (a \geq 0) \qquad \qquad |a| = -a \quad (a<0).

W programach to na ogół funkcja abs()abs(). Zwłaszcza nierówności z wartością bezwzględną będą nam przydatne - np. w oszacowaniach błędu czy sprawdzaniu osiągnięcia wyniku przy obliczeniach zmiennoprzecinkowych (bo jak pamiętamy - nie sprawdzamy tam równości liczb, tylko przybliżoną odległość od wyniku = nierówność z wartością bezwzględną).

A teraz polecenie: rozwiązać nierówność

∣∣x−1∣−1∣<2.| |x-1| - 1| < 2 .

Odp. x∈(−2,4)x \in (-2,4)

Zadanie 13. Rozwiązać nierówność

∣x−1∣<x−1.|x-1| < x -1 .

Odp. nie ma rozwiązań

Zadanie 14. Rozwiązać nierówność

∣x−3∣+∣x+2∣<13.|x-3| + |x + 2| < 13 .

Odp. x∈(−6,7)x \in (-6,7)

Zadanie 15. Wykazać (samodzielnie) ważną (ze względu na jej wykorzystanie w oszacowaniach błędów) własność wartości bezwzględnej: dla dowolnych a,b∈Ra,b \in {\mathbb{R}} zachodzi

∣∣a∣−∣b∣∣≤∣a−b∣.| |a| - |b| | \leq |a-b| .

Zadanie 16. Pokaż, że liczby:

31223\sqrt[12]{3} \qquad \sqrt{\frac{2}{3}}

są niewymierne.

Zadanie 17. Pokaż, że log⁡25\log_2{5} jest liczbą niewymierną.

Zadanie 18. ∗^* Udowodnić, że jeśli m,n∈Nm,n \in{\mathbb{N}}, m,n>1m,n > 1 oraz NWD(m,n)=1NWD(m,n) = 1, to log⁡mn\log_m{n} jest liczbą niewymierną.

Zadanie 19. ∗^* Czy z aksjomatów liczb rzeczywistych (można je odszukać i posługiwać się nimi ) wynika, że 0<10 < 1?

Zadanie 20. W oparciu o zasadę Archimedesa udowodnić wspomnianą własność liczb naturalnych:

∀ε>0∃n∈N1n<ε.\forall_{\varepsilon > 0} \quad \exists_{n \in {\mathbb{N}}} \quad \frac{1}{n} < \varepsilon .

Zadania dla informatyków...

(A1) Przygotować programy, które obliczają sumę

1−12+13−14+15−....+19999−1100001 - \frac{1}{2} + \frac{1}{3} - \frac{1}{4} + \frac{1}{5} - .... + \frac{1}{9999} - \frac{1}{10000}

w różnych programach i arytmetykach różnych precyzji, który

  • a) dodaje składniki od lewej do prawej,

  • b) dodaje składniki od prawej do lewej,

  • c) dodaje osobno składniki dodatnie i ujemne oraz sumuje wyniki,

  • d) jak w c) ale zmieniając kolejności sumowań (od lewej lub od prawej).

Porównaj wyniki, wyjaśnij ewentualne różnice.

Uwaga: −a=a⋅(−1)-a = a\cdot (-1). \qquad Odp. 0,693097183059945296917232371362...0,693097183059945296917232371362...

(A2) W programach do znajdowania rozwiązań równań kwadratowych sprawdź, jak wpływ na wynik ma typ współczynników (tzn. odróżnij np. a=1a=1, b=−200b=-200, c=1c=1 od przypadku a=1.000a=1.000, b=−200.000b=-200.000, c=1.000c=1.000). Uwaga na sqrtsqrt.

Jakie są wnioski?

Mathematica. Ilustracja arytmetyki komputerowej w (dobrym) programie matematycznym ‘‘Mathematica’’. Ma trochę więcej możliwości niż ‘‘zwykłe programy’’...

Prezentacja: Skrypt ilustracyjny - potrzebny darmowy CDF Player lub Mathematica

przykład działania skryptu

Potrzeba kontroli arytmetyki komputerowej będzie bardzo widoczna w każdej z metod rozwiązywania równań nieliniowych (a będzie taka potrzeba w wielu działach informatyki). Nawet najprostsze z równań tego typu tzn. wielomianowych jest dobrą ilustracją problemu. Jedna z najprostszych metod to metoda bisekcji. Szczegółowo będzie można ją omówić np. na analizie matematycznej, potrzebujemy tam kilku na razie nowych (?) pojęć jak ciągłość funkcji, czy własność Darboux, ale na razie odwołamy się tylko do intuicji dotyczącej wielomianów - jak w szkole średniej.

Szukamy rozwiązań równania

f(x)=0f(x) = 0

w pewnym ustalonym przedziale [a,b][a,b]. Na ogół musimy mieć pewność, że w tym przedziale jest rozwiązanie, co efektywnie sprawdzamy (dla funkcji ciągłych, umówmy się, że dla wielomianów), gdy f(a)⋅f(b)<0f(a) \cdot f(b) < 0. Procedura zakłada podział odcinka na połowy punktem x1=a+b2x_1 = \frac{a+b}{2} i sprawdzenie znaku wyrażeń f(a)⋅f(x1)f(a)\cdot f(x_1 ) oraz f(x1)⋅f(b)f(x_1 ) \cdot f(b). Oczywiście, gdy f(x1)=0f(x_1 ) = 0, to mamy wynik...

Dalej wybieramy ten z przedziałów [a,x1][a,x_1] lub [x1,b][x_1 , b], dla którego ten iloczyn jest ujemny. W kroku drugim teraz ten wybrany przedział dzielimy na połowę punktem x2x_2 i powtarzamy procedurę.

Całość kończymy, gdy albo napotkamy f(xk)=0f(x_k) = 0 (co może być trudne w arytmetyce zmiennopozycyjnej), albo uzyskamy żądaną dokładność ∣f(xk)∣<ε|f(x_k) | < \varepsilon.

Więcej o metodzie, złożoności czasowej algorytmu, założeniach i ograniczeniach - na innym przedmiocie (będą też lepsze metody). Na razie nam wystarczy.

Przykład (MB)

Rozpatrzmy równanie

x5−8x4+x+11=0x^5 - 8x^4 +x +11 = 0

na przedziale [−10,10][-10,10]. Zróbmy symulację wykonując wykres.

Graphics object consisting of 1 graphics primitive

Mamy dwa sugerowane rozwiązania: ``blisko’’ zera i w przedziale [5,10][5,10]. Na pewno dwa? To teraz wykonajmy wykres w [−2,2][-2,2] i ujawnia się trzecie rozwiązanie.

Graphics object consisting of 1 graphics primitive

Proszę sprawdzić algorytmem bisekcji (tablica + kalkulator lub program), wartości przybliżone stosując algorytm w wyznaczonych (graficznie) przedziałach: [−2,0][-2,0], [0,2][0,2] oraz [5,10][5,10].

Samodzielnie: Zbadać podobnie równanie x3−0,165x2+0,0003993=0x^3 - 0,165 x^2 + 0,0003993 = 0. Jeśli w programie, to ok. 10-11 kroków... Ponadto: teraz metodą bisekcji rozwiązać rozważane wcześniej trójmiany i porównać wyniki z wcześniejszymi obliczeniami.

A tak praktycznie: takie problemy rozwiązuje się algorytmami rekurencyjnymi - powiemy o tym przy okazji dalszego tematu - o ciągach rekurencyjnych.

Systemy pozycyjne. Wszyscy wiedzą (?), że komputer nie korzysta z zapisów liczb w systemie dziesiętnym.
Tu warto przypomnieć, że jeszcze niedawno uczniowie byli nauczani, że liczby wymierne to takie, które mają rozwinięcia dziesiętne skończone lub okresowe.

No to ćwiczenie dla wszystkich - ta definicja dotyczy rozwinięć dziesiętnych. CZY również innych? Sprawdzić na własnych przykładach lub poniższej prezentacji, czy liczby o rozwinięciu dziesiętnym skończonym mają takie np. w rozwinięciu dwójkowym? Jakie są możliwości? No i czy taka definicja była poprawna?

Prezentacja: konwersja w programie ‘‘Mathematica’’

Zamiana systemów pozycyjnych.

Prezentacja nie rozstrzyga wszystkiego. To pytanie: w zapisie dziesiętnym liczby wymierne mają rozwinięcia skończone lub nieskończone okresowe. A jak jest w zapisie dwójkowym takich liczb? Np. (13)2\left(\frac{1}{3}\right)_2?

(wskazówka do poszukiwań: ‘‘błędy reprezentacji’’)

Tutaj: też pewna wskazówka (ale nie dowód)... w formacie CDF...

Ćwiczenia. Wykonać ćwiczenie zamiany systemów pozycyjnych:

  • (10)10=(...)2(10)_{10} = (...)_2 ?

  • (10)2=(...)10(10)_2 = (...)_{10} ?

  • (20)10=(...)16(20)_{10} = (...)_{16} ?

  • ∗^* (14)10=(...)3(\frac{1}{4})_{10} = (...)_3 ?

  • (0,(24))10=(...)2(0,(24))_{10} = (...)_2 ?

Zadanie (R1)

Sprawdzić wyniki bezpośrednim rachunkiem (oraz/lub w programie) stosując arytmetykę dwójkową i trójkową:

45+13.\frac{4}{5} + \frac{1}{3}.

Algorytm Hornera. Dana jest dziesiętna postać liczby rzeczywistej xx. Aby zakodować tę liczbę w systemie o podstawie qq:

  • Przyjmujemy, z jaką liczbą miejsc po przecinku (czyli: nn) chcemy przedstawić liczbę xx.

  • Mnożymy xx przez podstawę qq systemu podniesioną do potęgi nn.

  • Zaokrąglamy wynik mnożenia do liczby całkowitej, a następnie kodujemy ją w wybranym przez nas systemie o podstawie qq tak, jak każdą liczbę całkowitą.

  • Oddzielamy ostatnie nn liczb przecinkiem.

Wprowadz liczbe dziesietna:
 1011
Liczbie 1011 w zapisie binarnym (dwojkowym) odpowiada 1111110011
Exiting Sage (CPU time 0m2.64s, Wall time 11m34.20s).