поведение bizzare обнуляемая десятичная точность - PullRequest
1 голос
/ 06 апреля 2011

У меня есть несколько столбцов в хранилище данных с точностью до десятичного знака.

Я хочу округлить его до 4 мест с целью отправки его с помощью текстового канала, и потребителям этого канала нужна точность x.

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

if (obj.myValue.HasValue)
    obj.myValue = System.Math.Round(obj.MyValue.Value, 4)

Приведенный выше пример работает при округлении, но в SOME случаях не удаляются завершающие 0. Конечный результат автоматически генерируется с использованием obj.myValue.ToString () (и т. Д. Для всех полей)

Похоже, что это происходит только с десятичными полями, которые можно обнулять.

Я не уверен, что отличается, но примерно в 10% строк вывод сохраняет конечные 0. Фактическое значение округляется, но 0 остаются:

134.402100000000

Я также пытался сделать это таким образом (просто чтобы убедиться и убрать начальную точность десятичного числа)

if (obj.myValue.HasValue)
    obj.myValue = decimal.Parse(obj.MyValue.Value.ToString("#.####"))

снова, некоторые строки остаются с добавленными конечными 0.

Похоже, что свойство инициализируется в x десятичных разрядах, а финальная ToString.

Учитывая, что у меня нет прямого доступа к этому коду, но я могу внедрить любой c # для выполнения с этим свойством, есть ли другие вещи, которые я мог бы попробовать? (Я также пытался жестко кодировать все строки в значение, и это прекрасно работает без лишних 0)

также интересно, что я не могу воспроизвести это поведение в моих тестах ..

        decimal d1 = 160236194.3900000000000001M;
        Console.WriteLine(d1);
        d1 = Math.Round(d1, 4);
        Console.WriteLine(d1);

160236194.3900000000000001
160236194.3900
Press any key to continue . . .

редактировать

попробовал другой подход благодаря e.James (тестирование, чтобы увидеть, удалит ли truncate 0)

if (obj.myValue.HasValue)
    obj.myValue = decimal.Truncate(obj.MyValue.Value)

и .. усечение работает на всех строках, но 0 все равно остаются на тех, которые имели ранее! Разница в том, что на этот раз это всего 0 с .. до обрезания было .8900000000 и т. Д. Это дико!

Ответы [ 2 ]

3 голосов
/ 06 апреля 2011

Некоторые десятичные числа не могут быть идеально представлены в двоичном формате. Ваше свойство obj.myValue является десятичным числом. Для некоторых десятичных разрядов он просто не сможет хранить что-либо, кроме (например) 1234.4021000000000001, которое максимально близко к ограниченному числу битов.

Я думаю, что Доменик имеет правильную идею со своим ответом. Пусть десятичные числа остаются в памяти не округленными, а только отображают * их округленные.

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

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

2 голосов
/ 06 апреля 2011

Почему бы не позволить логике дисплея обрабатывать логику дисплея? То есть, только когда вы переходите к отображению decimal как string, вы должны заботиться о количестве отображаемых трейлингов 0, и в этом случае вы должны использовать theDecimal.ToString("#.####").

...