Встроенные примитивные числовые типы не всегда могут подходить для определенных программ. Например, необходимо хранить и использовать в программе очень большие числа, которые выходят за пределы допустимых значений для типов long и double. Кроме того, при вычислениями с числами с плавающей точкой мы можем столкнуться с рядом не очень приятных особенностей.
Все вычисления с плавающей точкой следуют спецификации IEEE 754. В частности, существует три специальных значения с плавающей точкой для обозначения переполнений и ошибок:
Положительная бесконечность (Positive infinity)
Отрицательная бесконечность (Negative infinity)
NaN (не число)
Для представления этих значений в Java есть специальные константы:
Double.POSITIVE_INFINITY (для типа double) и Float.POSITIVE_INFINITY (для типа float)
Double.NEGATIVE_INFINITY и Float.NEGATIVE_INFINITY
Double.NaN и Float.NaN
Например, результатом деления положительного числа с плавающей точкой на 0 является положительная бесконечность:
public class Program{
public static void main(String[] args) {
double d = 1.2;
double result = d / 0;
System.out.println(result); // Infinity
}
}
ПРи делении на -0.0 образуется отрицательная бесконечность (например, 1.0 / -0).
Деление 0,0 на 0 или квадратный корень отрицательного числа дает NaN:
public class Program{
public static void main(String[] args) {
double d = 0.0;
double result = d / 0;
System.out.println(result); // NaN
}
}
Мы можем использовать эти константы для проверки результата вычислений. Например:
public class Program{
public static void main(String[] args) {
double result1 = 0.0 / 0;
if(result1 == Double.NaN)
System.out.println("result1 is NaN");
else
System.out.printf("result1 is %f\n", result1);
double result2 = 1.0 / 0;
if(result2 == Double.POSITIVE_INFINITY)
System.out.println("result2 is Double.POSITIVE_INFINITY");
else
System.out.printf("result2 is %f\n", result2);
}
}
Для проверки на NaN также можно использовать встроенный метод Double.isNaN():
public class Program{
public static void main(String[] args) {
double result = 0.0 / 0;
if(Double.isNaN(result))
System.out.println("result is NaN");
else
System.out.printf("result is %f\n", result);
}
}
В целом следует отметить, что числа с плавающей точкой не подходят для финансовых вычислений, где ошибки округления недопустимы. Например:
public class Program{
public static void main(String[] args) {
System.out.println(2.0 - 1.1);
}
}
Данная программа выведет число 0.8999999999999999, а не 0.9. Такие ошибки округления возникают из-за того, что числа с плавающей точкой представлены в двоичной системе счисления.
А точного двоичного представления дроби 1/10 не существует. Поэтому если требуются точные вычисления без ошибок округления, то лучше использовать класс BigDecimal.
Основные методы класса BigDecimal:
BigDecimal add(BigDecimal other): возвращает сумму двух чисел
BigDecimal subtract(BigDecimal other): возвращает разность двух чисел
BigDecimal multiply(BigDecimal other): возвращает произведение двух чисел
BigDecimal divide(BigDecimal other): возвращает частное двух чисел
BigDecimal divide(BigDecimal other, RoundingMode mode): результат деления двух чисел, округленное в соответствии с режимом mode
int compareTo(BigDecimal other): сравнивает два числа. Возвращает -1, если текущий объект меньше числа other, 1 - если текущий объект больше и 0 - если числа равны
static BigDecimal valueOf(double x): возвращает объект BigDecimal, значение которого равно числу, переданному в качестве параметра
double doubleValue(): преобразует объект BigDecimal в double
float floatValue(): преобразует объект BigDecimal в float
Пример использования BigDecimal:
import java.math.*;
public class Program {
public static void main(String[] args) {
BigDecimal c = BigDecimal.valueOf(2325.06);
BigDecimal d = BigDecimal.valueOf(215.06);
c = c.subtract(d.multiply(BigDecimal.valueOf(2.1)));
System.out.println(c); // 1873.434
double y = c.doubleValue();
System.out.println(y); // 1873.434
}
}
Для работы с очень большими целочисленными значениями числовыми данными можно использовать тип BigInteger из пакета java.math. Основные методы класса BigInteger:
BigInteger add(BigInteger other): возвращает сумму двух чисел
BigInteger subtract(BigInteger other): возвращает разность двух чисел
BigInteger multiply(BigInteger other): возвращает произведение двух чисел
BigInteger divide(BigInteger other): возвращает частное двух чисел
BigInteger mod(BigInteger other): возвращает остаток от целочисленного деления двух чисел
BigInteger sqrt(): возвращает квадратный корень числа
int compareTo(BigInteger other): сравнивает два числа. Возвращает -1, если текущий объект меньше числа other, 1 - если текущий объект больше и 0 - если числа равны
static BigInteger valueOf(long x): возвращает объект BigInteger, значение которого равно числу, переданному в качестве параметра
int intValue(): конвертирует объект BigInteger в объект int
byte byteValue(): преобразует объект BigInteger в byte
short shortValue(): преобразует объект BigInteger в short
long longValue(): преобразует объект BigInteger в long
Пример использования класса BigInteger:
import java.math.*;
public class Program {
public static void main(String[] args) {
BigInteger a = BigInteger.valueOf(2147483647);
BigInteger b = BigInteger.valueOf(2147483641);
//a = a * b; // так нельзя
a = a.multiply(b);
System.out.println(a); // 4611686001247518727
long x = a.longValue();
System.out.println(x); // 4611686001247518727
}
}
Стоит отметить, несмотря на то, что объекты BigInteger и BigDecimal представляют числа, мы не можем применять с ними стандартные арифметические операции. Все математические действия с данными объектами идут через их методы.