JavaRush /Java Blog /Random EN /bigdecimal in java

bigdecimal in java

Published in the Random EN group
Hello! In today's lecture we will talk about large numbers. No, about the REALLY BIG ones. Previously , we have seen a table of value ranges for primitive data types more than once. It looks like this:
Primitive type Size in memory Range of values
byte 8 bit -128 to 127
short 16 bit to -32768 to 32767
char 16 bit from 0 to 65536
int 32 bits from -2147483648 to 2147483647
long 64 bits from -9223372036854775808 to 9223372036854775807
float 32 bits from (2 to the power -149) to ((2-2 to the power -23)*2 to the power 127)
double 64 bits from (-2 to the power of 63) to ((2 to the power of 63) - 1)
boolean 8 (when used in arrays), 32 (when used in non-arrays) true or false
If we are talking about integers, the most capacious data type is long , and when we are talking about floating point numbers, double . But what if the number we need is so large that it doesn’t even fit into long ? The range of possible Long values ​​is quite large, but still limited to a certain size - 64 bits. What can we come up with if our Very Large Number weighs 100 bits? Fortunately, you don't need to invent anything. In Java, two special classes were created for such cases - BigInteger (for integers) and BigDecimal (for floating-point numbers). What is their feature? First of all, they theoretically have no maximum size. Theoretically, because there are no computers with infinite memory. And if you create a number in the program that is larger than the size of the computer's memory, of course, the program will not work. But such cases are unlikely. Therefore, we can say that the size of numbers BigIntegeris BigDecimalpractically unlimited. What are these classes used for? First of all, for calculations with extremely high accuracy requirements. There are, for example, programs in which human life can depend on the accuracy of calculations (software for airplanes and rockets or for medical equipment). Therefore, if even the 150th decimal place plays an important role, BigDecimalit is the best choice. In addition, quite often these objects are used in the world of finance, where the accuracy of calculations down to the smallest values ​​is also extremely important. How to work with objects BigIntegerand BigDecimalwhat is important to remember about them? Objects of these classes are created like this:
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);
   }
}
Passing a string as a parameter is only one of the possible constructors. Here we use strings because our numbers exceed the maximum values long​​and double, and somehow we need to explain to the compiler exactly what number we want to get :) Just pass the number 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111 will not work: Java will try to “fit” the passed number into one of primitive data types, but it won’t fit into any of them. Therefore, using a string to pass the desired number is a good option. Both classes can automatically extract numeric values ​​from passed strings. Another important point to remember when working with large number classes is that their objects are immutable ( Immutable) . You are already well acquainted with the principle of immutability through the example of a class Stringand wrapper classes for primitives (Integer, Long and others).
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);

   }
}
Console output:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Our numbers haven't changed, as you'd expect. For the addition operation to succeed, you must create a new object and assign the result of the addition to it.
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);

   }
}
Console output:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Now everything works as it should :) By the way, did you notice how unusual the addition operation looks?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
This is another important point. Large number classes do not use the +-*/ operators in their operation, but instead provide a set of methods. Let's take a look at the main ones (you can, as always, find a complete list of methods in the Oracle documentation: here and here ).
  1. methods for performing arithmetic operations: add() , subtract(), multiply(), divide(). Used for addition, subtraction, multiplication and division operations respectively.

  2. doubleValue(), intValue(), floatValue(), longValue()etc. - Used to convert a large number to a Java primitive type. Be careful when using them and remember the difference in capacity!

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

    Console output:

    
    8198552921648689607
  3. min()and max()- allow you to find the minimum and maximum value of two large numbers passed.
    Please note: methods are not static!

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

    Console output:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

BigDecimal rounding control

This topic is included in a separate section, since rounding large numbers and adjusting it is not such a simple thing. You can set the number of decimal places for a number BigDecimalusing the setScale(). For example, we want to set the precision of the number 111.5555555555 to three decimal places. However, we will not be able to pass the number 3 as an argument to the method setScale()and thus solve our problem. As mentioned above, BigDecimalthese are numbers for calculations with increased accuracy. In its current form, our number has 10 decimal places. We want to discard 7 of them and leave only 3. Therefore, in addition to the number 3, we must pass the rounding mode as a parameter . There are 8 rounding modes in total BigDecimal. Quite a lot! But if you need to really fine-tune the accuracy of calculations in the program, you will have everything you need for this. So, here are the 8 rounding modes available in BigDecimal:
  1. ROUND_CEILING- rounding up

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- discharge discarding

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR- rounding down

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

  4. ROUND_HALF_UP— rounding up if the number after the decimal point >= .5

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN— rounding up if the number after the decimal point > .5

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN— rounding will depend on the number to the left of the decimal point. If the number on the left is even, then rounding will be done downward. If the number to the left of the decimal point is odd, it will be rounded up.

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

    The number to the left of the decimal point - 2 - is even. Rounding occurs down. Since we require 0 decimal places, the result will be 2.

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

    The number to the left of the decimal point - 3 - is odd. Rounding occurs upward. Since we require 0 decimal places, the result will be 4.

  7. ROUND_UNNECCESSARY— used in cases where the rounding mode needs to be passed to some method, but the number does not need rounding. If you try to round a number when the ROUND_UNNECCESSARY mode is set, an ArithmeticException is thrown.

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- rounding up.

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

Comparison of large numbers

This question is also important. You already remember that the method is used to compare objects in Java equals(). It is either provided by the language itself (in the case of Java's built-in classes) or overridden by the programmer. But in the case of class objects, it is not recommended BigDecimalto use the method equals()for comparison. The reason for this is that the BigDecimal.equals()two-number method returns true only if the two numbers have the same value and scaleequals() : Let's compare the behavior of the y Doubleand y methods 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));

   }
}
Console output:

true
false
As you can see, the numbers 1.5 and 1.50 in the case of c BigDecimalturned out to be unequal! This happened precisely because of the specifics of the method equals()in the class BigDecimal. For a more correct comparison of the two, BigDecimalit is better to use the method 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));

   }
}
Console output:

0
The method compareTo()returned 0, which means equal to 1.5 and 1.50. This is the result we were counting on! :) This concludes our lesson for today. It's time to get back to tasks! :)
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION