Округление десятичных значений в C#



Тип данных decimal используется для хранения чисел с высоким уровнем точности. Потенциально большое количество знаков после запятой полезно для многих математических или статистических расчетов. Тем не менее, иногда необходимо и округлять эти значения. Эта проблема не так часто волнует разработчиков, пишущих программы на заказ, но для студентов или самостоятельно изучающих язык C# статья ниже может оказаться весьма полезной.

Округление значения

C# предоставляет три собственные числовые типы данных для хранения значений с плавающей запятой. К ним относятся одинарной точности, двойной точности и десятичные числа, которые объявляются с помощью "float", "double" и "decimal" ключевых слов соответственно. Каждый из этих типов имеет различный диапазон возможных значений с различной степенью точности. Тип " float " является наименее точным с наименьшим диапазоном значений. Тип «decimal» имеет самый большой диапазон и наибольшую точность. Выбор типа значения для использования в любых целях является компромиссом между требованиями размера и точности чисел и объемом памяти, используемой объявленной переменной.

В этой статье мы будем работать с типом данных decimal, но акцентируем внимание не на его размере и точности, а на дополнительной функциональности, присущей этому типу в отличие от двух других вариантов. В частности, мы будем использовать четыре статических метода округления, которые доступны только для десятичных значений. Конечно, это можно использовать и для одно- и двойной чисел точности тоже. Однако в этих случаях необходимо сначала привести к или преобразовать значение в decimal или использовать члены класса Math.

Обратите внимание: Методы, описанные в этой статье, требуют .NET Framework версии 2.0 или более поздней версии. Некоторые из функций доступны в .NET 1.1, но там использование может быть ограничено.

Truncate

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

decimal pr;
pr = decimal.Truncate(1.1M);    // pr = 1
pr = decimal.Truncate(1.8M);    // pr = 1
pr = decimal.Truncate(1M);      // pr = 1
pr = decimal.Truncate(-1.1M);   // pr = -1
pr = decimal.Truncate(-1.8M);   // pr = -1
Floor и Ceiling

Статические методы Floor и Ceiling выполняют аналогичные функции усечения: они удаляют дробную часть числа и возвращают целое число. Опять же целое число возвращается в десятичной структуре. Основное различие между этими методами и Truncate является то, что направление округления фиксируется как для положительных и отрицательных чисел. Для функции Floor округление всегда вниз, а Ceilin всегда вверх, как можно видеть в результатах примере кода ниже.

decimal res;
res = decimal.Floor(1.1M);       // res = 1
res = decimal.Floor(1.8M);       // res = 1
res = decimal.Floor(1M);         // res = 1
res = decimal.Floor(-1.1M);      // res = -2
res = decimal.Floor(-1.8M);      // res = -2
 
res = decimal.Ceiling(1.1M);     // res = 2
res = decimal.Ceiling(1.8M);     // res = 2
res = decimal.Ceiling(1M);       // res = 1
res = decimal.Ceiling(-1.1M);    // res = -1
res = decimal.Ceiling(-1.8M);    // res = -1
Контролируемые округления

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

В заключительной части этой статьи мы рассмотрим метод Round более подробно.

Простое округление

Самый простой способ, которым можно использовать метод Round, это с одним параметром, содержащим число, которое надо изменить. При использовании таким образом возвращаемое значение содержит целое число, которое ближе всего к переданному значению.

decimal res;
res = decimal.Round(1.1M);       // res = 1
res = decimal.Round(1.8M);       // res = 2
res = decimal.Round(1M);         // res = 1
При округлении значения, точно на полпути между двумя целыми числами, метод обеспечивает то, что может показаться странным результатом. Попробуйте выполнить следующие две строки кода. Вы увидите, что в одном случае значение округляется вверх и в других вниз.

result = decimal.Round(1.5M);       // result = 2
result = decimal.Round(2.5M);       // result = 2
Можно было бы ожидать, что оба значения округляются в сторону увеличения и метод возвратит 2 и 3 соответственно. Однако, по умолчанию, этот метод использует правило средней точки (медианы), которое гласит, что когда значение округляется ровно на полпути между двумя целыми числами, всегда выбирается ближайшее значение.

Правила медианы

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

Чтобы задать правило, параметр MidpointRounding добавляется к вызову метода.

decimal res;
res = decimal.Round(1.5M, MidpointRounding.ToEven);          // res = 2
res = decimal.Round(2.5M, MidpointRounding.ToEven);          // res = 2
res = decimal.Round(1.5M, MidpointRounding.AwayFromZero);    // res = 2
res = decimal.Round(2.5M, MidpointRounding.AwayFromZero);    // res = 3
res = decimal.Round(-2.5M, MidpointRounding.AwayFromZero);   // res = -3
Округление до указанного количества десятичных знаков

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

decimal res;
res = decimal.Round(1.2345M, 1); // res = 1.2
res = decimal.Round(1.2345M, 2); // res = 1.23
res = decimal.Round(1.2345M, 3); // res = 1.234
Здесь правило медианы по умолчанию "ToEven" применяется для округления, за исключением того, что конченая цифра округляется до ближайшего четного числа.

res= decimal.Round(1.25M, 1);   // res= 1.2
res = decimal.Round(1.35M, 1);   // res = 1.4
Вы можете изменить правило медианы, используется при округлении до количества знаков после запятой. Чтобы сделать это, просто добавьте значение MidpointRounding в качестве третьего параметра:

res = decimal.Round(1.25M, 1, MidpointRounding.AwayFromZero);  // res = 1.3
res = decimal.Round(1.35M, 1, MidpointRounding.AwayFromZero);  // res = 1.4
Примечание из msdn.microsoft.com к Math.Round

Из-за потери точности, которая может быть результатом представления десятичных значений как чисел с плавающей точкой и выполнения арифметических операций с плавающей запятой, в некоторых случаях в Round(Double, Int32) может отсутствовать округление среднего значения до ближайшего четного значения цифр десятичной позиции. Это показано в следующем примере, где 2.135 округляется до 2,13 вместо 2.14. Это происходит потому, что внутренний метод умножает значение на 10 разрядов, и операция умножения в этом случае страдает от потери точности.
Console.WriteLine( “2.135 -->” + Math.Round(2.135, 2); // 2.135 --> 2.13
Таким образом, в статье мы попробовали немного прояснить ситуацию с округлением decimal. Как видим, все не так уж и сложно, но есть нюансы, которые необходимо иметь в виду при написании программ. Кстати, программы на заказ пишу и я. Недорого, быстро и с гарантией.
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, си шарп, округление, decimal




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




Базовый регулятор громкости C#
Нахождение строки с наибольшим числом символов
Лабиринты Java, часть 4: класс AStarPathfinder