Подтвердить что ты не робот

Нужна помощь округления до 2 знаков после запятой

Почему это происходит, когда я делаю следующее...

Math.Round(0.75, 1, MidpointRounding.AwayFromZero)

Я получаю 0,8

но когда я делаю следующее...

Math.Round(0.575, 2, MidpointRounding.AwayFromZero)

Я не получаю 0.58. Вместо этого я получаю 0.57. Я хочу, чтобы все было 5 и выше, поэтому 0.575 должно быть 0.58.

4b9b3361

Ответ 1

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

Если вы хотите избежать этой проблемы, используйте более подходящий тип данных. decimal сделает то, что вы хотите:

Math.Round(0.575M, 2, MidpointRounding.AwayFromZero)

Результат: 0.58

Причина, по которой 0,75 делает то, что ее легко представить в двоичной плавающей точке, так как она проста 1/2 + 1/4 (т.е. 2 ^ -1 + 2 ^ -2). В общем случае любая конечная сумма степеней двух может быть представлена ​​в двоичной плавающей точке. Исключения составляют, когда ваши полномочия 2 слишком сильно изменяют диапазон (например, 2 ^ 100 + 2 не является точно представимым).

Изменить для добавления:

Форматирование удваивается для вывода на С# может представлять интерес с точки зрения понимания, почему его так трудно понять, что 0.575 не действительно 0.575. DoubleConverter в принятом ответе покажет, что 0.575 как точная строка 0.5749999999999999555910790149937383830547332763671875 Вы можете видеть из этого, почему округление дает 0.57.

Ответ 2

Метод System.Math.Round использует структуру Double, которая, как указывали другие, подвержена ошибкам точности с плавающей запятой. Простое решение, которое я нашел для этой проблемы, когда я столкнулся с ней, заключался в использовании метода System.Decimal.Round, который не страдает от одной и той же проблемы и не требует повторного изменения ваших переменных как десятичных знаков:

Decimal.Round(0.575, 2, MidpointRounding.AwayFromZero)

Результат: 0.58

Ответ 3

Это вызвано отсутствием точности с удвоениями/десятичными знаками (т.е. функция не всегда даст ожидаемый результат).

См. следующую ссылку: MSDN на Math.Round

Вот соответствующая цитата:

Из-за потери точности, которая может возникнуть в результате представления десятичных значений в виде чисел с плавающей запятой или выполнения арифметических операций с значениями с плавающей запятой, в некоторых случаях метод Round (Double, Int32, MidpointRounding) может не отображаться вокруг середины значения, указанные параметром режима. Это проиллюстрировано в следующем примере, где 2.135 округляется до 2.13 вместо 2.14.Это происходит потому, что внутри метод умножает значение на 10digits, а операция умножения в этом случае страдает от потери точности.