Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C: float ja virheellinen tulos

Sivun loppuun

kayttaja-3842 [10.12.2012 12:21:34]

#

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

Chiman [10.12.2012 12:30:58]

#

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ä.

jlaire [10.12.2012 13:02:36]

#

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.

Grez [10.12.2012 13:02:39]

#

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.

Chiman [10.12.2012 13:30:46]

#

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

Grez [10.12.2012 14:11:42]

#

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)

Chiman [10.12.2012 15:32:14]

#

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.

Yucca [12.12.2012 19:51:53]

#

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.

Chiman [12.12.2012 21:03:34]

#

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ä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta