Monien äärettömien reaalilukujen tiivistäminen äärelliseksi määräksi bittejä vaatii likimääräisen esityksen. Useimmat ohjelmat tallentavat kokonaislukulaskelmien tulokset enintään 32 tai 64 bittiä. Koska mikä tahansa kiinteä määrä bittejä, useimmat reaaliluvuilla tehdyt laskelmat tuottavat määriä, joita ei voida esittää tarkasti käyttämällä niin montaa bittiä. Siksi liukulukulaskennan tulos on usein pyöristettävä, jotta se mahtuu takaisin sen äärelliseen esitykseen. Tämä pyöristysvirhe on liukulukulaskennan tyypillinen piirre. Siksi, kun käsittelemme laskelmia liukulukuilla (varsinkin jos laskelmat ovat rahallisia), meidän on huolehdittava ohjelmointikielen pyöristysvirheistä. Katsotaanpa esimerkkiä:
Javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
vlc lataa videoita youtubesta
Lähtö:
x = 0.7999999999999999
y = 0.8
false
Tässä vastaus ei ole se, mitä odotimme, koska java-kääntäjän tekemä pyöristys.
Syy pyöristysvirheen takana
Float- ja Double-tietotyypit toteuttavat IEEE-liukuluku 754 -määrityksen. Tämä tarkoittaa, että numerot esitetään seuraavassa muodossa:
SIGN FRACTION * 2 ^ EXP 0,15625 = (0,00101)2joka liukulukumuodossa esitetään muodossa: 1.01 * 2^-3
Kaikkia murtolukuja ei voida esittää tarkalleen kahden potenssin murto-osana. Yksinkertaisena esimerkkinä 0.1 = (0.000110011001100110011001100110011001100110011001100110011001… )2 eikä sitä siten voida tallentaa liukulukumuuttujan sisään.
Toinen esimerkki:
javapublic class Main { public static void main(String[] args) { double a = 0.7; double b = 0.9; double x = a + 0.1; double y = b - 0.1; System.out.println('x = ' + x); System.out.println('y = ' + y ); System.out.println(x == y); } }
Lähtö:
x = 0.7999999999999999
y = 0.8
false
Toinen esimerkki:
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); // Value of a is expected as 0.1 System.out.println('a = ' + a); } }
Lähtö:
a = 0.09999999999999998Kuinka korjata pyöristysvirheet?
- Pyöristä tulos: Round()-funktiota voidaan käyttää minimoimaan liukulukuaritmeettisen tallennuksen epätarkkuuden vaikutukset. Käyttäjä voi pyöristää numerot laskennan edellyttämään desimaalien määrään. Esimerkiksi kun työskentelet valuutan kanssa, pyöristät todennäköisesti 2 desimaalin tarkkuudella.
- Algoritmit ja toiminnot: Käytä numeerisesti vakaita algoritmeja tai suunnittele omia funktioita käsittelemään tällaisia tapauksia. Voit katkaista/pyöristää numeroita, joiden oikeellisuudesta et ole varma (voit myös laskea operaatioiden numeerista tarkkuutta)
- BigDecimal-luokka: Voit käyttää java.math.BigDecimal luokka, joka on suunniteltu antamaan meille tarkkuutta erityisesti suurten murtolukujen tapauksessa. Seuraava ohjelma näyttää, kuinka virhe voidaan poistaa:
import java.math.BigDecimal; import java.math.RoundingMode; public class Main { public static void main(String args[]) { BigDecimal a = new BigDecimal('1.0'); BigDecimal b = new BigDecimal('0.10'); BigDecimal x = b.multiply(new BigDecimal('9')); a = a.subtract(x); // Rounding to 1 decimal place a = a.setScale(1 RoundingMode.HALF_UP); System.out.println('a = ' + a); } }
Lähtö:
0.1Tässä a = a.setScale(1 RoundingMode.HALF_UP);
Pyöreät a1 desimaalin tarkkuudella käyttämällä HALF_UP pyöristystilaa. Joten BigDecimalin käyttö mahdollistaa aritmeettisten ja pyöristystoimintojen tarkemman hallinnan, mikä voi olla erityisen hyödyllistä taloudellisissa laskelmissa tai muissa tapauksissa, joissa tarkkuus on ratkaisevan tärkeää.
Tärkeä huomautus:
Math.round pyöristää arvon lähimpään kokonaislukuun. Koska 0,10 on lähempänä 0:aa kuin 1, se pyöristetään 0:ksi. Pyöristyksen ja 1,0:lla jakamisen jälkeen tulos on 0,0. Joten voit huomata eron tulosten välillä BigDecimal-luokan ja Maths.round-funktion avulla.
Javapublic class Main { public static void main(String args[]) { double a = 1.0; double b = 0.10; double x = 9 * b; a = a - (x); /* We use Math.round() function to round the answer to closest long then we multiply and divide by 1.0 to to set the decimal places to 1 place (this can be done according to the requirements.*/ System.out.println('a = ' + Math.round(a*1.0)/1.0); } }
Lähtö:
0.0