logo

Закръгляване на грешки в Java

Компактирането на много безкрайни реални числа в краен брой битове изисква приблизително представяне. Повечето програми съхраняват резултата от целочислените изчисления при максимум 32 или 64 бита. Като се има предвид всеки фиксиран брой битове, повечето изчисления с реални числа ще произведат количества, които не могат да бъдат точно представени с помощта на толкова много битове. Следователно резултатът от изчисление с плаваща запетая често трябва да бъде закръглен, за да се побере обратно в неговото крайно представяне. Тази грешка при закръгляване е характерна черта на изчисленията с плаваща запетая. Следователно, докато обработваме изчисления в числа с плаваща запетая (особено ако изчисленията са от гледна точка на пари), трябва да се погрижим за грешки при закръгляване в език за програмиране. Да видим пример:

Java
public 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);  } } 


какво е хибернация в java

Изход:



x = 0.7999999999999999  
y = 0.8
false

Тук отговорът не е това, което очаквахме, поради закръгляването, направено от java компилатора.

Причина за грешката при закръгляне

Типовете данни Float и Double изпълняват спецификацията 754 на IEEE с плаваща запетая. Това означава, че числата са представени във форма като:

SIGN FRACTION * 2 ^ EXP 

0,15625 = (0,00101)2което във формат с плаваща запетая е представено като: 1,01 * 2^-3
Не всички дроби могат да бъдат представени точно като дроб от степен две. Като прост пример 0.1 = (0.000110011001100110011001100110011001100110011001100110011001… )2 и следователно не може да се съхранява в променлива с плаваща запетая.

Друг пример:

java
public 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);  } } 

Изход:

x = 0.7999999999999999  
y = 0.8
false

Друг пример:

Java
public 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);  } } 

Изход:

a = 0.09999999999999998

Как да коригираме грешките при закръгляне?

  • Закръглете резултата: Функцията Round() може да се използва за минимизиране на всякакви ефекти от неточността на аритметичното съхранение на плаваща запетая. Потребителят може да закръгли числата до броя на десетичните знаци, който се изисква от изчислението. Например, докато работите с валута, вероятно ще закръглите до 2 знака след десетичната запетая.
  • Алгоритми и функции: Използвайте числено стабилни алгоритми или проектирайте свои собствени функции за справяне с такива случаи. Можете да съкратите/закръглите цифри, за които не сте сигурни, че са правилни (можете също да изчислите числената точност на операциите)
  • BigDecimal клас: Можете да използвате java.math.BigDecimal клас, който е предназначен да ни даде точност, особено в случай на големи дробни числа. Следната програма показва как грешката може да бъде отстранена:
Java
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);  } } 


Изход:

0.1

тук a = a.setScale(1 RoundingMode.HALF_UP);

кръгове aдо 1 знак след десетичната запетая с помощта на режим на закръгляване HALF_UP. Така че използването на BigDecimal осигурява по-прецизен контрол върху аритметичните и закръглящите операции, което може да бъде особено полезно за финансови изчисления или други случаи, в които прецизността е от решаващо значение.

Важна забележка:

Math.round закръглява стойността до най-близкото цяло число. Тъй като 0,10 е по-близо до 0, отколкото до 1, то се закръгля до 0. След закръгляването и разделянето на 1,0 резултатът е 0,0. Така че можете да забележите разликата между изходите с класа BigDecimal и функцията Maths.round.

Java
public 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);  } } 

Изход:

0.0