Kirjautuminen

Haku

Tehtävät

Koodit: QB: Luku muistissa

Kirjoittaja: Antti Laaksonen

Kirjoitettu: 22.01.2007 – 22.01.2007

Tagit: ohjelmointitavat, koodi näytille, vinkki

Luku 12345 voidaan QBasicissa tallentaa vaikkapa INTEGER-muuttujaan, jolloin muuttujan nimen perään tulee merkki %, tai SINGLE-muuttujaan, jolloin muuttujan nimen perään tulee merkki !. Näitä muuttujia voi käsitellä ohjelmassa samalla tavalla, mutta tietokoneen muistiin luvut tallennetaan tyystin eri tavalla. Tässä koodivinkissä näytetään, kuinka muuttujien sisältöä muistissa voi tutkia ja miten erityyppiset luvut tallennetaan muistiin.

QBasicissa INTEGER (%) ja LONG (&) ovat kokonaislukutyyppejä, kun taas SINGLE (!) ja DOUBLE (#) ovat liukulukutyyppejä. Kokonaislukujen arvot ovat tarkkoja ja rajoittuvat melko pienelle alueelle. Liukuluvuissa voi olla desimaaleja ja niiden lukualue on suurempi, mutta luvun arvoa ei pysty aina ilmoittamaan tarkasti. Tämän takia liukulukujen laskuissa esiintyy pyöristysvirheitä.

Funktio LEN kertoo, kuinka monta tavua lukumuuttuja vie tilaa muistissa. Esimerkiksi INTEGER-muuttuja vie kaksi tavua ja SINGLE-muuttuja vie neljä tavua. Näin INTEGER-muuttujalla voi olla 216 = 65536 eri arvoa ja SINGLE-muuttujalla voi olla 232 = 4294967296 eri arvoa. Lukualueet ovat INTEGER-muuttujalla -32768 - 32767 ja SINGLE-muuttujalla -3,4*1038 - -1,4*10-45 ja 1,4*10-45 - 3,4*1038. Lisäksi SINGLE-muuttuja voi saada arvon nolla.

Muuttujan sijainti muistissa selviää funktioilla VARSEG ja VARPTR, joista ensimmäinen ilmoittaa muuttujan segmentin ja toinen ilmoittaa muuttujan siirtymän. DOSissa muistiosoite ilmoitetaan kaksiosaisesti segmentin ja siirtymän avulla. Kun segmentti määritetään DEF SEG -komennolla, muistia pystyy nyt lukemaan PEEK-funktiolla ja muistiin pystyy kirjoittamaan POKE-komennolla. Käsiteltävä muistin paikka ilmoitetaan siirtymän avulla ja muistista luetaan tai sinne kirjoitetaan tavu kerrallaan.

Tältä näyttää INTEGER-muuttuja 12345 muistissa:
00111001 00110000

Nämä binääriluvuiksi muutetut tavut on saatu suoraan POKE-komennolla. Muuttuja on tallennettu muuten aivan tavalliseen tapaan binäärilukuna, mutta ensin tulee luvun loppuosa ja sitten vasta luvun alkuosa. Kun tavujen järjestys käännetään, tuloksena on binääriluku 11000000111001, joka on kymmenjärjestelmässä odotetusti 213 + 212 + 25 + 24 + 23 + 20 = 12345.

Tältä näyttää SINGLE-muuttuja 12345 muistissa:
00000000 11100100 01000000 01000110

Jälleen tavut täytyy lukea lopusta alkuun oikean tuloksen saamiseksi. Muistissa olevassa liukuluvussa on kolme osaa: etumerkki (1 bitti), eksponentti (8 bittiä) ja mantissa (23 bittiä). Etumerkki ilmoittaa, onko luku positiivinen vai negatiivinen. Tässä tapauksessa etumerkki on 0, mikä tarkoittaa positiivista lukua. Eksponentti ilmoittaa luvun pohjana olevan kakkosen potenssin ja mantissa ilmoittaa, millä luvulla tämä tulee kertoa. Sekä eksponentti että mantissa ilmoitetaan hieman erikoisella tavalla.

Eksponentti on muuten tavallinen 8-bittinen kokonaisluku, mutta siihen on lisätty luku 127. Siis jos muistissa on luku 200, tämä tarkoittaa lukua 73, ja jos muistissa on luku 15, tämä tarkoittaa lukua -112. Tässä tapauksessa eksponentti on binäärilukuna 10001100 eli kymmenjärjestelmässä 140. Kun tästä vähennetään 127, saadaan todellinen eksponentti 13. Luvun pohjana on tämän perusteella 213 = 8192.

Mantissan kokonaisosa on aina 1, jonka jälkeen on muuttuva desimaaliosa. Kun kokonaisosa on aina 1, sitä ei tarvitse erikseen tallentaa muistiin. Tässä tapauksessa mantissa on siis binäärilukuna 1,1000000111001 eli kymmenjärjestelmässä 20 + 2-1 + 2-8 + 2-9 + 2-10 + 2-13 = 1,506958008. Kun nyt tiedossa on sekä eksponentin tuottama kakkosen potenssi että mantissa, ne täytyy enää kertoa keskenään. Näin luvuksi saadaan 1,506958008 * 8192 = 12345.

Kun liukulukuja käyttelee huolettomasti ohjelmassa, tulee harvoin ajatelleeksi, kuinka suuren työn tietokone joutuu samaan aikaan tekemään. Myös muissa ohjelmointikielissä kokonaislukuja ja liukulukuja käsitellään muistissa tässä esitetyllä tavalla.

kluku% = 12345
lluku! = 12345

PRINT "Kokonaisluku vie tilaa"; LEN(kluku%); "tavua"
PRINT "Liukuluku vie tilaa"; LEN(lluku!); "tavua"
PRINT

PRINT "Kokonaisluku:"; kluku%
NaytaBitit VARSEG(kluku%), VARPTR(kluku%), LEN(kluku%)
PRINT

PRINT "Liukuluku:"; lluku!
NaytaBitit VARSEG(lluku!), VARPTR(lluku!), LEN(lluku!)
PRINT

' näyttää muistin sisällön tietyssä kohdassa
SUB NaytaBitit (segmentti%, siirto%, tavut%)
   DEF SEG = segmentti%
   FOR i% = 0 TO tavut% - 1
      luku% = PEEK(siirto% + i%)
      FOR j% = 7 TO 0 STEP -1
         IF (luku% AND 2 ^ j%) = 0 THEN
            PRINT "0";
         ELSE
            PRINT "1";
         END IF
      NEXT
      PRINT " ";
   NEXT
   PRINT
END SUB

Kommentit

moptim [24.01.2007 14:02:28]

#

:)

tesmu [24.01.2007 16:27:12]

#

KingOfTheWorld kirjoitti:

:)

indeed

OliO [06.05.2014 21:32:19]

#

:3

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta