Ответ 1
TL; DR
Оба десятичных знака точно представляют 0,1. Просто формат decimal
, точно такой же, как плавающая точка IEEE, допускает несколько поразрядных значений, которые представляют точно такое же число.
Объяснение
Это не значит, что single
не может точно представлять 0,1. Согласно документации GetBits
:
Двоичное представление числа
decimal
состоит из 1-битного знака, 96-битного целочисленного числа и коэффициента масштабирования, используемого для разделения целочисленное число и укажите, какая часть его является десятичной дробью. Масштабный коэффициент неявно равен числу 10, поднятому до показателя от 0 до 28.Возвращаемое значение представляет собой четырехэлементный массив из 32-разрядных целых чисел.
Первый, второй и третий элементы возвращаемого массива содержат низкий, средний и высокий 32 бит 96-битного целочисленного числа.
Четвертый элемент возвращаемого массива содержит масштабный коэффициент и знак. Он состоит из следующих частей:
Биты от 0 до 15, нижнее слово, не используются и должны быть равны нулю.
Биты с 16 по 23 должны содержать показатель между 0 и 28, который указывает мощность 10 для деления целочисленного числа.
Биты с 24 по 30 не используются и должны быть равны нулю.
Бит 31 содержит знак: 0 означает положительный, а 1 означает отрицательный.
Обратите внимание, что представление битов различает отрицательные и положительный ноль. Эти значения считаются равными во всех операции.
Четвертое целое число decimal
в вашем примере - 0x00030000
для bitsSingle
и 0x00020000
для bitsDecimal
. В двоичном виде это сопоставляется с:
bitsSingle 00000000 00000011 00000000 00000000
|\-----/ \------/ \---------------/
| | | |
sign <-+ unused exponent unused
| | | |
|/-----\ /------\ /---------------\
bitsDecimal 00000000 00000010 00000000 00000000
NOTE: exponent represents multiplication by negative power of 10
Следовательно, в первом случае 96-битное целое делится на дополнительный коэффициент 10 по сравнению со вторыми битами 16-23, выдает значение 3 вместо 2. Но это компенсируется 96-битным целым числом сама по себе, которая в первом случае также в 10 раз больше, чем во втором (очевидно из значений первых элементов).
Таким образом, разницу в наблюдаемых значениях можно объяснить просто тем фактом, что преобразование из single
использует тонкую логику для получения внутреннего представления по сравнению с "прямым" конструктором.