Примитивный тип | Размер в памяти | Диапазон значений |
---|---|---|
byte | 8 бит | от -128 до 127 |
short | 16 бит | до -32768 до 32767 |
char | 16 бит | от 0 до 65536 |
int | 32 бита | от -2147483648 до 2147483647 |
long | 64 бита | от -9223372036854775808 до 9223372036854775807 |
float | 32 бита | от (2 в степени -149) до ((2-2 в степени -23)*2 в степени 127) |
double | 64 бита | от (-2 в степени 63) до ((2 в степени 63) - 1) |
boolean | 8 (при использовании в массивах), 32 (при использовании не в массивах) | true или false |
BigInteger
и BigDecimal
практически ничем не ограничен.
Для чего используются эти классы?
Прежде всего, для вычислений с крайне высокими требованиями к точности. Есть, к примеру, программы, в которых от точности вычислений может зависеть человеческая жизнь (ПО для самолетов и ракет или для медицинского оборудования).
Поэтому, если даже 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
, а как-то ведь надо объяснить компилятору, какое именно число мы хотим получить :)
Просто передать в конструктор число
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
не выйдет: 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);
}
}
Вывод в консоль:
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Наше число не изменилось, как и следовало ожидать. Чтобы операция сложения прошла успешно, необходимо создать новый объект и присвоить ему результат сложения.
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);
}
}
Вывод в консоль:
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
Вот, теперь все работает как надо :)
Кстати, обратил внимание, как необычно выглядит операция сложения?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
Это еще один важный момент. Классы больших чисел не используют в своей работе операторы +-*/, а предоставляют вместо этого набор методов.
Давай ознакомимся с основными из них (полный перечень методов ты, как и всегда, можешь найти в документации Oracle: здесь и здесь).
методы для осуществления арифметических операций:
add()
,subtract()
,multiply()
,divide()
. Используются для операций сложения, вычитания, умножения и деления соответственно.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
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
Эта тема вынесена в отдельный раздел, поскольку округление больших чисел и его настройка — вещь не такая уж простая. Ты можешь установить количество цифр после запятой для числаBigDecimal
при помощи метода setScale()
.
К примеру, мы хотим установить для числа 111.5555555555 точность в три цифры после запятой.
Однако мы не сможем передать число 3 в качестве аргумента в метод setScale()
и таким образом решить нашу задачу.
Как было сказано выше, BigDecimal
— это числа для вычислений с повышенной точностью.
В текущем виде наше число имеет 10 цифр после запятой. Мы же хотим отбросить 7 из них и оставить только 3. Поэтому кроме числа 3 мы должны передать в качестве параметра режим округления (rounding mode).
Всего у BigDecimal
существует 8 режимов округления. Немало! Но если тебе в программе понадобится действительно тонкая настройка точности вычислений, у тебя будет для этого все необходимое. Итак, вот какие 8 режимов округления есть в BigDecimal
:
ROUND_CEILING
— округление в большую сторону111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
ROUND_DOWN
— отбрасывание разряда111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
ROUND_FLOOR
— округление в меньшую сторону111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
ROUND_HALF_UP
— округление в большую сторону, если число после запятой >= .50.55 -> setScale(1, ROUND_HALF_UP) -> 0.6 0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
ROUND_HALF_DOWN
— округление в большую сторону, если число после запятой > .50.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5 0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.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.
ROUND_UNNECCESSARY
— используется в тех случаях, когда в какой-то метод нужно передать режим округления, но число в округлении не нуждается. Если попробовать произвести округление числа при выставленном режиме ROUND_UNNECCESSARY — выброшено исключение ArithmeticException.3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
ROUND_UP
— округление в большую сторону.111.5551 -> setScale(3, ROUND_UP) -> 111.556
Сравнение больших чисел
Этот вопрос тоже важен. Ты уже помнишь, что для сравнения объектов в Java используется методequals()
. Он либо предоставляется самим языком (в случае встроенных в Java классов), либо переопределяется программистом.
Но в случае с объектами классов BigDecimal
использовать метод equals()
для сравнения не рекомендуется.
Причина этого в том, что метод BigDecimal.equals()
двух чисел возвращает true только в случае, если 2 числа имеют одинаковое значение и масштаб (scale):
Давай сравним поведение методов 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
Как видишь, числа 1.5 и 1.50 в случае с BigDecimal
оказались неравны! Это произошло именно из-за специфики работы метода 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.
Это тот результат, на который мы и рассчитывали! :)
На этом наше сегодняшнее занятие окончено.
Самое время вернуться к задачам! :)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ