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

Работающие реализации на Go

Round(), используемая в Postgres

Выше я уже упоминал, что в Postgres содержится код функции Round() на C, который работает для всех тестируемых значений. В CockroachDB мы , без комментариев он выглядит следующим образом:

Давайте разберёмся, как он работает. Первые шесть строк обрабатывают особые случаи. Далее мы выбираем roundFn из Ceil и Floor в зависимости от того, положительное число или отрицательное. Далее начинается самое интересное:

Этим кодом мы сдвигаем x ближе к нулю.

Далее мы проверяем, не стал ли x в точности нулём и не поменялся ли у него знак. Это означает что исходное число <= 0,5, в этом случае мы возвращаем ноль с нужным знаком.

Эта проверка нужна для очень больших чисел, для которых x-0,5 == x-1,0, в этих случаях мы можем вернуть число неизменённым.

Далее мы округляем число с помощью Floor() или Ceil() и возвращаем это значение, если оно отличается от x, что может случиться, только если дробная часть входного значения не равна в точности 0,5, так как выше мы вычли 0,5 из него.

Теперь мы знаем, что дробная часть равна 0,5, поэтому нам нужно округлить до ближайшего чётного числа (реализация Round() в Postgres в этом месте отличается от приведённых выше вариантов). Комментарий в коде лучше это описывает:

Чтобы сохранить оригинальное поведение, этот код можно заменить на следующий:

github.com/montanaflynn/stats

Ещё одна работающая реализация содержится в пакете github.com/montanaflynn/stats. Без комментариев она выглядит следующим образом:

Ключевое отличие от предыдущих решений заключается в использовании функции Modf(), которая корректно разделяет целую и дробную части чисел.

Math.round Java examples

Math.round is a static method and is part of java.lang.Math class. This method performs the rounding of a floating-point number to the nearest integer or long. There are two overloaded implementations of this method,

  1. returns the closest integer to the argument.
  2. returns the closest long to the argument.

Both of these methods always round up.

2.1. Code examples

Below example shows how math round works. It covers both regular scenarios and edge cases.

public class MathRoundingDemo {
    public static void main(String[] args) {
        //Round the floating point number to integer
        //Case 1: Rounding the number to lower whole number
		System.out.println("Rounding the number to lower whole number");
        System.out.println(String.format("3.2 is rounded to - %d", Math.round(3.2)));
		System.out.println("---------------------------------------------------");

        //Case 2: Rounding the number number to next integer
		System.out.println("Rounding the number number to next integer");
        System.out.println(String.format("3.7 is rounded to - %d", Math.round(3.7)));
		System.out.println("---------------------------------------------------");

        //Case 3: When the only number after decimal point is 5, number is rounded to upper whole number
		System.out.println("When the only number after decimal point is 5, number is rounded to upper whole number");
        System.out.println(String.format("3.5 is rounded to - %d", Math.round(3.5)));
		System.out.println("---------------------------------------------------");

        //Case 4: Numbers never double round up
		System.out.println("Numbers never double round up");
        System.out.println(String.format("7.4999 is rounded to - %d", Math.round(7.4999)));
		System.out.println("---------------------------------------------------");

        //Rounding to long value
		System.out.println("Rounding to long value");
        long roundedToLong = Math.round(123234.5);
        System.out.println("Rounded long value - " + roundedToLong);
		System.out.println("---------------------------------------------------");
        
        //Rounding the edge case numbers
        //Case 1: When argument passed is not a number, then ZERO is returned
		System.out.println("When argument passed is not a number, then ZERO is returned");
        System.out.println(String.format("0/0 is rounded to - %d", Math.round(Float.NaN)));
		System.out.println("---------------------------------------------------");

        //Case 2: When negetive infinity is rounded then Long.MIN_VALUE is returned
		float negativeInfinity = -1/0.0f;
		int roundedNum = Math.round(negativeInfinity);
		System.out.println("When negetive infinity is rounded then Long.MIN_VALUE is returned");
        System.out.println(String.format("-1/0 is rounded to - %d", roundedNum));
		System.out.println("---------------------------------------------------");

        //Case 2: When positive infinity is rounded then Long.MAX_VALUE is returned
		float positiveInfinity = 1/0.0f;
		int roundedMaxNum = Math.round(positiveInfinity);
		System.out.println("When positive infinity is rounded then Long.MAX_VALUE is returned");
        System.out.println(String.format("1/0 is rounded to - %d", roundedMaxNum));
		System.out.println("---------------------------------------------------");
    }
}

The output of the program looks as below:

MathRoundingDemo.java output

2.2. How to run the sample program

  • Save example code to in a directory of your choice.
  • Open the command prompt and navigate to the directory where the file is saved.
  • Run the command to compile, this will generate .
  • To run the example, run command . Don’t specify any extension.

2.3. Edge cases

  • When argument passed is a NaN, then it returns ZERO
  • When the passed number argument is negative infinity, it returns Long.MIN_VALUE
  • When the argument is positive infinity, it returns Long.MAX_VALUE

What does rounding mean?

Rounding is the mathematical process of making the number up or down to the nearest whole number. In this number process, any given decimal number is converted to the nearest whole number. For example,

  1. 3.2 is rounded to 3
  2. 3.7 is rounded to 4
  3. 3.5 is rounded to 4
  4. 7.49 is rounded to 7
  5. 7.4999999 is rounded to 7

Note: When the first digit after the decimal point is less than 5, then the number is rounded to lower integer and when it is 5 or more, then it is rounded to the next integer. Another important thing to remember is, not to double round. Do not round 7.49 as 7.5 and then round 7.5 to 8. Remember that, 7.49 is always rounded to 7.

Математические вычисления и класс Math

Последнее обновление: 28.10.2018

Для выполнения различных математических операций в Java в пакете java.lang определен класс
Math. Рассмотрим его основные методы:

  • : возвращает абсолютное значение для аргумента value

    double result = Math.abs(-13.5); // 13.5
    
  • : возвращает арккосинус value. Параметр value должен иметь значение от -1 до 1

    double result = Math.acos(1); // 0.0
    
  • : возвращает арксинус value. Параметр value должен иметь значение от -1 до 1

  • : возвращает арктангенс value

  • : возвращает кубический корень числа value

    double result = Math.cbrt(27); // 3
    
  • : возвращает наименьшее целое число с плавающей точкой, которое не меньше value

    double result = Math.ceil(2.34); // 3
    
  • : возвращает косинус угла d

  • : возвращает гиперболический косинус угла d

  • : возвращает основание натурального логарифма, возведенное в степень d

  • : возвращает наибольшее целое число, которое не больше d

    double result = Math.floor(2.56); // 2
    
  • : возвращает целочисленный результат деления a на b

    System.out.println(Math.floorDiv(1, 2)); // 0
    System.out.println(Math.floorDiv(7, 2)); // 3
    System.out.println(Math.floorDiv(9, 2)); // 4
    
  • : возвращает натуральный логарифм числа a

  • : возвращает натуральный логарифм числа (d + 1)

  • : возвращает десятичный логарифм числа d

  • : возвращает максимальное число из a и b

  • : возвращает минимальное число из a и b

  • : возвращает число a, возведенное в степень b

  • : возвращает случайное число от 0.0 до 1.0

  • : возвращает число double, которое представляет ближайшее к числу value целое число

    System.out.println(Math.rint(2)); // 2.0
    System.out.println(Math.rint(2.3)); // 2.0
    System.out.println(Math.rint(2.5)); // 2.0
    System.out.println(Math.rint(2.5001)); // 3.0
    System.out.println(Math.rint(2.8)); // 3.0
    
  • : возвращает число d, округленное до ближайшего целого числа

    System.out.println(Math.round(2.3)); // 2
    System.out.println(Math.round(2.5)); // 3
    System.out.println(Math.round(2.5001)); // 3
    System.out.println(Math.round(2.8)); // 3
    
  • : возвращает произведение числа value на 2 в степени factor

    System.out.println(Math.scalb(5, 3)); // 5*2*2*2 = 40
    System.out.println(Math.scalb(3, 4)); // 3*2*2*2*2 = 48
    
  • : возвращает число 1, если число value положительное, и -1, если значение value отрицательное. Если value равно 0, то возвращает 0

    System.out.println(Math.signum(2.3)); // 1
    System.out.println(Math.signum(-2.3)); // -1
    
  • : возвращает синус угла value

  • : возвращает гиперболический синус угла value

  • : возвращает квадратный корень числа value

    double result1 = Math.sqrt(16); // 4
    
  • : возвращает тангенс угла value

  • : возвращает гиперболический тангенс угла value

  • переводит радианы в градусы и — градусы в радианы

    System.out.println(Math.toDegrees(3.14159)); // 180
    System.out.println(Math.toRadians(90)); // 1,57079....
    

Также класс Math определяет две константы: и . Например, вычислим площадь круга:

import java.util.Scanner;

public class Program {
  
    public static void main(String[] args) {
          
        Scanner in = new Scanner(System.in);
        
        System.out.print("Введите радиус круга: ");
        int radius = in.nextInt();
        long area = Math.round(Math.PI * Math.pow(radius, 2));
        System.out.printf("Площадь круга с радиусом %d равна %d \n", radius, area);
    }
}

Консольный вывод:

Введите радиус круга: 10
Площадь круга с радиусом 10 равна 314

НазадВперед

2 Алгебраические функции в Java

В большинстве случаев программисту с головой хватает школьной математики: даже синусы и косинусы в коде можно встретить очень редко. Чаще всего они нужны при работе с играми, картами или игровыми движками. 90% программистов с этим никогда не сталкиваются.

Но, кроме геометрии, программистам иногда приходится использовать и алгебраические функции. И, конечно же, класс содержит самые распространенные из них:

Метод Описание
квадратный корень из
кубический корень из
возведение в степень:
экспонента:
натуральный логарифм :
десятичный логарифм :
натуральный логарифм :

Если вам нужен квадратный или кубический корень из числа, для этого есть функции и .

Корень из двух можно вычислить так:

Если вы хотите получить корень более высокой степени, воспользуйтесь функцией возведения в степень: в степени — это и будет корень четвертой степени, и т.д.

Для работы с логарифмами и экспонентами есть функции – натуральный логарифм и — экспонента. Для вычисления десятичного логарифма есть функция .

Если вам нужен логарифм числа по основанию , воспользуйтесь простой формулой:

Полезные функции

Последние две функции и могут быть вам полезны, если вы проводите вычисления при очень маленьких значениях .

При сложении очень маленьких и очень больших переменных часто может возникнуть ситуация, когда очень маленькое значение просто игнорируется (отбрасывается) как незначащее. Это, собственно, и будет происходить, если использовать функции и . Поэтому программисты придумали функции, которые возвращают только ту самую «маленькую значащую часть»

Пример:

Вы хотите посчитать натуральный логарифм от , где равен . Вы просто не сможете передать это число в функцию , т.к. если сложить и , получится . — настолько маленькое число, что будет отброшено полностью при сложении чисел.

А т.к. в математике часто приходится вычислять при числах, близких к , программисты придумали способ обойти эту проблему: передать в функцию не само число, а только его отличие от .

1 Округление вещественных чисел

Как мы уже разбирали, при присваивании переменной типа вещественного числа оно всегда округляется вниз до целого — его дробная часть просто отбрасывается.

А ведь легко можно представить ситуацию, когда дробное число нужно округлить просто до ближайшего целого или вообще вверх. Что делать в этой ситуации?

Для этого и для многих похожих случаев в Java есть класс , у которого есть методы , , .

Метод

Метод округляет число до ближайшего целого:

Но, как говорится, есть нюанс: результат работы этого метода — целочисленный тип (не ). Вещественные числа ведь могут быть очень большими, поэтому разработчики Java решили использовать самый большой целочисленный тип, который есть в Java — .

Поэтому чтобы присвоить результат в переменную типа , программист должен явно указать компилятору, что он согласен с возможной потерей данных (вдруг число не поместится в тип ).

Примеры:

Команда Результат

Метод

Метод округляет число до целого вверх, примеры:

Команда Результат

Метод

Метод округляет число до целого вниз, примеры:

Команда Результат

Хотя, для округления числа до целого вниз, будет проще использовать просто оператор приведения типа — :

Команда Результат

Если вам сложно запомнить эти команды, вам поможет небольшой урок английского:

  • — математика
  • — круг/округлять
  • — потолок
  • — пол

Java Integer Math

Математические операции, выполняемые с целочисленными типами Java (byte, short, int и long), ведут себя немного иначе, чем обычные математические операции. Поскольку целочисленные типы не могут содержать дроби, в каждом вычислении с одним или несколькими целочисленными типами все дроби в результате обрезаются. Посмотрите на это математическое выражение:

int result = 100 / 8;

Результат этого деления будет 12,5, но так как два числа являются целыми числами, фракция .5 обрезается. Результат, следовательно, всего 12.

Округление также происходит в подрезультатах больших вычислений.

С плавающей точкой Math

Java содержит два типа данных с плавающей точкой: float и double. Они могут содержать дроби в числах. Если нужны дробные выражения в математических выражениях, вы должны использовать один из этих типов данных. Вот пример математического выражения с плавающей точкой:

double result = 100 / 8;

Несмотря на то, что переменная результата теперь имеет тип с плавающей запятой (double), конечный результат по-прежнему равен 12 вместо 12,5. Причина в том, что оба значения в математическом выражении (100 и 8) оба являются целыми числами. Таким образом, результат деления одного на другое сначала преобразуется в целое число (12), а затем присваивается переменной результата.

Чтобы избежать округления вычислений, необходимо убедиться, что все типы данных, включенные в математическое выражение, являются типами с плавающей запятой. Например, вы могли бы сначала присвоить значения переменным с плавающей запятой следующим образом:

double no1 = 100;
double no2 = 8;

double result = no1 / no2;

Теперь переменная результата будет иметь значение 12,5.

В Java есть способ заставить все числа в расчете быть переменными с плавающей точкой. Вы ставите числа с большой буквы F или D. Вот пример:

double result = 100D / 8D;

Обратите внимание на прописные буквы D после каждого числа. Этот верхний регистр D говорит Java, что эти числа должны интерпретироваться как числа с плавающей запятой, и, таким образом, деление должно быть делением с плавающей запятой, которое сохраняет дроби вместо их обрезания

На самом деле вы также можете сделать число длинным, добавив суффикс числа к верхнему регистру L, но long по-прежнему является целочисленным типом, поэтому он не будет сохранять дробные части в вычислениях.

Точность с плавающей точкой

Типы данных с плавающей точкой не являются точными на 100%. Вы можете столкнуться с ситуациями, когда числа со многими дробями не складываются с ожидаемым числом. Если вычисление с плавающей запятой приводит к числу с большим количеством дробей, чем может обработать число с плавающей запятой или двойное число, дроби могут быть обрезаны. Конечно, заданная точность может быть более чем достаточной для многих типов вычислений, но имейте в виду, что дроби могут фактически быть отсечены.

Посмотрите:

double resultDbl3 = 0D;
System.out.println("resultDbl3 = " + resultDbl3);

for(int i=0; i<100; i++){
    resultDbl3 += 0.01D;
}
System.out.println("resultDbl3 = " + resultDbl3);

Вывод выводится при выполнении этого кода с Java 8:

resultDbl3 = 0.0
resultDbl3 = 1.0000000000000007

Первый оператор System.out.println() правильно печатает значение 0.0, которое является начальным значением переменной resultDbl3.

Однако второй оператор System.out.println() выводит несколько странный результат. Добавление значения 0,01 к 0 всего 100 раз должно привести к значению 1,0, верно? Но каким-то образом окончательный результат 1.0000000000000007. Как видите, что-то не так во фракциях.

Обычно неточность с плавающей запятой незначительна, но все же важно знать об этом

Как подключить джойстик к компьютеру Windows 10? Рекомендации по настройке

Округление

Одна из часто используемых операций при работе с числами – это округление.

В JavaScript есть несколько встроенных функций для работы с округлением:

Округление в меньшую сторону: становится , а — .
Округление в большую сторону: становится , а — .
Округление до ближайшего целого: становится , — , а — .
(не поддерживается в Internet Explorer)
Производит удаление дробной части без округления: становится , а — .

Ниже представлена таблица с различиями между функциями округления:

Эти функции охватывают все возможные способы обработки десятичной части. Что если нам надо округлить число до количества цифр в дробной части?

Например, у нас есть и мы хотим округлить число до 2-х знаков после запятой, оставить только .

Есть два пути решения:

Умножить и разделить.
Например, чтобы округлить число до второго знака после запятой, мы можем умножить число на , вызвать функцию округления и разделить обратно.

Метод toFixed(n) округляет число до знаков после запятой и возвращает строковое представление результата.

Округляет значение до ближайшего числа, как в большую, так и в меньшую сторону, аналогично методу :

Обратите внимание, что результатом является строка. Если десятичная часть короче, чем необходима, будут добавлены нули в конец строки:

Мы можем преобразовать полученное значение в число, используя унарный оператор или , пример с унарным оператором: .

4 Минимум и максимум из нескольких чисел

Есть еще одно полезное применение функций и .

Это вычисление минимума (или максимума) из нескольких чисел или переменных. Функции очень удобно вызывать друг в друге.

Вот как можно записать минимум из 3-х чисел:

А что? Очень удобно: вычисляем минимум пары чисел, а затем возвращаем меньшее число из найденного и оставшегося.

Минимум из четырех чисел получается аналогично:

Хотя можно эту формулу записать немного понятнее:

Для функции все аналогично.

Использование оператора или тернарного оператора сделало бы эти записи немного более громоздкими. А использование функций и — просто идеальное решение.

Тригонометрические функции

Класс Java Math содержит набор тригонометрических функций. Эти функции могут вычислять значения, используемые в тригонометрии, такие как синус, косинус, тангенс и т. д.

Mathkpi

Константа Math.PI представляет собой двойное значение, значение которого очень близко к значению PI — математическому определению PI.

Math.sin()

Метод Math.sin() вычисляет значение синуса некоторого значения угла в радианах:

double sin = Math.sin(Math.PI);
System.out.println("sin = " + sin);

Math.cos()

Метод Math.cos() вычисляет значение косинуса некоторого значения угла в радианах:

double cos = Math.cos(Math.PI);
System.out.println("cos = " + cos);

Math.tan()

Метод Math.tan() вычисляет значение тангенса некоторого значения угла в радианах:

double tan = Math.tan(Math.PI);
System.out.println("tan = " + tan);

Math.asin()

Метод Math.asin() вычисляет значение синусоиды значения от 1 до -1:

double asin = Math.asin(1.0);
System.out.println("asin = " + asin);

Math.acos()

Метод Math.acos() вычисляет значение арккосинуса от 1 до -1:

double acos = Math.acos(1.0);
System.out.println("acos = " + acos);

Math.atan()

Метод Math.atan() вычисляет значение арктангенса для значения от 1 до -1:

double atan = Math.atan(1.0);
System.out.println("atan = " + atan);

Вот что говорит JavaDoc:

Если вам нужен этот метод, пожалуйста, прочитайте JavaDoc.

Math.sinh()

Метод Math.sinh() вычисляет значение гиперболического синуса значения между 1 и -1:

double sinh = Math.sinh(1.0);
System.out.println("sinh = " + sinh);

Math.cosh()

Метод Math.cosh() вычисляет значение гиперболического косинуса от 1 до -1:

double cosh = Math.cosh(1.0);
System.out.println("cosh = " + cosh);

Math.tanh()

Метод Math.tanh() вычисляет значение гиперболического тангенса значения от 1 до -1:

double tanh = Math.tanh(1.0);
System.out.println("tanh = " + tanh);

Math.toDegrees()

Метод Math.toDegrees() преобразует угол в радианах в градусы:

double degrees = Math.toDegrees(Math.PI);
System.out.println("degrees = " + degrees);

Math.toRadians()

Метод Math.toRadians() преобразует угол в градусах в радианы:

double radians = Math.toRadians(180);
System.out.println("radians = " + radians);

Неточные вычисления

Внутри JavaScript число представлено в виде 64-битного формата IEEE-754. Для хранения числа используется 64 бита: 52 из них используется для хранения цифр, 11 из них для хранения положения десятичной точки (если число целое, то хранится 0), и один бит отведён на хранение знака.

Если число слишком большое, оно переполнит 64-битное хранилище, JavaScript вернёт бесконечность:

Наиболее часто встречающаяся ошибка при работе с числами в JavaScript – это потеря точности.

Посмотрите на это (неверное!) сравнение:

Да-да, сумма и не равна .

Странно! Что тогда, если не ?

Но почему это происходит?

Число хранится в памяти в бинарной форме, как последовательность бит – единиц и нулей. Но дроби, такие как , , которые выглядят довольно просто в десятичной системе счисления, на самом деле являются бесконечной дробью в двоичной форме.

Другими словами, что такое ? Это единица делённая на десять — , одна десятая. В десятичной системе счисления такие числа легко представимы, по сравнению с одной третьей: , которая становится бесконечной дробью .

Деление на гарантированно хорошо работает в десятичной системе, но деление на – нет. По той же причине и в двоичной системе счисления, деление на обязательно сработает, а становится бесконечной дробью.

В JavaScript нет возможности для хранения точных значений 0.1 или 0.2, используя двоичную систему, точно также, как нет возможности хранить одну третью в десятичной системе счисления.

Числовой формат IEEE-754 решает эту проблему путём округления до ближайшего возможного числа. Правила округления обычно не позволяют нам увидеть эту «крошечную потерю точности», но она существует.

Пример:

И когда мы суммируем 2 числа, их «неточности» тоже суммируются.

Вот почему – это не совсем .

Не только в JavaScript

Справедливости ради заметим, что ошибка в точности вычислений для чисел с плавающей точкой сохраняется в любом другом языке, где используется формат IEEE 754, включая PHP, Java, C, Perl, Ruby.

Можно ли обойти проблему? Конечно, наиболее надёжный способ — это округлить результат используя метод toFixed(n):

Также можно временно умножить число на 100 (или на большее), чтобы привести его к целому, выполнить математические действия, а после разделить обратно. Суммируя целые числа, мы уменьшаем погрешность, но она все равно появляется при финальном делении:

Таким образом, метод умножения/деления уменьшает погрешность, но полностью её не решает.

Забавный пример

Попробуйте выполнить его:

Причина та же – потеря точности. Из 64 бит, отведённых на число, сами цифры числа занимают до 52 бит, остальные 11 бит хранят позицию десятичной точки и один бит – знак. Так что если 52 бит не хватает на цифры, то при записи пропадут младшие разряды.

Интерпретатор не выдаст ошибку, но в результате получится «не совсем то число», что мы и видим в примере выше. Как говорится: «как смог, так записал».

Два нуля

Другим забавным следствием внутреннего представления чисел является наличие двух нулей: и .

Все потому, что знак представлен отдельным битом, так что, любое число может быть положительным и отрицательным, включая нуль.

В большинстве случаев это поведение незаметно, так как операторы в JavaScript воспринимают их одинаковыми.

Java Math.round Syntax

The basic syntax of the round Function in Java Programming language is as shown below.

Number: It can be a number or a valid numerical expression.

  • If the number argument is a positive or negative number, the Math.round function will return the nearest value.
  • If the number argument is not a number, the Java Math.round function will return Zero.

Java Programming provides two different functions to round the specified value. The following Java math.round function will accept positive or negative float value as an argument and returns the closest mathematical integer value of type Int.

The following Java round double function will accept the positive or negative double value and returns the closest math integer value of type long.

Где делать округление: размышления о точности

Теперь, когда есть возможность управлять округлением расчёта, до какого знака следует округлять? Ответ зависит от того, как планируется использовать полученное число.

Вам известна требуемая точность конечного результата из потребностей пользователей. Для чисел, которые будут складываться и вычитаться для получения конечного результата, необходимо добавить ещё один десятичный разряд, так что сумма 0.0144 + 0.0143 будет округлена до 0.03, в то время как если округление выполняется до 0.01, результатом будет 0.02.

Если необходимы числа, которые будут умножаться для получения конечного результата, необходимо сохранять столько знаков после запятой, сколько возможно. Например, коэффициенты и удельные затраты не должны округляться. После умножения необходимо округлять конечный результат.

Overview

In this short article, we’re going to look at how to round a number to n decimal places in Java.

2. Decimal Numbers in Java

Java provides two primitive types that can be used for storing decimal numbers: float and double. Double is the type used by default:

However, both types should never be used for precise values, such as currencies. For that, and also for rounding, we can use the BigDecimal class.

3. Formatting a Decimal Number

If we just want to print a decimal number with n digits after decimal point, we can simply format the output String:

Alternatively, we can format the value with the DecimalFormat class:

DecimalFormat allows us to explicitly set rounding behavior, giving more control of the output than String.format() used above.

4. Rounding Doubles With BigDecimal

To round doubles to n decimal places, we can write a helper method:

There is one important thing to notice in this solution – when constructing BigDecimal; we must always use BigDecimal(String) constructor. This prevents issues with representing inexact values.

We can achieve the same by using the Apache Commons Math library:

The latest version can be found .

Once the library is added to the project, we can use the Precision.round() method, which takes two arguments – value and scale:

By default, it is using the same HALF_UP rounding method as our helper method. Therefore, the results should be the same.

Note that we can change rounding behavior by passing the desired rounding method as a third parameter.

5. Rounding Doubles With DoubleRounder

DoubleRounder is a utility in the decimal4j library. It provides a fast and garbage-free method for rounding doubles from 0 to 18 decimal points.

We can get the library (the latest version can be found ) by adding the dependency to the pom.xml:

Now, we can simply use:

However, DoubleRounder fails in a few scenarios, for example:

6. Math.round() Method

Another way of rounding numbers is to use Math.Round() Method.

In this case, we can control n number of decimal places by multiplying and dividing by 10^n:

This method is not recommended as it’s truncating the value. In many cases values are rounded incorrectly:

And so, this method is listed here for learning purposes only.

7. Conclusion

In this quick tutorial, we covered different techniques for rounding numbers to n decimal places.

We can simply format the output without changing the value, or we can round the variable by using a helper method. We’ve also covered a few libraries that deal with this problem.

The code used during the discussion can be found over on GitHub.

Способы записи числа

Представьте, что нам надо записать число 1 миллиард. Самый очевидный путь:

Но в реальной жизни мы обычно опускаем запись множества нулей, так как можно легко ошибиться. Укороченная запись может выглядеть как или для 7 миллиардов 300 миллионов. Такой принцип работает для всех больших чисел.

В JavaScript можно использовать букву , чтобы укоротить запись числа. Она добавляется к числу и заменяет указанное количество нулей:

Другими словами, производит операцию умножения числа на 1 с указанным количеством нулей.

Сейчас давайте запишем что-нибудь очень маленькое. К примеру, 1 микросекунду (одна миллионная секунды):

Записать микросекунду в укороченном виде нам поможет .

Если мы подсчитаем количество нулей , их будет 6. Естественно, верная запись .

Другими словами, отрицательное число после подразумевает деление на 1 с указанным количеством нулей:

Шестнадцатеричные числа широко используются в JavaScript для представления цветов, кодировки символов и многого другого. Естественно, есть короткий стиль записи: , после которого указывается число.

Например:

Не так часто используются двоичные и восьмеричные числа, но они также поддерживаются для двоичных и для восьмеричных:

Есть только 3 системы счисления с такой поддержкой. Для других систем счисления мы рекомендуем использовать функцию (рассмотрим позже в этой главе).

Заключение

В этой статье я рассказывал в основном об округлении к меньшему по модулю, но есть . В некоторых случаях подходят именно они, и я оставлю читателю возможность изучить их и попробовать реализовать на Go. Но я надеюсь, что теперь вам стало понятно, как устроено округление в Go и как нужно тестировать реализации округления.

Думаю, команда Go приняла правильное решение, добавив функцию Round() в стандартную библиотеку. Без этого мы бы продолжали пользоваться различными некорректными реализациями.

Надеюсь, теперь вам стало ясно, что при работе с float есть много подводных камней, про которые порой забывают даже эксперты. Легко придумать или скопировать откуда-то однострочную реализацию, но сложно написать действительно корректную. Неудивительно, что корректно работающее округление появилось лишь в шестой мажорной версии Java (через 15 лет, прошедших с релиза Java 1.0 до выхода Java 7), и я рад, что Go прошёл этот путь быстрее.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector