1. Введение
В реальной жизни редко бывает, чтобы нам нужно было видеть длинные «хвосты» после запятой. Например, если вы считаете стоимость товара, зарплату, средний балл или площадь комнаты, — вам обычно достаточно пары знаков после запятой, а не 15-ти.
Например, результат деления:
double x = 10.0 / 3.0;
System.out.println(x); // 3.3333333333333335
Пользователь, увидев такой результат, может испугаться и подумать, что программа сошла с ума. Поэтому числа часто нужно округлять — до ближайшего целого, до двух знаков после запятой и так далее.
В Java для этого есть несколько удобных инструментов.
2. Метод Math.round(): округление до ближайшего целого
Самый простой способ округлить число — воспользоваться методом Math.round(). Он принимает число с плавающей точкой (можно и float, и double) и возвращает ближайшее целое.
Как работает Math.round
- Если дробная часть меньше 0.5 — округляет вниз.
- Если дробная часть 0.5 или больше — округляет вверх.
Примеры:
System.out.println(Math.round(2.3)); // 2
System.out.println(Math.round(2.7)); // 3
System.out.println(Math.round(2.5)); // 3
System.out.println(Math.round(-2.5)); // -2
Тип возвращаемого значения
- Если передать float, вернётся int.
- Если передать double, вернётся long.
float f = 5.8f;
int roundedF = Math.round(f); // 6
double d = 5.8;
long roundedD = Math.round(d); // 6
Обратите внимание: иногда это вызывает удивление — округлили double, а получили long! Если вам нужен int, придётся сделать явное приведение:
int rounded = (int) Math.round(5.6); // 6
3. Округление до нужного количества знаков после запятой
Часто нужно округлить не до целого, а, например, до двух знаков после запятой (для денег, процентов и т.д.).
В Java нет «волшебного» метода вроде Math.roundTo2Digits(), но можно сделать это вручную.
Способ 1: математический трюк с умножением и делением
- Умножаем число на 100 (если нужно два знака).
- Округляем до целого с помощью Math.round.
- Делим обратно на 100.
Пример:
double value = 3.14159;
double rounded = Math.round(value * 100.0) / 100.0;
System.out.println(rounded); // 3.14
Как это работает:
- 3.14159 * 100 = 314.159
- Math.round(314.159) = 314
- 314 / 100.0 = 3.14
4. Форматирование чисел: класс DecimalFormat
Иногда нужно не только округлить число, но и вывести его красиво — с определённым количеством знаков после запятой, ведущими нулями, разделителями разрядов и т.п. Для этого в Java есть класс DecimalFormat из пакета java.text.
Как работает DecimalFormat
- Создаём объект с нужным шаблоном.
- Вызываем у него метод format(...).
import java.text.DecimalFormat;
double value = 3.14159;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(value)); // 3.14
Как устроен шаблон
- "0.00" — всегда два знака после запятой (даже если число целое).
- "0.###" — до трёх знаков после запятой, лишние нули не выводятся.
- "#,##0.00" — добавляет разделители тысяч (например, "1,234.56").
Примеры разных шаблонов:
| Шаблон | Число | Результат |
|---|---|---|
|
2 | 2.00 |
|
2.5 | 2.50 |
|
2.567 | 2.57 |
|
2.567 | 2.567 |
|
2.5 | 2.5 |
|
12345.678 | 12,345.68 |
Пример с разделителями тысяч
DecimalFormat df = new DecimalFormat("#,##0.00");
System.out.println(df.format(1234567.89)); // 1,234,567.89
Пример: вывод без лишних нулей
DecimalFormat df = new DecimalFormat("0.##");
System.out.println(df.format(3.1)); // 3.1
System.out.println(df.format(3.141)); // 3.14
System.out.println(df.format(3.145)); // 3.15
5. Форматирование с помощью String.format
Иногда для простых случаев удобно использовать String.format — встроенный способ форматировать строки, похожий на printf в других языках.
double value = 3.14159;
System.out.println(String.format("%.2f", value)); // 3.14
Здесь "%.2f" — означает «вывести число с двумя знаками после запятой».
Сравнение подходов:
- DecimalFormat — мощнее, поддерживает шаблоны и локализацию, удобен для разделителей тысяч.
- String.format — проще, если нужно просто задать количество знаков после запятой.
6. Особенности округления: Math.floor, Math.ceil, Math.rint
- Math.floor(x) — округляет вниз (в меньшую сторону), в том числе для отрицательных чисел.
- Math.ceil(x) — округляет вверх (в большую сторону).
- Math.rint(x) — округляет до ближайшего целого, но возвращает double.
Примеры:
System.out.println(Math.floor(2.7)); // 2.0
System.out.println(Math.ceil(2.1)); // 3.0
System.out.println(Math.rint(2.5)); // 2.0 (да-да, не опечатка!)
System.out.println(Math.rint(3.5)); // 4.0
Внимание: Math.rint иногда округляет «к ближайшему чётному» — это правило (т.н. banker's rounding) помогает уменьшать накопление ошибок при массовых вычислениях.
7. Полезные нюансы
Визуализация: таблица округлений
| Число | Math.round | Math.floor | Math.ceil | Math.rint |
|---|---|---|---|---|
| 2.3 | 2 | 2.0 | 3.0 | 2.0 |
| 2.5 | 3 | 2.0 | 3.0 | 2.0 |
| 3.5 | 4 | 3.0 | 4.0 | 4.0 |
| -2.3 | -2 | -3.0 | -2.0 | -2.0 |
| -2.5 | -2 | -3.0 | -2.0 | -2.0 |
Округление — это не форматирование!
Очень важно понимать разницу между округлением и форматированием.
- Округление — изменение значения числа (например, 2.718 → 2.72).
- Форматирование — изменение того, как число выглядит при выводе (например, 2.718 → "2.72" на экране, но в памяти остаётся 2.718).
double x = 2.718;
System.out.println(String.format("%.2f", x)); // 2.72
System.out.println(x); // 2.718
Если вы хотите использовать округлённое число в дальнейших вычислениях — округляйте математически! Если только для вывода — форматируйте.
8. Типичные ошибки при округлении и форматировании чисел
Ошибка №1: Округлили только для вывода, а дальше используем «хвостатое» число.
Очень частая ситуация — вывести красиво отформатированное значение на экран, а затем использовать исходное «длинное» число в расчётах. Для денег, баллов и итогов — сначала округлите (например, Math.round или приём с умножением/делением), затем сохраняйте/передавайте пользователю.
Ошибка №2: Ожидание, что Math.round(x) вернёт double с двумя знаками после запятой.
Math.round() всегда округляет до ближайшего целого: для float возвращает int, для double — long. Для двух знаков используйте умножение/деление или форматирование.
Ошибка №3: Использование DecimalFormat для вычислений.
DecimalFormat.format() возвращает строку. Использовать её в арифметике нельзя: получите ошибку компиляции или NumberFormatException при обратном разборе.
Ошибка №4: Неправильный шаблон DecimalFormat.
Шаблон должен соответствовать ожиданиям: "0.00" всегда покажет два знака ("2.00"), а "0.##" уберёт лишние нули ("2", "2.1", "2.12").
Ошибка №5: Потеря точности при делении на 100.
Если вы делите int на int, результат тоже int!
int a = 5;
System.out.println(a / 2); // 2, а не 2.5!
Чтобы деление было «дробным», хотя бы один операнд должен быть double:
int a = 5;
System.out.println(a / 2.0); // 2.5
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ