Trurl i Klapaucjusz byli uczniami wielkiego Kerebrona Emtadraty, który w Wyższej Szkole Neantycznej wykładał przez czterdzieści siedem lat Ogólną Teorię Smoków. Jak wiadomo, smoków nie ma. Prymitywna ta konstatacja wystarczy może umysłowi prostackiemu, ale nie nauce, ponieważ Wyższa Szkoła Neantyczna tym, co istnieje, wcale się nie zajmuje; banalność istnienia została już udowodniona zbyt dawno, by warto jej poświęcać choćby jedno jeszcze słowo. Tak tedy genialny Kerebron, zaatakowawszy problem metodami ścisłymi, wykrył trzy rodzaje smoków: zerowe, urojone i ujemne. Wszystkie one, jak się rzekło, nie istnieją, ale każdy rodzaj w zupełnie inny sposób.
To będzie oczywiście polemika z poprzednim tekstem Pawła Stacewicza: liczby w informatyce potrafią nie istnieć na wiele sposobów, w czym są bardzo podobne smokom.
Ale zacznijmy od matematyki. Tutaj oczywiście liczby istnieją, choć nie jest to istnienie samoistne. Matematyk potrafi długo i z uciechą opowiadać o ciekawych własnościach liczb rzeczywistych (wszystkich, lub o każdej z osobna), ale gdy to robi, to przynajmniej w duchu zakłada nie tylko istnienie samych liczb, ale również istnienie ciała liczb rzeczywistych. Teoria ciał nadaje sens istnienia pojęciom takim jak liczby rzeczywiste, wymierne czy zespolone. Łącząc je z pojęciem operacji, jakie na tych liczbach można wykonać bez potrzeby powoływania do życia nowych bytów, którymi będą wyniki owych operacji. Jeśli ktoś w tym miejscu pomyślał o programowaniu obiektowym i jego paradygmatach, to znaczy, że ma dobre skojarzenia. Tak, pomysł traktowania działań jako „czynności wewnętrznych” stosowany jest w matematyce, jak i w językach programowania (poza tym jest chlebem powszednim dla monad Leibniza).
W komputerach dane istnieją pod postacią zmiennych, czyli wyznaczonych miejsc w pamięci. Żeby uznać istnienie liczb, musimy mieć zmienne typu liczbowego gotowe do ich przechowywania. Wczesne języki programowania (Algol) mają pierwotne typy: integer i real (całkowite i rzeczywiste). Czytelnik powinien tu zauważyć, że o nieistnieniu liczb rzeczywistych od dawna dobrze wiemy – do tego potrzebny by był komputer analogowy. Racja. Nie wiem co przyświecało twórcom języka w takim wyborze słowa, nadmierny optymizm czy może zuchwałość, ale w nowszych językach zamiast real już przeważnie występuje określenie float. Jest to termin bardziej techniczny niż matematyczny, opisuje sposób przybliżonego zapisu liczby w pamięci.
Skoro nie liczby rzeczywiste, to może istnieją chociaż liczby wymierne? Też nie. Przybliżenie w zapisie float dotyczy każdej liczby, nie tylko tej o nieskończonym rozwinięciu dziesiętnym. Nader często jest tak, że x + y = x, również dla niezerowych wartości y. Z kolei działanie 0.1+0.1+0.1-0.3 nie daje wyniku zerowego, jak można się spodziewać (liczba 0.1 nie ma skończonego rozwinięcia w systemie binarnym). Zmienne float sprawdzają się w obliczeniach inżynierskich (przy rozsądnym używaniu), w zagadnieniach rozstrzygalności nie mają zastosowania.
A jak wygląda sprawa istnienia liczb całkowitych (integer)? Słabo. Przed Algolem wiele komputerów mogło ich w ogóle nie używać. O tym fakcie często się zapomina, ale komputery z lat czterdziestych wcale nie operowały na liczbach binarnych. Miały arytmometry posługujące się notacją BCD (Binary-Coded Decimal) – obliczenia prowadzone były na symbolach odpowiadających cyfrom dziesiętnym. Dopiero gdy zmienił się sposób liczenia, zaczęto na ciąg bitów zapisanych w rejestrze procesora mówić integer. Określenie na wyrost. Dzisiaj i z tego też się wycofano. Osiem bitów zapisanych w pamięci i tworzących bajt przeważnie określa się jako zmienna typu char (znak). Zmienna 16-bitowa bywa jeszcze opisywana jako word (słowo), co miało sens przy 16-bitowych procesorach, a częściej używa się słowa short. Zmienne 32- i 64-bitowe to long i long long. Nazwa „Integer” na nowo pojawia się dopiero w językach obiektowych jako nazwa typu złożonego, który w swoim wnętrzu musi radzić sobie z tym, że opisuje coś, co nie jest liczbą w matematycznym znaczeniu.
Skoro nie w informatyce stosowanej, to może choć w teoretycznej jest godne miejsce dla liczb? Niestety, tu również słabo nadają się one na pojęcie pierwotne. A już zwłaszcza wtedy, gdy narzędziem w rozważaniach ma być maszyna Turinga. Załóżmy, że chcemy liczyć kolejne cyfry rozwinięcia liczby π bezpośrednio ze wzoru na szereg Leibniza:
\frac{\pi}{4} =\frac{1}{1}-\frac{1}{3}+\frac{1}{5} -\frac{1}{7}\cdotsNajpierw musimy pokonać problem zapisu ułamków dziesiętnych (teoretycznie mamy do dyspozycji tylko liczby całkowite). To nie jest trudne. Ale natychmiast wystąpi problem zapisu liczby 1/3 – ta ma nieskończone rozwinięcie. Cóż z tego że mamy nieskończoną taśmę, skoro musimy przeznaczyć nieskończony czas na zapis tak banalnej rzeczy, jak prosty ułamek? Jeśli chcemy w ogóle otrzymać jakiś wynik w skończonym czasie, to musimy pogodzić się ze skończoną dokładnością i z góry określić ile cyfr nas zadowoli.
Oczywiście istnieją też algorytmy, dzięki którym komputery potrafią szybko znajdować kolejne cyfry rozwinięcia (znamy już ponad 1013 cyfr). Algorytmy te operują nie na liczbach jako takich, tylko na liczbach w konkretnym systemie pozycyjnym. Inaczej mówiąc, algorytmu stworzony do liczenia w systemie szesnastkowym (często używany w informatyce) nie da się zaadaptować do liczb w systemie dziesiętnym. I odwrotnie. W operacjach istotna jest nie tylko sama wartość liczbowa, a symbole (cyfry) tworzące jej zapis. Dla bliżej zainteresowanych opis algorytmu Czudnowskiego, najszybszego w chwili obecnej.
Gdy niżej podpisany uruchomił podany na stronie Wiki kod pythona, ze zdziwieniem (i satysfakcją) stwierdził że cyferki wyskakują z niego z prędkością kilkadziesiąt razy większą, niż ze znanego w Uniksach od dziesięcioleci języka bc służącego do obliczeń arbitralnej precyzji, a do trygonometrii używającego algorytmów pokrewnych leibniziańskiemu. Zwięzłość algorytmu też powinna dziwić — to tylko kilkanaście linijek kodu z bardzo dziwnymi długimi liczbami. Śpieszę więc z wyjaśnieniem, że moc tkwi w przywołanej w pierwszym wierszu bibliotece Decimal. Ta ma przeszło sześć tysięcy wierszy i jest kunsztowną realizacją arytmetyki, całkowicie oderwaną od maszynowej reprezentacji liczb.
Tak oto dotarliśmy do finału, w którym możemy stwierdzić: liczby w podstawach informatyki nie istnieją, lecz bardzo łatwo powołać je do życia w takiej formie, że rozwiązywaniu problemów służą lepiej, niż liczby „matematyczne”
❄ ❄ ❄
Tekst ten napisany został w niedzielę 23 grudnia, po wyczerpaniu „polemicznych możliwości” pod tekstem Pawła Stacewicza. Jednak publikację zlecam dopiero na wigilijną północ, by nie mącić nikomu tradycyjnego spokoju dnia Wigilii. Korzystając z okazji składam wszystkim życzenia pogody: ducha, ciała i aury. Oraz zachęcam do polemiki — szczególnie tych, którzy mają zdanie całkowicie odmienne od mojego.