.net十进制值1m和1.0000m之间是否存在实际差异?
内部存储不同:
1m : 0x00000001 0x00000000 0x00000000 0x00000000
1.0000m : 0x000186a0 0x00000000 0x00000000 0x00050000
但是,BCL中的方法是否会使用“有效数字”的知识呢?
我问,因为我正在研究压缩磁盘存储或网络传输的十进制值所需空间的方法,并且在我存储它之前想要“规范化”该值以提高它的可压缩性。但是,我想知道它是否可能导致问题。我猜它应该没问题,但只是因为我没有看到任何暴露值的精度的方法或属性。有没有人知道呢?
答案 0 :(得分:11)
编码差异的原因是因为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运算符作为十进制类型并且不自己操作/比较位/字节,那么您应该是安全的。
您还会注意到字符串转换也会考虑这个二进制表示并生成不同的字符串,因此如果您依赖字符串表示,则需要小心。
答案 1 :(得分:5)
decimal
类型跟踪比例因为它在算术中很重要。如果您手动对两个数字进行长时间乘法 - 例如,3.14 * 5.00 - 结果有6位 precision 和 scale 为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 /另一种说法是说你的测量结果准确,最好是在规定值的+/- 5/100之内。
答案 2 :(得分:4)
我能想到的唯一原因就是调用`ToString返回源代码中的确切文本表示。
Console.WriteLine(1m); // 1
Console.WriteLine(1.000m); // 1.000