1. Дробные числа
Допустим вы решили написать простейший калькулятор. Или любую другую программу, где нужны вычисления (от банального подсчёта денег до сложной физики). Далеко не всё в реальной жизни — целое число, и с этим ничего не поделаешь!
Так что давайте вооружимся новым типом данных!
В программировании дробные числа еще называют вещественными, или числами с плавающей точкой (floating-point). В Java, как и в большинстве языков, они нужны для хранения не только целых, но и "дробных" значений: всяких 3.14, -28.57, 2.718281828...
Вещественные числа бывают двух основных типов:
| Тип | Хранит | Диапазон значений (приблизительно) | Точность | Типичный размер |
|---|---|---|---|---|
|
Числа | ±1.5 × 10-45 ... ±3.4 × 1038 | ~7 знаков после запятой | 4 байта |
|
Числа | ±5.0 × 10-324 ... ±1.7 × 10308 | ~15–16 знаков после запятой | 8 байт |
Тип float
Тип float получил название от floating-point number — число с плавающей запятой. Вещественные числа — это числа из математики, у них есть определенные свойства. А у компьютера много ограничений. Поэтому не совсем корректно называть дробные числа в Java вещественными. Для них используется название "числа с плавающей запятой".
Тип float обычно хранит 7 значащих цифр (например, 0.1234567), степень десятки и занимает 4 байта в памяти. Этого очень мало для точных вычислений, поэтому все быстро перешли на числа двойной точности.
Тип double
Тип double получил свое название от двойная (double) точность. Он занимает в памяти 8 байт (в 2 раза больше, чем float) и может хранить до 15 значащих цифр: 0.123456789012345. Этого вполне достаточно для большинства вычислений с дробными числами, поэтому double является основным типом для хранения дробных чисел в Java.
В нынешней лекции основной акцент будет на типе double: он по умолчанию рекомендуется для всех “обычных” дробных чисел. Но дальше мы рассмотрим и тип float.
2. Объявление и инициализация переменных типа double
Всё, как с int — только теперь используем double.
// Объявляем переменную и присваиваем ей значение Пи
double pi = 3.1415926;
// Можно объявить и без инициализации
double averageSalary;
averageSalary = 91234.56;
// Можно вычислять!
double pizzaPieces = 8;
double friends = 3;
double piecesPerFriend = pizzaPieces / friends; // 2.666... (а не 2)
Особенности синтаксиса:
- В качестве десятичного разделителя используется точка (3.14). Если используете запятую — получите ошибку компиляции!
- Строго говоря, записав double d = 3;, вы не получите ошибку — типы автоматически приведутся (целое число превращается во "вещественное" без потерь).
3. Ввод и вывод вещественных чисел с помощью Scanner
Сначала попробуем вывести дробное число:
double amount = 42.75;
System.out.println(amount); // Выведет: 42.75
Всё хорошо! А если добавить текст:
System.out.println("На вашем счету: " + amount + " евро."); // На вашем счету: 42.75 евро.
Ввод с клавиатуры
Для ввода double нужно использовать специальный метод класса Scanner: console.nextDouble().
Scanner console = new Scanner(System.in);
System.out.println("Введите температуру за окном:");
double temperature = console.nextDouble(); // Сразу вводим double
System.out.println("На улице сейчас: " + temperature + " градусов.");
4. Тип double в действии: арифметика
Все привычные операции (+, -, *, /) работают, как и для int:
double distance = 100.5;
double time = 2.0;
double speed = distance / time; // 50.25
System.out.println("Средняя скорость: " + speed); // Средняя скорость: 50.25
Вот и вся арифметика. Единственное отличие: результат деления — всегда дробное число, если хотя бы один из операндов — double.
Сравним с int
int a = 5, b = 2;
System.out.println(a / b); // 2 (остаток отбрасывается)
double aa = 5, bb = 2;
System.out.println(aa / bb); // 2.5
5. Типичные ошибки и странности при работе с double
Ошибка преобразования ввода
Ситуация классическая: пользователь вводит 3,14 — а программа ждёт 3.14. В Java метод Scanner.nextDouble() ориентируется на текущую локаль: в русской/немецкой локали запятая допустима, в английской — нужна точка. При необходимости настройте локаль для Scanner или читайте строку и парсьте вручную.
// Это вызовет проблему в Locale.US, если введено "3,14"
double value = console.nextDouble();
Ошибка "неточности" чисел в компьютере
Вот здесь у новичков обычно начинается лёгкое недоумение:
double x = 0.1 + 0.2;
System.out.println(x); // Хм... 0.30000000000000004
Поздравляю, вы столкнулись с "магией" представления дробных чисел внутри компьютера. Дело в том, что многие числа невозможно точно представить в двоичной системе. Это обычно некритично для большинства приложений, но есть нюансы в финансах и точных науках.
6. Важно: double и int — автоматическое и явное преобразование
Бывает, что вы складываете целое и дробное, или присваиваете int переменной double, — ошибок не будет:
int i = 2;
double d = i; // Всё ок!
System.out.println(d); // 2
double dd = 3.7;
int ii = (int) dd; // Нужно явно привести тип double к типу int!
System.out.println(ii); // 3, дробная часть отбросилась
Часто это вызывает неожиданность — почему после приведения дробная часть исчезла? Просто потому, что тип int не умеет хранить дроби (всё, что после точки, исчезло навсегда).
Подробнее про преобразование double в int и оператор (int) в следующей лекции.
7. Форматированный вывод: красиво выводим double
Часто по умолчанию double выводится с кучей лишних нулей. Можно отформатировать вывод:
double temp = 23.56789;
System.out.println(temp); // 23.56789
// 2 знака после запятой
System.out.println(String.format("%.2f", temp)); // 23.57
// 1 знак после запятой
System.out.println(String.format("%.1f%n", temp)); // 23.6
| Формат | Результат | Описание |
|---|---|---|
|
23.57 | число с 2 знаками после запятой |
|
23.6 | число с 1 знаком после запятой |
8. Типичные ошибки при работе с float и double
Ошибка №1: неявное преобразование double в float
float f = 1.23; // Ошибка!
Компилятор будет недоволен: "Ты пытаешься положить double в float — это может привести к потере точности!" Всегда добавляй суффикс f.
Ошибка №2: забыли, что деление двух int — это int-результат
int a = 7, b = 2;
double result = a / b; // 3.0, а не 3.5
Чтобы получить дробную часть, явно преобразуй хотя бы один операнд:
double result = (double) a / b; // 3.5
Ошибка №3: сравнение дробных чисел
Не сравнивай дробные числа на равенство с помощью ==. Используй сравнение с небольшим допуском (epsilon).
Ошибка №4: потеря точности у float
Не храни большие числа или очень точные значения в float — они могут "сломаться" или потерять важные цифры.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ