At komprimere mange uendelige reelle tal til et endeligt antal bit kræver en omtrentlig repræsentation. De fleste programmer gemmer resultatet af heltalsberegninger ved maks. 32 eller 64 bit. Givet et hvilket som helst fast antal bits vil de fleste beregninger med reelle tal producere mængder, der ikke kan repræsenteres nøjagtigt ved brug af så mange bits. Derfor skal resultatet af en flydende kommaberegning ofte afrundes for at passe tilbage til dens endelige repræsentation. Denne afrundingsfejl er et karakteristisk træk ved flydende kommaberegning. Derfor er vi nødt til at tage hånd om afrundingsfejl i et programmeringssprog, mens vi håndterer beregninger i flydende kommatal (især hvis beregninger er i form af penge). Lad os se et eksempel:
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); } }
kamelhylster python
Produktion:
x = 0.7999999999999999
y = 0.8
false
Her er svaret ikke, hvad vi forventede grunden til afrundingen udført af java compiler.
Årsag bag afrundingsfejl
Float- og Double-datatyper implementerer IEEE-floating point 754-specifikationen. Det betyder, at tal er repræsenteret i en form som:
SIGN FRACTION * 2 ^ EXP 0,15625 = (0,00101)2som i flydende kommaformat er repræsenteret som: 1,01 * 2^-3
Ikke alle brøker kan repræsenteres nøjagtigt som en brøkdel af en potens af to. Som et simpelt eksempel 0,1 = (0,000110011001100110011001100110011001100110011001100110011001…)2 og kan derfor ikke gemmes inde i en variabel med flydende komma.
Et andet eksempel:
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); } }
Produktion:
x = 0.7999999999999999
y = 0.8
false
Et andet eksempel:
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); } }
Produktion:
a = 0.09999999999999998Hvordan rettes afrundingsfejl?
- Afrund resultatet: Funktionen Round() kan bruges til at minimere eventuelle effekter af aritmetisk lagerunøjagtighed med flydende komma. Brugeren kan afrunde tal til det antal decimaler, der kræves af beregningen. For eksempel, mens du arbejder med valuta, vil du sandsynligvis afrunde til 2 decimaler.
- Algoritmer og funktioner: Brug numerisk stabile algoritmer eller design dine egne funktioner til at håndtere sådanne sager. Du kan afkorte/afrunde cifre, hvis du ikke er sikker på, at de er korrekte (du kan også beregne numerisk præcision af operationer)
- BigDecimal Klasse: Du kan bruge java.math.BigDecimal klasse, som er designet til at give os nøjagtighed, især i tilfælde af store brøktal. Følgende program viser, hvordan fejlen kan fjernes:
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); } }
Produktion:
0.1Her a = a.setScale(1 RoundingMode.HALF_UP);
runder atil 1 decimal ved at bruge HALF_UP afrundingstilstand. Så brug af BigDecimal giver mere præcis kontrol over aritmetikken og afrundingsoperationerne, hvilket kan være særligt nyttigt til økonomiske beregninger eller andre tilfælde, hvor præcision er afgørende.
Vigtig bemærkning:
Math.round afrunder værdien til nærmeste heltal. Da 0,10 er tættere på 0 end på 1, bliver det afrundet til 0. Efter afrunding og division med 1,0 er resultatet 0,0. Så du kan bemærke forskellen mellem output med BigDecimal klasse og Maths.round funktion.
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); } }
Produktion:
0.0