Как округлить число в с
Перейти к содержимому

Как округлить число в с

  • автор:

Учимся округлять в C#

А знаете ли вы, что Math.Round(1.5) == Math.Round(2.5) == 2 ? Можете ли сходу сказать, сколько будет -7%3 и 7%-3 ? Помните ли, чем отличаются Math.Round , Math.Floor , Math.Ceiling , Math.Truncate ? А как происходит округление при использовании string.Format ? Давайте немного погрузимся в мир округлений и разберёмся с нюансами, которые не для всех могут быть очевидными.

Math.Round

 Math.Round — это метод округления к ближайшему числу или к ближайшему числу с заданным количеством знаков после запятой. Работает с типами decimal и double , в параметрах можно встретить три вида параметров:
  • value : округляемое число
  • digits : количество знаков в дробной части, которые нужно оставить
  • mode : параметр, который определяет в какую сторону округлять число, которое находится ровно посередине между двумя вариантами

Параметр mode используется, когда округляемое значение находится ровно посередине между двумя вариантами. Принимает значение из следующего перечисления:

Обратите внимание, что по умолчанию mode == MidpointRounding.ToEven , поэтому Math.Round(1.5) == Math.Round(2.5) == 2 .

Math.Floor, Math.Ceiling, Math.Truncate

Сводная таблица

Сориентироваться в методах округления может помочь следующая табличка:

Округление проводится в соответствии со стандартом IEEE Standard 754, section 4.

Целочисленное деление и взятие по модулю

В C# есть два замечательных оператора над целыми числами: / для целочисленного деления (MSDN) и % для взятия остатка от деления (MSDN). Деление производится по следующим правилам:

  • При целочисленном делении результат всегда округляется по направлению к нулю.
  • При взятии остатка от деления должно выполняться следующее правило: x % y = x – (x / y) * y

Также можно пользоваться шпаргалкой:

string.Format

При форматировании чисел в виде строки можно пользоваться функцией string.Format (см. Standard Numeric Format Strings, Custom Numeric Format Strings). Например, для вывода числа с двумя знаками после десятичной точки можно воспользоваться string.Format(«», value) или string.Format(«», value) . Округление происходит по принципу AwayFromZero . Проиллюстрируем правила округления очередной табличкой:

", value) |       

Задачи

На приведённую тему есть две задачки в ProblemBook.NET: Rounding1, Rounding2.

  • GitHub
  • Twitter
  • RSS

Как округлить число

введите сюда описание изображения

Как округлить 2 элемент массива до вида 3 элемента массива.

Отслеживать
8,552 4 4 золотых знака 29 29 серебряных знаков 53 53 бронзовых знака
задан 14 мар 2016 в 5:18
953 2 2 золотых знака 10 10 серебряных знаков 27 27 бронзовых знаков
Если вам дан исчерпывающий ответ, отметьте его как верный (галка напротив выбранного ответа).
17 мар 2016 в 6:14

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Они и так находятся в одном и том же виде. Просто у третьего элемента в конце нули, поэтому они не отображаются.

А так округлять можно с помощью метода Round класса Math :

Math.Round(double value, int digits); 
  • value — число, которое нужно округлить.
  • digits — количество цифр в дробной части, которые нужно оставить.

Про перегрузку Math.Round(value) и про методы Math.Floor(value) , Math.Ceiling(value) и Math.Truncate(value) ничего говорить не буду, т.к. они Вам не подходят, все они округляют до целого.

Если Вам нужно округление для красивого вывода, то лучше использовать строку стандартных числовых форматов с описателем N или F, которые выводят число в нормальной записи (с плавающей точкой) с указанием точности:

double value = -123.45678; string strA = value.ToString("N"); // "-123.46" В зависимости от NumberDecimalDigits (см. ниже) string strB = value.ToString("N2"); // "-123.46" string strC = value.ToString("N10"); // "-123.4567800000" 

Число, стоящее после N, указывает на точность. Число называется описателем точности. Если числа нет, то число знаков после запятой определяется значением NumberFormatInfo.NumberDecimalDigits :

 Console.WriteLine(System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalDigits); // У меня выводится 2 

У меня NumberDecimalDigits = 2. Поэтому в предыдущем коде strA = «-123.46» .

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

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

Покажу на предыдущем примере. Если использовать 0:

double value = -123.45678; string strA = value.ToString("0"); // "-123" string strB = value.ToString("0.00"); // "-123.46" string strC = value.ToString("0.0000000000"); // "-123.4567800000" 

Если использовать #:

double value = -123.45678; string strA = value.ToString("0"); // "-123" string strB = value.ToString("0.##"); // "-123.46" string strC = value.ToString("0.##########"); // "-123.45678" 

Округление чисел, онлайн калькулятор

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

Математические калькуляторы

Найти значение выражения

Калькулятор десятичных дробей

Извлечь корень 2, 3, 4, 5, n степени онлайн

Двоичный калькулятор онлайн

Математика 4,5,6,7,8,9,10,11 класс, ЕГЭ, ГИА

Мы в соцсетях Присоединяйтесь!
Нашли ошибку? Есть предложения? Сообщите нам
Этот калькулятор можно вставить на сайт, в блог

Код для вставки без рекламы с прямой ссылкой на сайт

Код для вставки с рекламой без прямой ссылки на сайт

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

Округление к целому в .NET

Все мы знаем, что такое округление. Если кто-то забыл, то округление — это замена числа на его приближённое значение, записанное с меньшим количеством значащих цифр. Если спросить человека с ходу, что получится при округлении 6,5 до целых, он не задумываясь ответит «7». Нас со школы учили, что числа округляются до ближайшего целого большего по модулю числа. То есть, если в округляемом числе дробная часть равна или больше половине разряда целой части, то мы округляем исходное число до ближайшего большего.

6,4 = 6 6,5 = 7 6,6 = 7

И вот, выходя из школы и становясь программистами мы зачастую ожидаем того же поведения от наших мощных языков программирования. Совсем забывая, что в школе нас учили «математическому округлению», а на самом деле видов этих округлений намного больше. На одной только википедии можно нарыть вот сколько вариантов округления 0,5 к ближайшему целому числу:

  • Математическое округление
  • Случайное округление
  • Чередующееся округление
  • Банковское округление

А вот «банковское округление» — это уже интересненько. «Почему?» — спросите вы. В дотнете мы часто используем класс Convert, который предоставляет уйму методов для конвертации одного типа данных в другие (не путать с приведением, о нем будет ниже). И вот, оказывается, что при конвертации чисел с плавающей запятой (double, float, decimal) в целочисленный тип int через метод Convert.ToInt32 под капотом работает «банковское» округление. Оно тут используется по умолчанию!

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

Первая мысль программиста, который это видит — «Возможно округление работает в обратную сторону, и по правилам округляется до наименьшего числа?», «Может я что-то забыл из школьной математики?». Дальше он идет в google и понимает что, ничего не забыли, и что творится какая-то чернь. На этом шаге ленивый разработчик решит, что это стандартное поведение метода Convert.ToInt32, округлять до наименьшего целого, и забьет на дальнейший поиск. И будет думать, что если Convert.ToInt32(6,5) = 6, то по аналогии Convert.ToInt32(7,5) = 7. Но не тут-то было. Таких разработчиков в дальнейшем судьба бьет по голове пачкой багов от отдела QA.

Дело в том, что «банковское» округление работает чуть хитрее — оно округляет число до ближайшего четного целого числа, а не до ближайшего целого по модулю. Этот тип округления якобы более честный в случае применения в банковских операциях — банки не будут обделять ни себя ни клиентов, из расчета, что операций с четной целой частью, сколько же, сколько и операций с нечетной целой частью. Но как по мне — всё равно мутновато 🙂 Так вот, именно поэтому Convert.ToInt32(6,5) даст результат 6, а результат для Convert.ToInt32(7,5) будет равен 8, а не 7 🙂

Что же делать, что бы получить всем привычное «математическое» округления? У методов класса Convert нет дополнительных настроек округления. Оно и верно, ибо класс этот служит в первую очередь не для округления, а для конвертации типов. На помощь нам приходит замечательный класс Math с его методом Round. Но тут тоже будьте аккуратны, ибо по умолчанию этот метод работает так же как и округление в Convert.ToInt32() — по «банковскому» правилу. Однако, это поведение можно изменять с помощью второго аргумента, входящего в метод Round. Так, Math.Round(someNumber, MidpointRounding.ToEven) даст нам дефолтовое «банковское» округление. А вот Math.Round(someNumber, MidpointRounding.AwayFromZero) будет работать по привычным правилам «математического» округления.

И кстати, Convert.ToInt32() не использует под капотом System.Math.Round(). Специально нарыл на github реализацию этого метода — округление считается по остаткам:

public static int ToInt32(double value) < if (value >= 0) < if (value < 2147483647.5) < int result = (int)value; double dif = value - result; if (dif >0.5 || dif == 0.5 && (result & 1) != 0) result++; return result; > > else < if (value >= -2147483648.5) < int result = (int)value; double dif = value - result; if (dif < -0.5 || dif == -0.5 && (result & 1) != 0) result--; return result; >> throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); > 

И напоследок пару слов о приведении типов:

var number = 6.9; var intNumber = (int)number; 

В этом примере я привожу тип с плавающей запятой (double в данном случае) к целочисленному int. Так вот, при приведении типов к целочисленному вся не целая часть просто отсекается. Соответственно, в данном примере в переменной «intNumber» будет лежать число 6. Никаких правил округления тут нет, просто отсечение всего, что идет после запятой. Помните об этом!

  • Про округление на wikipedia
  • Про проблему конвертации
  • Про округление Math.Round
  • Реализация Convert.ToInt32

P.P.S. Кстати, в python округление по дефолту работает так же по «банковскому» принципу. Возможно, в вашем языке такая же штука, будьте бдительны с числами 🙂

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

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