.NET中的1m和1.0000m之间有任何实际区别吗?

14

在.NET中,使用1m和1.0000m这两个十进制数值是否有实际区别呢?

它们的内部存储方式不同:

1m      : 0x00000001 0x00000000 0x00000000 0x00000000
1.0000m : 0x000186a0 0x00000000 0x00000000 0x00050000

但是,在BCL中有没有使用“有效数字”知识的情况呢?

我问这个问题是因为我正在努力压缩磁盘存储或网络传输所需的十进制值的空间,并且正在考虑在存储之前“规范化”该值以提高其可压缩性。但是,我想知道它是否可能会在将来引起问题。我猜应该没问题,但只是因为我没有看到任何公开精度的方法或属性。有人知道不一样的吗?

3个回答

12
差异的原因在于Decimal数据类型将数字存储为整数(96位整数),使用一个比例来形成除数以获取小数部分。该值本质上是:
integer / 10^scale

在内部,Decimal类型表示为4个Int32,有关详细信息,请参阅Decimal.GetBits文档。简而言之,GetBits返回一个由4个Int32组成的数组,其中每个元素表示Decimal编码的后续部分。

Element 0,1,2 - Represent the low, middle and high 32 bits on the 96 bit integer
Element 3     - Bits 0-15 Unused
                Bits 16-23 exponent which is the power of 10 to divide the integer by
                Bits 24-30 Unused 
                Bit 31 the sign where 0 is positive and 1 is negative

在你的例子中,简单来说,当1.0000m被编码为十进制数时,实际的表示方式是10000 / 10^4,而1m则被表示为1 / 10^0,从数学上讲它们是相同的值,只是以不同的方式编码。

如果你使用.NET内置的decimal类型操作符,并且不手动操作/比较位/字节,那么就可以保证安全。

你还会注意到字符串转换也将考虑这种二进制表示方式并生成不同的字符串,因此如果你依赖于字符串表示,则需要小心。


小细节:不是字节1、2、3,而是(4字节四元组)。或者你可以说前12个字节保存整数值。 - Matt Brunell
@Matt Brunell,你说得完全正确!谢谢你,我已经相应地更正了答案。 - Chris Taylor

5
< p > decimal 类型会跟踪比例因为在算术中它很重要。如果您手动进行两个数字的长乘法,例如 3.14 * 5.00,结果具有 6 位 精度 和 4 位比例

为了进行乘法,请忽略小数点(暂时)并将两个数字视为整数。

  3.14
* 5.00
------
  0000 -- 0 * 314 (0 in the one's place)
 00000 -- 0 * 314 (0 in the 10's place)
157000 -- 5 * 314 (5 in the 100's place)
------
157000

这将为您提供未经缩放的结果。现在,数一下表达式小数点右侧的总位数(应该是4),并将小数点插入左侧4个位置:

15.7000

那个结果虽然等价于15.7,但比15.7更加精确。数值15.7000具有6位有效数字和4位小数;而15.7只有3位有效数字和1位小数。
如果要进行精确的算术运算,跟踪数值和结果的精度和小数位数非常重要,因为它可以告诉您关于结果精度的一些信息(请注意,精度与准确性不同:使用标有1/10英寸刻度的尺子测量某物,无论您在小数点右侧放置多少个尾随零,最好的说法是其精度最多为1/10英寸。另一种说法是,您的测量结果在规定值的正负5/100内是准确的。)

不幸的是,Decimal 跟踪精度的方式并不能可靠地保留有关所涉及数字精度的任何信息。除以不是形如 2^n * 5^n 的数字将产生最大可表示数字的位数,无论这些数字是否代表任何真实的准确性,并且没有任何指示表明减法会导致灾难性的抵消。 - supercat

4
我能想到的唯一原因是调用`ToString`会返回在源代码中精确的文本表示。
Console.WriteLine(1m); // 1
Console.WriteLine(1.000m); // 1.000

1
“ToString” 怎么可能知道源代码的任何信息呢? - John Saunders
1
@Chaos:胡说八道。找一个更好的解释,但不是那个。你知道.NET的其他功能吗,其中存储有关源代码的实际信息,而不是元数据吗? - John Saunders
@John - 我认为显然精度实际上是从源代码中检索的元数据。 - ChaosPandion
9
@John,@Chaos,这是因为Decimal数据类型实际上被存储为带有除数(scale)的整数。因此,当数字1.000m被编码成Decimal数据类型时,它被存储为1000和一个缩放比例为3,而数字1被存储为具有缩放比例为0的1。 - Chris Taylor
4
我认为大家在这里过于纠结语义细节了,@ChaosPandion 的意思是它将数字的表示形式存储为输入源代码时的样子,这是正确的。 - codekaizen
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接