2009-12-04 3 views
4

У меня есть следующий код теста:десятичных удвоить

decimal test1 = 0.0500000000000000045656554454M; 
double test2 = (double)test1; 

Это приводит к test2, показывая, как 0,05 при отладке. Почему он округляется до 2 знаков после запятой?

Благодаря

ответ

8

Величина этой конверсии фактически равна 0.050000000000000009714451465470119728706777095794677734375, как показано DoubleConverter. Это точное значение ближайшего двойника до десятичной величины, которую вы преобразовали.

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

+0

+1: вот почему я получил 0.05000000000000001 в своем отладчике. – Peter

+0

ОК, но почему это значение тогда отображается как 0,05 при сериализации? Спасибо –

+0

Хороший вопрос: «вам обычно не показывают точный результат» -> почему бы и нет? Для форматирования вывода, нормально, я думаю, но в отладчике это может пригодиться, как показывает этот вопрос. – Peter

4

Причина заключается в том, что двойное может содержать не более 15-16 значащих цифр.

см double (C# Reference)

+0

+1 для ссылки на C#. Я думаю, что это 15-16 цифр в худшем случае, но в некоторых случаях это может быть лучше, чем это (в зависимости от того, может ли это быть фактически представлено двойным ...) – Anna

+0

+1, добавочное примечание: C# использует IEEE-754 для данных с плавающей точкой с одинарной и двойной точностью. – user7116

+0

Этот ответ неверен: причина в том, что ваш отладчик просто не отображает 0.05000000000000000971445146547011972870677709579467773437, как указал Джон. Однако 15/16 значительных цифр все еще правильные, но есть разница между числами цифр и цифрами значимых цифр. – Peter

1

Есть две причины, я могу думать:

  1. Из-за различного представления десятичной и двойной. См. Статью this для получения дополнительной информации о представлении с плавающей запятой. Вполне возможно, что для всего числа в двоичном разряде недостаточно битов.
  2. Из-за того, как печатаются номера. Возможно, что в ваших параметрах печати после десятичной точки будет меньше 18 чисел, и в этом случае вы получите округленный результат.

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

.. Но знает, что единственное решение первой задачи прекратить использование двойной :-)

3

Вы должны смотреть на this article о арифметике с плавающей точкой и .NET. Округление происходит из-за сочетания того, как число преобразуется в значение с плавающей запятой с двойной точностью и как оно отформатировано при печати, так как по умолчанию по умолчанию значение по умолчанию равно 15 десятичным знакам для удвоения, а ваш исходный номер содержит десятичное значение после 15-го числа.

Вы можете попробовать test2.ToString("0.000000000000000000000000"), чтобы узнать, сможете ли вы высвободить из номера больше информации, но я сомневаюсь, что так будет.