Każdemu absolwentowi szkoły podstawowej (mam nadzieję, że wciąż podstawowej…) powinna być znana poniższa funkcja:
Tak, jest to zwyczajna wartość bezwzględna, znana również jako moduł liczby. Jej formalna definicja gwarantuje, że dla każdego
. Innymi słowy, wartość bezwzględna nigdy nie może być ujemna. Nic więc dziwnego, że używamy jej chętnie w tych właśnie sytuacjach, gdy interesuje nas tylko dodatnia połowa osi liczb. Oto bardzo prosty przykład:
Mamy tu elementarną sztuczkę, polegającą na początkowym przypisaniu polu identifier
wartości spoza zwykłej dziedziny (-1
), co oznaczać ma brak identyfikatora. Możemy tak zrobić, bo dzięki wartości bezwzględnej (funkcji Math.abs
) generowane losowe identyfikatory będą zawsze dodatnie.
Albo raczej prawie zawsze…
System liczb w lojbanie.
Jako kolejny temat odnośnie lojbanu zdecydowałem się opisać jego system numeryczny, czyli sposób wyrażania liczb. W dużym stopniu zainspirował mnie do tego pewien komentarz stwierdzający, że w lojbanie – biorąc pod uwagę jego nietypowość – używa się pewnie liczb Churcha albo innej, równie pokręconej konstrukcji :) Pewnie byłoby to jakoś zgodne z jego ideą, ale na szczęście w rzeczywistości jest zupełnie inaczej ;P
Zacznijmy od prostych cyfr, które to przedstawia poniższa tabelka:
no | pa | re | ci | vo | mu | xa | ze |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
bi | so | dau | fei | gai | jau | xei/rei | vai |
8 | 9 | A (10) | B (11) | C (12) | D (13) | E (14) | F (15) |
Powinna ona od razu wzbudzić przyjazne uczucia, jako że wyraźnie pokazuje wielce interesujący fakt: lojban ma natywne wsparcie dla systemu szesnastkowego! I chociaż domyślnie używanym jest nadal ten dziesiętny, taka zapobiegliwość u twórców języka jest z pewnością godna uznania ;)
Nie bez powodu też ciągle używam pojęcia ‘cyfr’ zamiast ‘liczb’. Tak jak notacji matematycznej, liczby w lojbanie składa się bowiem z cyfr, i to dokładnie w ten sam, pozycyjny sposób. Powyższy zestaw słówek (są to oczywiście cmavo) jest wobec tego zupełnie wystarczający do wyrażenia każdej skończonej liczby naturalnej; nie ma żadnych osobnych form gramatycznych dla dziesiątek czy setek. Oto przykłady, które powinny ukazywać dokładną analogię między zapisem dziesiętnym a słownym w lojbanie:
paxa | vore | muno | xaso | parebi | revoci | repavono | sononopa |
16 | 42 | 50 | 69 | 128 | 243 | 2140 | 9001 |
Przy liczbach sięgających dziesiątek czy setek milionów pomocny jest separator ki’o, który jest oddziela tysiące (podobnie jak spacja w języku polskim lub przecinek w angielskim). Tak więc 4096 to vo ki’o nosoxa, a ilość bajtów w megabajcie (czyli 1048576) wyrazimy jako pa ki’o novobi ki’o muzexa. Przy okazji nadmienię, że spacje w zapisie tekstowym mogę wstawiać między cyframi w dowolny sposób (również nigdzie), co dotyczy zresztą każdego ciągu cmavo w lojbanie.
Co z większymi zbiorami liczb, jak całkowite czy wymierne? Mamy oczywiście znak minus, pozwalający tworzyć liczby ujemne: ni’u (dla spójności istnieje też znak plus: ma’u). Do ułamków niezbędny jest z kolei separator dziesiętny pi, którego nie należy mylić z liczbą π (ona sama ma zresztą swoje własne oznaczenie: pai). Wreszcie, jest też kreska ułamkowa, czyli fi’u. Przy pomocy tych słów możemy już wyrazić całkiem sporo różnych liczb:
ni’u mu | re pi voxa | ni’u pamu pi ze | re fi’u mu |
-5 | 2,46 | -15,7 | 2/5 |
Na tym zestawie chwilowo zakończymy, mimo że lojban posiada gramatykę “obsługującą” nawet liczby zespolone (!). Ciekawsze będzie raczej pokazanie sposobu użycia liczb w wypowiedzi. W ‘normalnych’ językach liczby służą zazwyczaj do określania ilości czegoś, najczęściej w sztukach. Dość podobnie jest w lojbanie, gdzie możemy liczbą opatrzyć sumti, jak w poniższym przykładzie:
mi renro vo rokci
Rzucam czterema kamieniami.
Jako ciekawostkę mogę dodać, że powyższe bridi nie specyfikuje tego, czy były to cztery osobne rzuty czy też jeden rzut wszystkimi czterema kamieniami naraz. Możliwe jest aczkolwiek dokładniejsze określenie, ale oczywiście nie będę się tym zajmował :)
Drugi sposób użycia liczb to sytuacje, gdy stanowią one samodzielne sumti. Dzieje się to nieco częściej niż w innych językach, gdzie zdania typu “Dwa plus dwa równa się cztery.” są relatywnie niezbyt powszechne poza samą matematyką. Tutaj jest trochę inaczej między innymi z tego względu, że użycia wszelkich jednostek miar – takich jak metry czy kilogramy – odbywają się za pośrednictwem odpowiadających im predykatów (czyli selbri), na przykład takich jak ten:
grake :: x1 ma masę x2 gramów wg standardu x3
Miejsce (“argument”) x2 wymaga tutaj właśnie liczby jako samodzielnego sumti. Tworzymy go za pomocą rodzajnika li. Stąd mamy np. li revo – liczba 24, a także:
loi patlu poi mi te vecnu cu grake li cinono
Ziemniaki, które kupiłem, ważą 500 gramów.
Tym, jak mógłby wyglądać dialog w sklepie, który do tego zakupu doprowadził, być może zajmę się w przyszłości :)
Programując, rzadko mamy do czynienia z bardzo dużymi wartościami. Dowodem na to jest choćby fakt, że 32-bitowe systemy dopiero teraz zaczynają być w zauważalny sposób zastępowane 64-bitowymi. Jedynie w przypadku rozmiarów bardzo dużych plików operowanie zmiennymi mogącymi zmieścić wartości większe niż 4 miliardy jest konieczne.
Inne dziedziny życia i nauki przynoszą nam nieco większe wartości. Ekonomia czasami mówi o dziesiątkach bilionów (PKB dużych krajów), a fizyka często posługuje się wielkościami zapisywanymi przy pomocy notacji potęgowej – aż do ok. 1080, czyli szacowanej liczby wszystkich atomów we Wszechświecie.
Wydawać by się mogło, że wielkość ta jest bliska górnej granicy wartości, jakich kiedykolwiek moglibyśmy używać w sensownych zastosowaniach. Okazuje się jednak, że tak nie jest; co więcej, jakakolwiek liczba zapisana za pomocą co najwyżej potęgowania jest tak naprawdę bardzo, bardzo mała.
Do zapisywania naprawdę dużych liczb potrzebne są bowiem inne notacje. Jednym z takich sposobów zapisu jest notacja strzałkowa Knutha, która jest “naturalnym” rozszerzeniem operacji algebraicznych. Tak jak dodawanie jest iterowaną inkrementacją, mnożenie jest iterowanym dodawaniem, a potęgowanie – iterowanym mnożeniem:
,
tak każdy następny operator strzałkowy jest iterowaną wersją poprzedniego. I tak pierwszy z nich, to zwykłe potęgowanie
, ale już drugi:
jest odpowiednikiem wielokrotnego podnoszenia danej liczby do jej potęgi. W ogólności, skracając ciąg n strzałek do , otrzymujemy definicję:
Na pierwszy rzut oka może wydawać się to nieoczywiste, jednak już dla n = 3 i jednocyfrowych argumentów, wielkość liczb otrzymywanych przy użyciu notacji strzałkowej znacznie przekracza te, które można w wygodny sposób zapisać przy pomocy samego potęgowania. Chcąc je mimo wszystko przedstawić w tej postaci, trzeba się uciekać do sztuczek z klamerkami:
Oczywiście wraz ze wzrostem liczby strzałek nawet takie triki przestają wystarczać.
W tej chwili pewnie nasuwa się proste pytanie: czy z takiego systemu zapisu jest w ogóle jakiś pożytek, jeśli nikt nie posługuje się na poważnie tak wielkimi liczbami?… Odpowiedź jest jak najbardziej twierdząca, mimo że założenie w pytaniu jest nieprawdziwe. Otóż niektóre dziedziny matematyki używają nie tylko takich, ale i znacznie większych wartości – i nie chodzi tu nawet o teorię liczb, którą to jako pierwszą podejrzewalibyśmy o rzucanie liczbami “z kosmosu”.
Według Księgi Rekordów Guinnessa największą skończoną liczbą kiedykolwiek użytą w poważnym dowodzie matematycznym jest bowiem tzw. liczba Grahama, będącą górnym ograniczeniem pewnej wielkości występującej w problemie luźno związanym z grafami. Żeby ją zdefiniować, można użyć notacji strzałkowej – trzeba to jednak zrobić… iteracyjnie, wprowadzając pomocniczy ciąg gn:
Już pierwszy jego wyraz nie daje się zapisać w postaci potęgowej, ale gwoździem programu jest zauważenie, że kolejne jego elementy posługują się poprzednimi w celu określenia liczby strzałek w operatorze . Innymi słowy, mamy tu wejście na kolejny poziom abstrakcji i stoimy już chyba tak wysoko, że aż strach spoglądać w dół ;)
Co jednak ze wspomnianą wcześniej liczbą Grahama? Teraz na szczęście jej określenie jest już bardzo proste. Jest ona równa ni mniej, ni więcej, jak tylko… g64 :-)