.NET"十进制"算术是否独立于平台/架构?

Tim*_*mwi 16 .net c# math

System.Double最近询问过,并被告知计算可能因平台/架构而异.不幸的是,我找不到任何信息告诉我是否同样适用System.Decimal.

我是否保证在独立于平台/架构的情况下获得与任何特定计算完全相同的结果decimal

Eri*_*ert 31

我是否保证在独立于平台/架构的情况下获得与任何特定十进制计算完全相同的结果?

C#4规格显然,价值,你得到的将被计算在任何平台上是相同的.

正如LukeH的回答所指出的那样,ECMA版本的C#2规范赋予了符合实现的余地以提供更高的精度,因此在另一个平台上实现C#2.0可能会提供更高精度的答案.

出于这个答案的目的,我将只讨论C#4.0指定的行为.

C#4.0规范说:


对十进制类型值的操作结果是计算精确结果(保留每个运算符定义的比例)然后舍入以适合表示形式的结果.结果四舍五入到最接近的可表示值,并且当结果等于接近两个可表示的值时,结果四舍五入到在最低有效位数[...]中具有偶数的值.零结果始终具有0的符号和0的标度.


由于操作的精确值的计算在任何平台上应该是相同的,并且舍入算法是明确定义的,因此无论平台如何,结果值应该相同.

但是,请注意关于零的括号和最后一句.可能不清楚为什么这些信息是必要的.

十进制系统的一个奇怪之处在于,几乎每个数量都有多个可能的表示.考虑确切值123.456.十进制是96位整数,1位符号和8位指数的组合,表示从-28到28的数字.这意味着精确值123.456可以用小数123456 x 10 -3或1234560表示x 10 -4或12345600 x 10 -5.规模很重要.

C#规范还规定了如何计算有关比例的信息.文字123.456m将编码为123456 x 10 -3,而123.4560m将编码为1234560 x 10 -4.

观察此功能的效果:

decimal d1 = 111.111000m;
decimal d2 = 111.111m;
decimal d3 = d1 + d1;
decimal d4 = d2 + d2;
decimal d5 = d1 + d2;
Console.WriteLine(d1);
Console.WriteLine(d2);
Console.WriteLine(d3);
Console.WriteLine(d4);
Console.WriteLine(d5);
Console.WriteLine(d3 == d4);
Console.WriteLine(d4 == d5);
Console.WriteLine(d5 == d3);
Run Code Online (Sandbox Code Playgroud)

这产生了

111.111000
111.111
222.222000
222.222
222.222000
True
True
True
Run Code Online (Sandbox Code Playgroud)

请注意如何在小数运算之间保留有关重要零数字的信息,并且decimal.ToString知道这一点并显示保留的零(如果可以).还要注意十进制相等如何知道基于精确值进行比较,即使这些值具有不同的二进制和字符串表示.

我认为规范实际上并不是说decimal.ToString()需要根据它们的比例正确地打印出带有尾随零的值,但如果没有这样做,那么实现就是愚蠢的.我会认为这是一个错误.

我还注意到CLR实现中十进制的内部存储器格式是128位,细分为:16个未使用位,8个标度位,7个未使用位,1个符号位和96个尾数位.内存中这些位的确切布局不是由规范定义的,如果另一个实现想要为了它自己的目的将额外的信息填充到这23个未使用的位中,它可以这样做.在CLR实现中,未使用的位应始终为零.

  • @Eric:微软的C#规范似乎比"ECMA规范"(在我的回答中引用的摘录)更严格地锁定"十进制".似乎MS规范保证了`decimal`的*exact*行为,而ECMA-334允许一些余地.例如,一个符合ECMA标准的实现理论上可能具有12位指数,112位尾数,并且还允许带符号的零,无穷大和NaN - 根据我的解释 - 而另一个可能遵循MS规范.如果是这种情况,那么在每个(符合ECMA的)平台上计算的值将不保证是相同的. (6认同)
  • @LukeH:这是一个很好的问题; 我甚至没想过检查ECMA规范.我只是假设自从The Before Time以来C#4规范中的措辞没有改变.如果我有空闲时间,我会调查一下. (3认同)
  • @James,@ Timwi:正确,我们将比例保持在0.000.这似乎与规范声明相矛盾,即"零结果始终具有零刻度".我不确定为什么规范会这样说; 它很奇怪.我会调查. (2认同)

Jus*_*gan 5

decimal类型是在什么相当于使用结构与base-10表示的(含整数的,我相信),相对于double和其他浮点类型,其表示在基-2-非整数值.因此,decimals是在任何体系结构上的标准精度内的基数10值的精确表示.对于运行正确实现.NET规范的任何体系结构都是如此.

因此,为了回答您的问题,由于在decimal规范中以这种方式标准化了行为,因此在decimal符合该规范的任何体系结构上的值应该相同.如果他们不符合那个规范,那么他们就不是真正的.NET.

"十进制".NET类型与"浮点"和"双"C/C++类型

  • 我不确定我是否按照你的第一句话中的逻辑.double类型也使用包含整数的结构实现,实际上,它们与十进制类型的整数相同.double包含一位整数,它是符号,11位整数是指数,52位整数是尾数.十进制包含作为符号的一位整数,作为指数的8位整数,以及作为尾数的96位整数.唯一的区别是,在一个double中,指数是2的幂,在十进制中,指数是10的幂. (10认同)
  • 我的观点是,双精度是每一位特定数字的精确表示,而小数则是特定数字的精确表示.它们只是*不同数字组*的精确表示.可以精确表示为十进制选择的数字集是对财务计算最有用的集合. (7认同)
  • 我也没有遵循你的第二句话的逻辑.十进制值1.0m/3.0m不是三分之一的确切值; 它是近似的三分之一精确到大约28位小数左右.双值1.0/3.0也不是三分之一的准确值; 它是一个精确到大约15位小数的近似值.双精度是二进制值的精确表示和十进制值的近似值; 小数是十进制值的精确表示.但两者都是不恰当的代表,例如,数字可以完全代表三. (6认同)
  • @Timwi:根据规范,你问的是.NET框架的具体实现是否正确.这与您最初提出的问题明显不同.知道一个实现是否正确虽然你应该能够通过查看规范并运行一些单元测试来自己确认这一点. (3认同)

Jef*_*tes 5

即使浮点类型的格式已明确定义,浮点计算确实可能具有不同的结果,具体取决于体系结构,如C#规范的4.1.6节所述:

可以以比操作的结果类型更高的精度执行浮点运算.例如,某些硬件体系结构支持"扩展"或"长双"浮点类型,其范围和精度比double类型更大,并使用此更高精度类型隐式执行所有浮点运算.只有在性能成本过高的情况下,才能使这种硬件架构以较低的精度执行浮点运算,而不是要求实现放弃性能和精度,C#允许更高精度的类型用于所有浮点运算.

虽然该decimal类型需要近似以使值在其有限范围内表示,但是根据定义,该范围被定义为适合于金融和货币计算.因此,它具有比float或更高的精度(和更小的范围)double.它也比其他浮点类型更明确定义,因此它看起来与平台无关(参见4.1.7节 - 我怀疑这种平台独立性更多是因为对于具有大小和类型的类型没有标准硬件支持精度decimal而不是因为类型本身,所以这可能会随着未来的规范和硬件架构而改变).

如果您需要知道该decimal类型的特定实现是否正确,您应该能够使用将测试正确性的规范来制作一些单元测试.


Luk*_*keH 5

本说明书的阅读建议decimal-像floatdouble- 可能被允许在执行一些回旋余地,只要符合一定的最低标准.

以下是ECMA C#规范的一些摘录(第11.1.7节).所有大胆的重点都是我的.

decimal类型可以表示的值,包括那些在范围为1×10 -28至1×10 28至少 28个显著数字.

类型的有限值集合decimal的形式为(-1)s x c x 10 - e,其中符号s 为0或1,系数c由0 <= c < Cmax给出,标度e为使得额敏 <= Ë <= 的Emax,其中 的C max至少 1×10 28,额敏 <= 0,和 的Emax > = 28.decimal类型不一定 支持有符号的零,无穷大或NaN的.

decimals的绝对值小于1.0m,则该值是精确到至少 28 小数位.对于decimal绝对值大于或等于的s 1.0m,该值精确到至少 28位.

请注意,Microsoft C#规范(第4.1.7节)的措辞与ECMA规范的措辞明显不同.它似乎decimal更严格地锁定了更严重的行为.

  • 我调查了一下.在ECMA规范标准化时,有来自其他公司的技术委员会成员,他们对基准十浮点的IEEE标准有相当大的兴趣和专业知识.显然他们认为,如果一个实现可以在实现它的假设未来芯片上使用基于硬件的IEEE兼容十进制算法,那么只要满足精度和准确度的最低标准,就应该允许符合标准的实现.您在规范中看到的语言是由此产生的妥协. (4认同)
  • @Justin:的确,然而,在这种情况下,我只是问那个写那部分规格的人那天他在想什么.由于他在我旁边的办公室,所以找到他并不困难. (4认同)