CodeGym /Java блог /Случаен /BigDecimal в Java
John Squirrels
Ниво
San Francisco

BigDecimal в Java

Публикувано в групата
здрасти В днешния урок ще говорим за големи числа. Не, имам предвид НАИСТИНА ГОЛЯМ. Преди многократно сме се сблъсквали с tableта с диапазони на стойности за примитивни типове данни. Изглежда така:
Примитивен тип Размер в паметта Диапазон на стойността
byte 8 бита -128 до 127
къс 16 бита -32768 до 32767
въглен 16 бита 0 до 65536
вътр 32 бита -2147483648 до 2147483647
дълго 64 бита -9223372036854775808 до 9223372036854775807
плавам 32 бита (2 на степен -149) до ((2 на степен -23) * 2 на степен 127)
двойно 64 бита (-2 на степен 63) до ((2 на степен 63) - 1)
булево 8 (когато се използва в масиви), 32 (когато не се използва в масиви) истина or лъжа
Най-просторният целочислен тип данни е long . Когато става дума за числа с плаваща запетая, това е двойното . Но Howво ще стане, ако числото, от което се нуждаем, е толкова голямо, че дори не се побира в дълго ? Дългият тип данни има доста голям диапазон от възможни стойности, но все пак е ограничен до 64 бита. Какво трябва да измислим, ако нашето Много голямо число изисква 100 бита? За щастие не е нужно да измисляме нищо. За случаи като този Java има два специални класа: BigInteger (за цели числа) и BigDecimal(за числа с плаваща запетая). Какво ги прави специални? Първо, на теория те нямат максимален размер. Казваме "на теория", защото няма компютри с безкрайна памет. И ако вашата програма създаде число, по-голямо от количеството налична памет, тогава програмата няма да работи, разбира се. Но такива случаи са малко вероятни. В резултат на това можем да кажем, че BigInteger и BigDecimal могат да представят числа с практически неограничен размер. За Howво се използват тези класове? На първо място, за изчисления с изключително строги изисквания за точност. Например човешкият живот може да зависи от точността на изчисленията в някои програми (например софтуер, който управлява самолети, ракети or медицинско оборудване). Така че, ако 150-ият знак след десетичната запетая е важен, тогава BigDecimalе най-добрият избор. В допълнение, обекти от този клас често се използват в света на финансите, където точното изчисляване дори на най-малките стойности също е изключително важно. Как работите с BigInteger и BigDecimal обекти и трябва ли да знаете за тях? Обектите от тези класове се създават по следния начин:

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
Предаването на низ към конструктора е само една възможна опция. Тук използваме низове, защото нашите числа надвишават максималните стойности за long и double и се нуждаем от няHowъв начин да обясним на компилатора кое число искаме да създадем :) Просто предаване на числото 1111111111111111111111111111111111111111111111111111111111111111111111 към конструктора няма да работи: Java ще се опита да натъпче подаденото число в един от примитивните типове данни, но то няма да се побере в нито един от тях. Ето защо използването на низ за предаване на желаното число е добър вариант. И двата класа могат автоматично да извличат числови стойности от предадените низове. Друг важен момент, който трябва да запомните, когато работите с класове с големи числа, е, че техните обекти са неизменни ( Immutable ). Вече сте запознати с неизменността благодарение на опита си с класа String и класовете обвивки за примитивни типове (Integer, Long и т.н.).

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
Конзолен изход:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
Както бихте очаквали, нашият номер не се е променил. За да извършите операцията по добавяне, трябва да създадете нов обект, за да получите резултата от операцията.

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
Конзолен изход:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Вижте, сега всичко работи Howто трябва :) Между другото, забелязахте ли колко необичайно изглежда операцията за добавяне?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
Това е друг важен момент. Класовете с големи числа не използват операторите + - * /. Вместо това те предоставят набор от методи. Нека се запознаем с основните (Howто винаги, можете да намерите пълен списък с методи в documentацията на Oracle: тук и тук ).
  1. методи за аритметични операции: add() , subtract() , multiply() , divide() . Тези методи се използват съответно за събиране, изваждане, умножение и деление.

  2. doubleValue() , intValue() , floatValue() , longValue() и т.н. се използват за преобразуване на голямо число в един от примитивните типове на Java. Бъдете внимателни, когато използвате тези методи. Не забравяйте за разликите в размера на битовете!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }
    

    Конзолен изход:

    
    8198552921648689607
    
  3. min() и max() ви позволяват да намерите минималната и максималната стойност на две големи числа.
    Имайте предвид, че тези методи не са статични!

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }
    

    Конзолен изход:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

BigDecimal поведение при закръгляване

Тази тема има отделен раздел, тъй като закръгляването на големи числа и конфигурирането на поведение при закръгляване не са толкова прости. Можете да използвате метода setScale() , за да зададете броя на десетичните знаци за BigDecimal . Да предположим например, че искаме числото 111.5555555555 да има три цифри след десетичната запетая. Не можем обаче да постигнем това, което искаме, като подадем числото 3 като аргумент на метода setScale() . Както бе споменато по-горе, BigDecimalе за представяне на числа със строги изисквания за изчислителна точност. В сегашния си вид нашето число има 10 цифри след десетичната запетая. Искаме да изпуснем 7 от тях и да запазим само 3. Съответно, освен числото 3, трябва да преминем и режима на закръгляване. BigDecimal има общо 8 режима на закръгляване. Това е много! Но ако наистина трябва да прецизирате прецизността на изчисленията си, ще имате всичко необходимо. И така, ето 8-те режима на закръгляване, предлагани от BigDecimal :
  1. ROUND_CEILING — закръглява нагоре

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN — закръгля към нула

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR — закръглява надолу

    
     111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
    
    

  4. ROUND_HALF_UP — закръглява нагоре, ако числото след десетичната запетая >= 0,5

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN — закръглява нагоре, ако числото след десетичната запетая > 0,5

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN — закръгляването зависи от числото вляво от десетичната запетая. Ако числото отляво е четно, закръгляването ще бъде надолу. Ако числото вляво от десетичната запетая е нечетно, тогава закръгляването ще бъде нагоре.

    
    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2
    

    Числото отляво на десетичната запетая е 2 (четно). Числото се закръгля надолу. Искаме 0 знака след десетичната запетая, така че резултатът е 2.

    
    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4
    

    Числото вляво от десетичната запетая е 3 (нечетно). Числото се закръгля нагоре. Искаме 0 знака след десетичната запетая, така че резултатът е 4.

  7. ROUND_UNNECCESSARY — Този режим се използва, когато трябва да подадете режим на закръгляване към метод, но числото не трябва да бъде закръглено. Ако се опитате да закръглите число със зададен режим ROUND_UNNECCESSARY, се хвърля ArithmeticException.

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP — закръглява от нулата.

    
    111.5551 -> setScale(3, ROUND_UP) -> 111.556
    

Сравняване на големи числа

Това също е важно. Спомняте си, че използваме метода equals() за сравняване на обекти в Java. Имплементацията се предоставя or от самия език (за стандартни Java класове), or се отменя от програмиста. Но в случай на BigDecimal обекти, използването на метода equals() за сравнения не се препоръчва. Това е така, защото методът BigDecimal.equals() връща true само ако 2-те числа имат една и съща стойност и мащаб: Нека сравним поведението на метода equals() за класовете Double и BigDecimal :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));
      
   }
}
Конзолен изход:

true 
false
Както можете да видите, за BigDecimal числата 1,5 и 1,50 се оказаха неравни! Това се дължи именно на спецификата на имплементацията на метода equals() в класа BigDecimal . За по-точно сравнение на два BigDecimal обекта е по-добре да използвате метода compareTo() :

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
Конзолен изход:

0
Методът compareTo() върна 0, което означава, че 1,5 и 1,50 са равни. И това е резултатът, който очаквахме! :) Това приключва днешния ни урок. Сега е време да се върнем към задачите! :)
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION