Tervehdys kaikki,
Törmäsin tuossa ongelmaan floatien kanssa. Nimittäin jos lasken esim. 90.0 / 100.0 tulos pitäisi olla 0.9? Floatit antavat kuitenkin tulokseksi 0.89999998.
Löytisikö esim. standard kirjastoista joitan funktiota joka osais hanskata noi floatti "virheet"?
- Kiitos
Desimaaliluvut toteutetaan tietokoneissa yleensä käyttämällä liukulukuja, jotka eivät ole aina tarkkoja. Toisin sanoen esimerkiksi luvulle 0,9 ei ole tarkkaa esitystä. Silti esim. tämä tulostaa 0.9:
cout << 0.89999998 << endl;
Eli näytä koodistasi oleellinen kohta ja kerro mitä sen pitäisi tehdä.
Minua hämmästyttää, miten moni ohjelmoija ei tiedä liukuluvuista yhtään mitään, mutta kuitenkin käyttää niitä paljon ja kuvittelee niiden toimivan jonkin sortin taikuudella.
Kyseessä ei ole bugi vaan ominaisuus. Liukulukujen tarkkuus on rajallinen. Lisäksi ne ovat matalla tasolla kaksi- eivätkä kymmenkantaisia.
Jos esimerkiksi luku 1/3 pitäisi esittää kymmenjärjestelmässä ja käytössä olisi vain rajattu määrä desimaaleja, se pitäisi pyöristää (0,333 ≠ 0,333...). Vastaavasti monet luvut (kuten 0,9) vaatisivat kaksikantaisessa muodossa äärettömän monta desimaalia, joten ne pyöristyvät. Kun liukuluku sitten muutetaan takaisin kymmenjärjestelmään ja tulostetaan, vastaus ei välttämättä ole tasan se, mitä odotit.
Voit harkita vaihtoehdoksi esimerkiksi fixed point -esitystä tai murtolukuja.
Chiman kirjoitti:
Desimaaliluvut toteutetaan tietokoneissa yleensä käyttämällä liukulukuja, jotka eivät ole aina tarkkoja.
Itse tekisin selkeän eron desimaalilukujen ja liukulukujen välille. Useissa ohjelmointikielissä on erikseen float ja decimal (tms.) tietotyypit. Lauseestasi voisi saada käsityksen, että em. decimal toteutetaan usein liukulukuna.
Muilta osin yhdyn vastaukseesi.
Esimerkiksi rahamääriä ei pidä koskaan käsitellä liukulukuina, koska määrien pitää täsmätä tarkasti.
Grez kirjoitti:
Itse tekisin selkeän eron desimaalilukujen ja liukulukujen välille. Useissa ohjelmointikielissä on erikseen float ja decimal (tms.) tietotyypit. Lauseestasi voisi saada käsityksen, että em. decimal toteutetaan usein liukulukuna.
Niin, tarkoitin desimaalilukuja matemaattisena terminä: http://fi.wikipedia.org/wiki/Desimaaliluku
No kyllähän minä sen arvasin, mutta silti se voi aiheuttaa väärinkäsityksiä. Sitä paitsi en ole samaa mieltä että liukulukuina käsittely olisi "yleensä" eli ylivoimaisesti tyypillisin tapa käsitellä niitä. Toki liukulukuja käytetään hyvin yleisesti, mutta läheskään aina ne ei ole desimaalilukuja (matemaattinen termi).
En ole myöskään tuosta samaa mieltä että "rahamääriä ei koskaan..."
Ei niiden kaikissa tilanteissa tarvitse täsmätä tarkasti. Jos vaikka lasketaan kustannusarviota ja tulos ei muutenkaan olisi tarkka edes 1% tarkkuudella. Tällaisia laskuja voi ihan hyvin tehdä vaikka Excelillä (joka laskee sisäisesti liukuluvuilla)
Grez kirjoitti:
En ole myöskään tuosta samaa mieltä että "rahamääriä ei koskaan..."
Ei niiden kaikissa tilanteissa tarvitse täsmätä tarkasti.
Rahamäärien käsittely sentin tarkkuudella helpottaa lukujen jäljitettävyyttä, kun ei tarvitse kerääntyvien pyöristysvirheiden takia ihmetellä miksi luvut eivät täsmää.
Ainakaan minä en halua rohkaista ohjelmoijia toteuttamaan rahamäärien käsittelyä liukuluvuilla.
Chiman kirjoitti:
Grez kirjoitti:
En ole myöskään tuosta samaa mieltä että "rahamääriä ei koskaan..."
Ei niiden kaikissa tilanteissa tarvitse täsmätä tarkasti.Rahamäärien käsittely sentin tarkkuudella helpottaa lukujen jäljitettävyyttä, kun ei tarvitse kerääntyvien pyöristysvirheiden takia ihmetellä miksi luvut eivät täsmää.
Ainakaan minä en halua rohkaista ohjelmoijia toteuttamaan rahamäärien käsittelyä liukuluvuilla.
Maailma ei ole ihan niin yksinkertainen, että aina voisi esittää kaikki rahasummat sentin tai vastaavan kerrannaisina ja pelkkinä kokonaislukuina. Tavallisin vastaesimerkki nykyisin on bensan hinta, joka ihmisjärjelle käsittämättömistä, mutta bisnesjärjelle selvistä syistä esitetään sentin kymmenesosina litraa kohti.
Myös esimerkiksi rahasummien keskiarvon laskeminen, korosta puhumattakaan, tuppaa tuottamaan desimaaleja.
Hyvä ja oikea periaate on toki se, että rahasummat pyritään mahdollisuuksien mukaan esittämään kokonaislukuina. Mutta aina se ei ole mahdollista, ainakaan välivaiheissa.
Yucca kirjoitti:
Maailma ei ole ihan niin yksinkertainen, että aina voisi esittää kaikki rahasummat sentin tai vastaavan kerrannaisina ja pelkkinä kokonaislukuina. Tavallisin vastaesimerkki nykyisin on bensan hinta, joka ihmisjärjelle käsittämättömistä, mutta bisnesjärjelle selvistä syistä esitetään sentin kymmenesosina litraa kohti.
Bensan litrahinta, korko tai vaikka valuuttakurssi eivät ole rahamääriä vaan muuntokertoimia, jotka toimivat hyvin liukulukuina. Bensalaskun maksettava summa, tilin korkohyvitys ja valuutanvaihdossa saatava rahamäärä ovat kuitenkin aina kokonaisina sentteinä.
Pidän rahamääriä rahayksikön sadasosien kappalemääränä, johon kokonaisluku on luontainen valinta. Jos hyvin pienellä vaivalla voi tehdä hommat tarkasti ja varmasti, en näe syytä liukulukujen käyttöön. Toki tapauskohtainen harkinta on aina paikallaan.
Rehellisyyden nimissä myönnän, että käytännössä liukuluvuilla pärjää valtaosassa rahalaskuista ilman pyöristysvirheitä. Nähdäkseni vain suuri toistomäärä tai isot summat voivat luoda senttivirheitä.
Aihe on jo aika vanha, joten et voi enää vastata siihen.