Java Academy · Oppitunti

Miksi doublea ei käytetä rahalle

Liukulukujen tarkkuusongelmat

Oppitunti 1/413 vaihetta

Miksi doublea ei käytetä rahalle on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Vaarallinen oletus

Hintojen tallentaminen double-tyyppiin tuntuu luontevalta. Valitettavasti double ei pysty esittämään useimpia desimaalilukuja tarkasti, mikä aiheuttaa pieniä virheitä ja pilaa talouslaskelmat.

Klassinen yllätys

Kun luvut 0.1 ja 0.2 lasketaan yhteen double-tyypillä, tulokseksi ei saada 0.3:a. Tuloksessa on pieni pyöristysvirhe.

public class Main {
    public static void main(String[] args) {
        double result = 0.1 + 0.2;
        System.out.println(result);
    }
}

Miksi näin tapahtuu

Tietokoneet tallentavat double-arvot binäärimuodossa. Samoin kuin kolmasosaa ei voi esittää tarkasti desimaalimuodossa, monia desimaalilukuja, kuten 0.1:tä, ei voi esittää tarkasti binäärimuodossa.

Tallennettavaksi valitaan lähin binäärinen likiarvo, ja virhe kertyy.

Virheet kasaantuvat

Yksi pieni virhe voi vaikuttaa harmittomalta, mutta tuhansia tapahtumia käsittelevässä silmukassa erot kasaantuvat havaittaviksi virheiksi.

public class Main {
    public static void main(String[] args) {
        double total = 0.0;
        for (int i = 0; i < 10; i++) {
            total += 0.1;
        }
        System.out.println(total);
    }
}

Yhtäsuuruusvertailu epäonnistuu

Pyöristysvirheiden vuoksi laskettuja double-arvoja vertaileva ==-vertailu epäonnistuu usein silloin, kun odotatte niiden olevan yhtä suuria.

public class Main {
    public static void main(String[] args) {
        double a = 0.1 + 0.2;
        double b = 0.3;
        System.out.println(a == b);
    }
}

Rahalta vaaditaan tarkkuutta

Rahoituksessa sentin murto-osan virhettä ei voida hyväksyä. Tarkastajat odottavat summien täsmäävän sentilleen.

Siksi rahaa ei pidä koskaan tallentaa liukulukutyyppiin.

Ratkaisu: BigDecimal

Java tarjoaa BigDecimal-luokan, joka tallentaa desimaaliluvut tarkasti. Se käsittelee skaalaamattoman arvon ja skaalan erikseen, joten 0.1 tarkoittaa todella arvoa 0.1.

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("0.1");
        BigDecimal b = new BigDecimal("0.2");
        System.out.println(a.add(b));
    }
}

Käyttäkää aina String-rakentajaa

Luokaa BigDecimal String-arvosta, ei double-arvosta. double-arvon välittäminen siirtää binäärivirheen BigDecimal-arvoon.

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal fromDouble = new BigDecimal(0.1);
        BigDecimal fromString = new BigDecimal("0.1");
        System.out.println(fromDouble);
        System.out.println(fromString);
    }
}

Tai käyttäkää valueOf-metodia

BigDecimal.valueOf on turvallinen oikotie. Se muuntaa doublen kanonisen merkkijonoesityksen kautta ja välttää raakan binäärivirheen.

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal price = BigDecimal.valueOf(19.99);
        System.out.println(price);
    }
}

Rahan tallentaminen sentteinä

Yksinkertaisissa tapauksissa vaihtoehtona on tallentaa raha kokonaislukuna senttien määränä käyttäen long-tyyppiä. Tällöin 19.99 dollaria tarkoittaa 1999 senttiä, ja kaikki laskutoimitukset ovat tarkkaa kokonaislukulaskentaa.

public class Main {
    public static void main(String[] args) {
        long cents = 1999;
        long total = cents * 3;
        System.out.println(total + " cents");
    }
}

Tärkein opetus

Käyttäkää float- ja double-tyyppejä tieteellisissä ja graafisissa sovelluksissa, joissa pienet virheet ovat hyväksyttäviä. Käyttäkää rahalle ja kaikille täsmällisyyttä vaativille arvoille BigDecimal-tyyppiä tai kokonaisina sentteinä tallennettuja lukuja.

Pikatesti

Testatkaa ymmärrystänne liukulukujen tarkkuudesta.

Kertaus

Opitte, miksi double ei sovi rahalle:

  • Binäärinen liukulukuesitys ei pysty tallentamaan monia desimaalilukuja tarkasti
  • Virheet, kuten 0.1 + 0.2-laskun tuloksen poikkeaminen arvosta 0.3, kasaantuvat
  • Käyttäkää tarkkaan desimaalilaskentaan BigDecimal-tyyppiä
  • Luokaa se String-arvosta tai käyttäkää valueOf-metodia, älkää koskaan suoraan double-arvosta
  • Kokonaisina sentteinä tallentaminen on toinen tarkka vaihtoehto
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Miksi doublea ei käytetä rahalle” ilmainen?

Kyllä – oppitunnin ”Miksi doublea ei käytetä rahalle” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Miksi doublea ei käytetä rahalle”?

Liukulukujen tarkkuusongelmat Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”Miksi doublea ei käytetä rahalle”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Miksi doublea ei käytetä rahalle
  2. BigDecimalin käyttö
  3. Pyöristys ja skaala
  4. BigInteger suurille luvuille
← Takaisin: Java Academy