2.18. Talsystemer

I computersproget Forth, kan man benytte omkring 70 forskellige talsystemer afhængig af sprogversionen. Det talsystem vi bruger i vore dage et 10-talsystemet eller det decimale talsystem. Sådan har det ikke været altid verden over. For omkring 4000 år siden brugtes 60-talsystemet i områ det lige nordvest for Persiske Hav. Lad os lige se på tallet 4320. Det består af 4 tusinder, 3 hundreder, 2 tiere og 0 enere, hvilket de fleste sikkert tager som en selvfølgelighed, men er det nu også så selvfølgelig? Nej, det allerede nævnte har sikkert allerede røbet, at det slet ikke er så enkelt 10-talsystemet er nonsens for enhver computer. Den kan alene arbejde i 2-talsystemet. Det skyldes, at computeren, som det elektriske apparat den er, reelt kun kan reagere på, om der går en strøm i en ledning eller ikke. Hvis der går en strøm, har man vedtaget at registrere tilstanden med tallet 1. Hvis der ikke går nogen strøm, registreres det med tallet 0.

2 er grundtal i totalsystemet, som 10 er det i 10-talsystemet og n i n-talsystemet. Cifrene i et talsystem udgør altid det antal, talsystemets grundtal angiver. Grundtallet er normalt det, der giver talsystemet dets navn. I totalsystemet er der to cifre (nul og et). I titalsystemet er der ti cifre (fra og med 0 til og med 9) osv.

Fordi alle talsystemer har 0 som laveste ciffer, bliver højeste ciffer en mindre end talsystemets grundtal. I 2-talsystemet bliver det størst ciffer således 2 - 1 = 1 og i 10-talsystemet 10 - 1 = 9 og sådan fremdeles. Det bageste ciffer (det længst til højre) vil repræsentere ciffer gange grundtal i første. Et ciffer i et tal vil altid udgøre ciffer gange grundtal i n - 1. Men lad os lade Python gøre det lidt klarere:

2.18.1. Hexadeximale og oktale tal

I Python specificeres et hexadecimalt tal ved et foranstillet nul efterfulgt af et x og afsluttet med det hexadecimale tal som f.eks. 0x49 svarende til 9 + 4 * 16 = 73 i vores normale 10-talsystem. Jeg kommer ikke nærmere ind på det oktale talsystem (det med grundtallet 8), men skal nøjes med kort at nævne, at i det er 7 største ciffer x udelades. Det betyder, at 0x49 svarer til 0111 (1 ener 1 8-er og 1 64-er eller 8 ** 2) altså 1 + 8 + 64 = 73 i det decimale talsystem. Det kan være svært for en begynder at forstå, så lad os se på et par eksempler:

Først et eksempel fra 10-talsystemet (decimaltal systemet)

>>> for i in range(0,9):
...     print "10 i",i,". er:", 10 ** i
...
10 i 0 . er: 1
10 i 1 . er: 10
10 i 2 . er: 100
10 i 3 . er: 1000
10 i 4 . er: 10000
10 i 5 . er: 100000
10 i 6 . er: 1000000
10 i 7 . er: 10000000
10 i 8 . er: 100000000
>>>

Det binære talsystem:
>>> for i in range(0,9):
...     print "2 i ",i,". er:", 2 ** i
...
2 i  0 . er: 1
2 i  1 . er: 2
2 i  2 . er: 4
2 i  3 . er: 8
2 i  4 . er: 16
2 i  5 . er: 32
2 i  6 . er: 64
2 i  7 . er: 128
2 i  8 . er: 256
>>>

Det oktale talsystem:
>>> for i in range(0,9):
...     print "8 i",i,". er:",8 ** i
...
8 i 0 . er: 1
8 i 1 . er: 8
8 i 2 . er: 64
8 i 3 . er: 512
8 i 4 . er: 4096
8 i 5 . er: 32768
8 i 6 . er: 262144
8 i 7 . er: 2097152
8 i 8 . er: 16777216
>>>

Det hexadecimale talsystem:
>>> for i in range(0,9):
...     print "16 i",i,". er:",16 ** i
...
16 i 0 . er: 1
16 i 1 . er: 16
16 i 2 . er: 256
16 i 3 . er: 4096
16 i 4 . er: 65536
16 i 5 . er: 1048576
16 i 6 . er: 16777216
16 i 7 . er: 268435456
16 i 8 . er: 4294967296
>>>

Udskriv hexadecimale tal:
>>> for i in range(0,17):
...     print hex(i)
...
0x0
0x1
0x2
0x3
0x4
0x5
0x6
0x7
0x8
0x9
0xa
0xb
0xc
0xd
0xe
0xf
0x10

Udskriv oktale tal
>>> for i in range(0,17):
...     print oct(i)
...
0
01
02
03
04
05
06
07
010
011
012
013
014
015
016
017
020

2.18.2. Fra oktale og hexadecimale tal til decimale

>>> a = 0x49
>>> a
73
>>> a = 0111
>>> a
73

>>> # om der benyttes "store" eller "små"
>>> # bogstaver er uden betydning
>>> a = 0xa5
>>> a
165
>>> b = 0XB2
>>> b
178

2.18.3. Fra decimale til oktale og hexadecimale tal

>>> oct(73)
'0111'
>>> hex(73)
'0x49'

2.18.4. Hexadecimale tal i tekststrenge

I tekststrenge erstattes nul af backslach.

>>> "\x41", chr(65) # 1 + 4 * 16 = 65
('A', 'A')
>>> "\x61", chr(97) # 1 + 6 * 16 = 97
('a', 'a')

Det lettest sagte er at funktion chr er gammeldags, vil fra Python 2.4 være helt out, så det er ene og alene unichr funktionen, der bør bruges. Men går vi i dybden, så er det ikke helt så let. Forklaringen er, at chr funktionen i dens oprindelige udformning ene og alene var beregnet til karakterer (tal, bogstaver m.m.), hvis numeriske værdi var under 129. Til og med Python 2.2 returneredes der en fejlmelding, hvis karakterens numeriske værdi var større end 128. Fra og med karakter nummer 129 og tegntabellen ud skulle funktionen unichr bruges. Kort sagt er det en større tegntabel, hvor stor ligger sådan lidt hen i det uvisse, for Pythons vedkommende bliver den fra version 2.4 enorm stor, da man går over til at bruge 64 bits (et ettal efterfulgt af 64 nuller) kode. Der må have været en del overvejelser i Python samfundet, om hvordan chr funktionen skal fungere fremover, for selv i den samme version af sproget er der og har der været afvigelser. I den version jeg bruger lige nu (en Python 2.3) returnerer chr og unichr funktionerne tegnnummer 156 således:

>>> chr(156)
'\x9c'
>>> unichr(156)
u'\x9c'
I begge tilfælde er returneringen helt i orden. At der står et u foran anførselstegnet i unichr returneringen fortæller, at strengen er en unicode streng, hvad chr returneringen naturligvis ikke er. FORDI returneringen her var i orden, kan der være god grund til at antage, at Python har "snydt" lidt, så der i den version jeg bruger lige nu, benyttes samme kode i chr som i unichr funktionerne, men som antydet er det ikke altid tilfældet, hvad du vil kunne konstere ved at bruge en Python version lavere end 2.3

l = []  # her oprettes tom liste
for i in range(65,91):
if i / 78 == 0: print "\n"
l.append(chr(i)) # chr konverteret tal til karakter (character)
...
>>> l
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
>>> l = []
>>> for i in range(65 + 32,91 + 32):
...     l.append(chr(i))
...
>>> l
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
>>>

Tallet 32 er lig med afstanden mellem et "store" bogstavs numeriske værdi og det tilsvarende "lille" bogstavs numeriske værdi.

>>> def  uni():
...     tal = input("Skriv et helt tal mellem -1 og 256: ")
...     print tal, unichr(tal)
...
>>> uni()
Skriv et helt tal mellem -1 og 256: 255
255 ÿ