Perustietotyyppien ominaisuuksista¶
Seuraavat kaksi ohjelmaa vaikuttavat ensi silmäyksellä identtisiltä:
def main():
luku = int(input("Syötä luku: "))
if luku < 0:
print("Oltava ei-negatiivinen!")
else:
tulos = 1;
while luku > 0:
tulos = tulos * luku
luku -= 1
print("Kertoma on:", tulos)
main()
#include <iostream>
using namespace std;
int main() {
cout << "Syota luku: ";
int luku = 0;
cin >> luku;
if ( luku < 0 ) {
cout << "Oltava ei-negatiivinen!" << endl;
} else {
int tulos = 1;
while ( luku > 0 ) {
tulos = tulos * luku;
--luku;
}
cout << "Kertoma on: " << tulos << endl;
}
}
Kuitenkin jos ohjelmat suoritetaan ja annetaan alkuarvoksi esimerkiksi
17
, tulostaa Python-ohjelma 355687428096000
ja C++-ohjelma
-288522240
. C++:n laskema tulos on epäilemättä väärin, sillä
kertoman arvo (ei-negatiivisten lukujen tulo) ei voi olla
negatiivinen. Mistä ongelma johtuu?
Python on jossain määrin harvinainen ohjelmointikieli, koska siinä kokonaislukujen arvoa ei ole rajoitettu. Useimmissa muissa ohjelmointikielissä kokonaisluvut (ja muutkin lukutyypit) esitetään konekielitasolle päädyttäessä jollain kiinteällä määrällä bittejä. Tämä bittimäärä riippuu pääosin käytössä olevasta prosessoriarkkitehtuurista, mutta joskus myös käytetystä kääntäjästä. Tyypillinen bittimäärä kokonaislukuarvojen tapauksessa on 32 bittiä, mutta saattaa olla esimerkiksi 16 tai 64 bittiäkin.
Jos koneen prosessori esittää kokonaislukuarvot 32 bitillä, se ei pysty käsittelemään kuin kokonaislukuja, jotka ovat välillä -2147483648 – 2147483647 (yhteensä 232 erilaista). Jos laskutoimituksen tuloksena syntyy em. prosessorilla kokonaisluku, jota ei voi esittää 32 bitillä, tapahtuu ylivuoto. Ylivuodon seurauksena tulos on tietenkin virheellinen.
Vastaava tilanne voi syntyä myös reaaliluvuilla laskettaessa, olkoonkin että bittimäärät ja lukuarvot eivät ole samat, koska reaaliluvut esitetään eri muodossa kuin kokonaisluvut. Alivuodoksi kutsutaan tilannetta, jossa reaaliluvuilla laskettaessa saadaan itseisarvoltaan niin pieni tulos, että prosessori ei osaa erottaa sitä nollasta.
C++:ssa ohjelmoija voi jossain määrin yrittää vaikuttaa siihen, miten lukuja käsitellään: C++:ssa esimerkiksi on useita eri kokonaislukujen esittämiseen tarkoitettuja tietotyyppejä, kun Pythonissa oli vain yksi.
Koska kyseessä on jonkin verran nippelitietämys, tällä kurssilla yritetään selvitä seuraavilla tyypeillä:
int
eli normaali kokonaislukutyyppi, joka sopii positiivisten ja negatiivisten arvojen käsittelyynunsigned int
eli kokonaislukutyyppi, jolla voi käsitellä vain ei-negatiivisia lukuja (luonnolliset luvut)long int
eli tyyppi, joka saattaa mahdollistaa suuremman esitysalueen kuin normaaliint
-tyyppi, mutta vain jos tietokoneen prosessoriarkkitehtuuri tukee sitäunsigned long int
, joka on melko looginen yhdistelmä kahta edellistä.
Olennainen huomio tässä vaiheessa on se, että C++-kieli ei määrittele,
kuinka monella bitillä lukutietotyypit esitetään. Ei siis kannata
luottaa siihen, että int
-tyyppiset kokonaisluvut esitetään aina ja
kaikkialla 32 bitillä, vaikka se sattumalta onkin niin kurssin
työympäristössä.