Avatar ·

Как округлить число до N знаков после запятой в Java?

Всем привет! Я новичок в Java и столкнулся с проблемой при работе с дробными числами. Мне нужно, чтобы после математических операций число выводилось с определенным количеством знаков после запятой. Например, я вычисляю среднее арифметическое и хочу показать результат с двумя знаками: 5.67, а не 5.6748912. Пробовал использовать `System.out.printf("%.2f", number)`, но это только для вывода. Мне нужно само число сохранить округленным для дальнейших расчетов. Пытался сделать так: ```java double value = 5.6748912; double rounded = Math.round(value * 100) / 100; System.out.println(rounded); // Выводит 5.0, а не 5.67! ``` Почему так происходит? Вроде умножил на 100, округлил, поделил — должно работать. Очевидно, что я что-то упускаю. Также слышал про `BigDecimal`, но не понимаю, как его правильно использовать. Подскажите, пожалуйста, надежный способ, который работает для любых чисел (положительных и отрицательных) и не теряет точность. Заранее спасибо! <<>>

Почему ваш код не работает и как исправить

Ваша ошибка — классическая для начинающих. Дело в том, что Math.round() возвращает long или int, а вы делите целое число на 100 — в результате получается целочисленное деление, и дробная часть отбрасывается. Исправленный вариант:

double value = 5.6748912;
double rounded = Math.round(value * 100.0) / 100.0;
System.out.println(rounded); // 5.67

Но это не идеальное решение из-за особенностей double. Лучший способ — использовать BigDecimal.

Самый правильный способ: BigDecimal

BigDecimal специально создан для точных денежных и научных расчетов. Он позволяет задавать точность и режим округления:

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Main {
    public static void main(String[] args) {
        double value = 5.6748912;
        BigDecimal bd = new BigDecimal(value).setScale(2, RoundingMode.HALF_UP);
        double rounded = bd.doubleValue();
        System.out.println(rounded); // 5.67
    }
}

Подробности

  • setScale(2, RoundingMode.HALF_UP) — оставляет 2 знака после запятой и округляет по правилу "половина вверх" (как в школе).
  • Другие режимы: HALF_DOWN, CEILING, FLOOR, UP, DOWN.
  • Если число нужно только для вывода, проще использовать String.format("%.2f", value) или DecimalFormat.

Универсальный метод

Создайте вспомогательную функцию:

public static double roundToDecimals(double value, int places) {
    if (places < 0) throw new IllegalArgumentException();
    BigDecimal bd = new BigDecimal(value);
    bd = bd.setScale(places, RoundingMode.HALF_UP);
    return bd.doubleValue();
}

Использование: double result = roundToDecimals(5.6748912, 2); // 5.67

Важное предостережение

Помните, что double сам по себе не может точно хранить некоторые десятичные числа (например, 0.1). Если вам критична точность (финансы, измерения), храните значения в BigDecimal с самого начала, а не конвертируйте туда-обратно. Для простых задач с double описанный метод работает отлично.

<<>>

Альтернативный подход: DecimalFormat

Если вам нужно только отформатировать число для вывода (без сохранения в переменной), используйте DecimalFormat:

import java.text.DecimalFormat;

double value = 5.6748912;
DecimalFormat df = new DecimalFormat("#.##");
String formatted = df.format(value);
System.out.println(formatted); // 5.67

Плюсы и минусы

  • Плюс: Простота, не нужно думать о RoundingMode — по умолчанию округление HALF_EVEN.
  • Минус: Возвращает String, а не число. Не подходит для дальнейших вычислений.

Дополнение к первому ответу

Если вы работаете с валютами, никогда не используйте double. Применяйте BigDecimal с самого начала:

BigDecimal price = new BigDecimal("19.99");
BigDecimal tax = new BigDecimal("0.20");
BigDecimal total = price.multiply(tax).setScale(2, RoundingMode.HALF_UP);
System.out.println(total); // 4.00

Обратите внимание: передавайте цену как строку "19.99", а не как 19.99 (double), чтобы избежать потери точности на этапе создания объекта.