Методология Math.Round, начиная с наименьшего десятичного знака

Было создано много тем из-за путаницы в том, как работает Math.Round. По большей части на них отвечают, намекая людям на параметр MidpointRounding и на то, что большинство людей ожидают MidpointRounding.AwayFromZero. У меня есть еще один вопрос о фактическом алгоритме, реализованном AwayFromZero.

Дано следующее число (результат ряда вычислений): 13.398749999999999999999999999M

наши пользователи ожидают увидеть тот же результат, который Excel дал бы им 13.39875. Поскольку в настоящее время они округляют это число до 4 с помощью Math.Round(num, 4, MidpointRounding.AwayFromZero), результат отличается от ожидаемого на 0,0001. Предположительно, причина этого в том, что алгоритм просто смотрит на пятую цифру (4), а затем соответственно округляет. Если бы вы начали округлять с последних 9, реальный математический ответ фактически дал бы вам то же число, что и Excel.

Итак, вопрос... есть ли способ подражать этому поведению, а не текущему?

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

    private decimal Round(decimal num, int precision)
    {
        return Round(num, precision, 28);
    }

    private decimal Round(decimal num, int precision, int fullPrecision)
    {
        if (precision >= fullPrecision) return Math.Round(num, precision);

        return Round(Math.Round(num, fullPrecision), precision, --fullPrecision);
    }

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

В этом случае кажется, что любая другая система, используемая для создания этих средних цен (которые мы должны сопоставить), использует другой уровень точности (10 в базе данных, а Excel по умолчанию имеет значение 15 или что-то в этом роде). Учитывая, что у всех разный уровень точности, я застрял в середине с вопросом о переходе к более низкой точности, каких-то странных правилах округления (как описано выше) или просто о получении результатов, отличных от ожиданий пользователей.


person Joel Martinez    schedule 27.08.2010    source источник
comment
Я не согласен с утверждением, что реальный математический ответ на самом деле даст вам то же число, что и Excel. Математическое округление специально определено и не начинается с младшего разряда. Округление 13,39874999 до 6 значащих цифр на самом деле математически дает 13,3987.   -  person Stephen Cleary    schedule 27.08.2010
comment
@ Стивен, если я правильно его понял, он имеет в виду, что хочет выполнить настоящую математику, которая приводит к тому же результату, что и ошибочный подход, чтобы быть совместимым с ошибками.   -  person Jon Hanna    schedule 27.08.2010
comment
@Джон: Согласен. Я просто хотел исправить впечатление, что двойное округление является математически правильным и, следовательно, ожидаемым поведением.   -  person Stephen Cleary    schedule 27.08.2010
comment
@Стефан, правда. Достаточно сложно объяснить, что выбор, отличный от округления в начальной школе (предоставленный AwayFromZero), не является неправильным, не размывая его еще больше. Я думаю, что кверант это понимает, но мы всегда должны думать и о человеке, который заходит в поиск Google.   -  person Jon Hanna    schedule 30.08.2010
comment
Эти комментарии определенно должным образом отмечены :-) Я добавил немного больше фона в качестве редактирования к посту выше. Было бы здорово получить дополнительные мысли в свете новой информации, если она изменит ваши ответы.   -  person Joel Martinez    schedule 30.08.2010
comment
@ Джоэл Мартинес: я не уверен, о чем вы спрашиваете. Ваш пример Excel рассчитан на 5 мест, так почему ваши пользователи ожидают одного и того же ответа на 4 места?   -  person Rick Regan    schedule 06.09.2010
comment
@Rick Regan, это неокругленный результат ... они используют его в качестве основы для своего отчета об ошибке.   -  person Joel Martinez    schedule 07.09.2010
comment
@Joel Martinez: Но это не округление - оно округляется Excel.   -  person Rick Regan    schedule 07.09.2010


Ответы (2)


Если я вас правильно понимаю, люди ожидают 13,3988, потому что они сначала округляют до 13,39875, а затем до 13,3988, и им нужно, чтобы вы были совместимы с ошибками.

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

private static decimal InaccurateRound(decimal num, int precision)
{
  return Math.Round(
    Math.Round(num, precision + 1, MidpointRounding.AwayFromZero),
    precision, MidpointRounding.AwayFromZero);
}
person Jon Hanna    schedule 27.08.2010
comment
Двойное округление не является конечной остановкой. Есть соответствующие примеры для любого количества повторений. Например, 0,4444444449 будет округлено до 1, только если вы примените округление AwayFromZero 10 раз к каждой позиции справа налево. - person jmster; 13.09.2016

Итак, если вы округлите это число до 5 знаков, а затем округлите результат до 4 знаков... Вы получите другой результат, чем если бы вы просто округлили исходное число до 4 знаков? Это ожидаемо. И я думаю, это объясняет, что вам нужно делать. другой вариант - заставить Excel показывать полную точность, чтобы «они» округлялись так же, как ваш код. Округление дважды просто кажется неправильным.

person phkahler    schedule 27.08.2010