Etumerkittömän kokonaisluvun konvertoiminen ASCII-muotoon MC680x0:lla |
Markus Ketola |
Konekieliohjelmoija törmännee ennemmin tai myöhemmin tilanteeseen, jossa datarekisterissä oleva arvo olisi esim. debuggauksen vuoksi saatava tulostettua näkyviin. Korkeamman tason ohjelmointikielillä muuttujan arvon tulostaminen käy kivuttomasti jonkin funktion (esim. C-kielen printf) tai käskyn (esim. Basicin print) avulla, mutta konekieliohjelmoijan on tehtävä kaikki itse. Algoritmi luvun hajottamiseksi yksittäisiksi digiteiksi Käsiteltävä luku tulkitaan 10-järjestelmän luvuksi.
Toteutus 32-bittisille kokonaisluvuille MC68040:lla Suurin mahdollinen positiivinen 32-bittinen kokonaisluku on 2^32 - 1 = 4294967295 ja pienin tietysti 0. Mutta miten saada helposti selville annetun luvun digittien määrä? Joskus laskimella leikkiessäni keksin sattumalta kaavaan n = trunc(Log10(luku)) + 1 joka kertoo digittien määrän 10-järjestelmän luvussa. Nolla tosin täytyy käsitellä erikseen, koska siitä ei voi ottaa 10-kantaista logaritmia. Esimerkkirutiinissa lisätään annettuun lukuun 0.1 ennen kuin siitä otetaan 10-kantainen logaritmi FPU:n FLOG10-käskyllä. Tämä siksi, että muutoin 10:n potensseista tulee kokonaisluvuksi katkaisun jälkeen ykkösen verran liian pieniä tulokseksi. Tämä on sikäli outoa, että luvuista 10n luulisi tulevan helposti tasaluku vastaukseksi. Testieni mukaan FLOG10-käsky antaa 10:stä vastaukseksi noin "1 - epsilon", eli jotain hyvin lähellä 1:tä olevaa. Tosin FPU:ssa on jokin rekisteri, joka määrää mihin päin tulos pyöristetään, mutta rekisteristä tiedän vain sen olemassaolon. Muistelenkin jostain lukeneeni, ettei FPU:n käskyjä suositella käytettävän suoraan. Olisinkin käyttänyt tässä matematiikkakirjastoja, jos vain omistaisin dokumentaatiota niiden käytöstä. Tosin C-kielellä tekemäni kokeilut viittaavat siihen, että kyseisillä kirjastoillakin tulee vastaava ongelma eteen. Esimerkkirutiini:
Otsikosta huolimatta yllä olevan rutiinin pitäisi toimia sellaisenaan MC68020+ ja FPU -yhdistelmällä. Toteutus 16-bittisille kokonaisluvuille MC68000:lla Suurin mahdollinen 16-bittinen positiivinen kokonaisluku on 2^16 - 1 = 65535, ja pienin tietysti taas nolla. Erona edelliseen rutiiniin on lisäksi digittien määrän selvittämistapa: Nyt annettua lukua jaetaan 10:llä, kunnes kokonaisosa on nolla; jakojen määrä vastaa luvun digittien määrää. Esimerkkilistaus:
Toteutus C-kielellä :-) C-kielellä muuttajan arvon saisi tulostettua tietysti suoraan printf-funktiolla, mutta otin tämän esimerkin mukaan tuodakseni esiin, että tässä C-versiossa kummittelee vastaava pyöristysongelma kuin FPU:n FLOG10:tä käyttävässä esimerkissä. Ongelmakohta on LOG10-funktion tuloksen sijoittaminen integer-muuttujaan - double-muuttujaan sijoittaessa tulee toki oikea arvo. Esimerkki:
Merkille pantavaa on, että tekemäni kymmenkantaista logaritmia testaava ohjelma antaa eri vastauksen 68k-pohjaisessa Amiga-ympäristössä kuin Pentium-pohjaisessa Linux-ympäristössä siten, että jälkimmäisessä ympäristössä ohjelman antama tulos on oikein! Tämä siis tilanteessa, jossa 10-kantainen logaritmi luvuista 10n katkaistaan integer-muuttujaan. Alla kuvat testiohjelman tuloksista eri ympäristöissä. Ohessa vielä paketti, jossa ovat kaikki ohjelmat esimerkkilistauksineen. |