Miksi doublea ei käytetä rahalle
Liukulukujen tarkkuusongelmat
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
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
- Miksi doublea ei käytetä rahalle
- BigDecimalin käyttö
- Pyöristys ja skaala
- BigInteger suurille luvuille