为什么C#的System.Decimal(十进制数)“浪费”了一些位?

11

根据官方文档所述, System.Decimal 的128位填充如下:

返回值是一个由四个32位有符号整数组成的数组。

返回数组的第一个、第二个和第三个元素包含96位整数的低32位、中间32位和高32位。

返回数组的第四个元素包含比例因子和符号。它由以下部分组成:

位0到15(较低的字),未使用且必须为零。

位16到23必须包含介于0和28之间的指数,该指数表示将整数除以10的幂。

位24到30未使用且必须为零。

位31包含符号:0表示正数,1表示负数。

考虑到这一点,人们可以看到一些位是“浪费”的或未使用的。

为什么不采用例如120位整数,7位指数和1位符号的方式呢?

可能对于十进制而言采用现在的方式有很好的理由。本问题想要知道作出这个决定的理由。


除了Olivier分享的效率之外,将16位边界对齐可以帮助各种指令优化:https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf 32位边界也有类似的好处:https://dev59.com/PnM_5IYBdhLWcg3ww2Kb 因此,将其保持在32位边界上意味着这些优化不会被Decimal类型排除。 - Jamie F
4
就我所知,十进制类型似乎早于 .net 出现。.net 框架CLR将计算委托给oleaut32库,我可以找到 DECIMAL 类型的痕迹,最早可以追溯到 Windows 95。 - Kevin Gosse
2个回答

3

根据Kevin Gosse的评论

值得一提的是,十进制类型似乎早于.NET。.NET框架CLR将计算委托给oleaut32库,我发现DECIMAL类型可以追溯到Windows 95

我进一步搜索,并在oleauth32 Windows 95中找到了使用DECIMAL代码的可能用户。

旧的Visual Basic(非基于.NET的)和VBA有一种类似动态类型的称为'Variant'。只能在其中(仅在其中)保存与我们当前的System.Decimal几乎相同的东西。

Variant始终为128位,其中前16位保留为枚举值,用于指示Variant中包含的数据类型。

剩余112位的分离可能基于90年代初期常见的CPU架构或Windows程序员的易用性。不将指数和符号打包在一个字节中,以便腾出一个字节来存储整数,这样做似乎很明智。

在.NET构建时,此类型及其操作的现有(低级别)代码被重用为System.Decimal

尽管这些内容并非100%验证,但我希望答案包含更多历史证据,但这是我能拼凑出来的。


1

这里是Decimal的C#源代码。请注意FCallAddSub风格的方法。这些调用到(不可用)快速C++实现的方法。

我怀疑实现是这样的,因为它意味着对前96位中的“数字”进行操作可以简单快速,因为CPU操作32位字。如果使用了120位,CPU操作将变得更慢和更棘手,并且需要大量位掩码来获取有趣的额外24位,然后难以处理。此外,这将“污染”最高32位标志,并使某些优化成为不可能。

如果您查看代码,可以看到这种简单的位布局在任何地方都很有用。毫无疑问,在底层的C++(可能还有汇编语言)中特别有用。


FCallAddSub的实现 - user12031933

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