【问题标题】:Is there a C equivalent of C#'s decimal type?是否有 C# 的十进制类型的 C 等价物?
【发布时间】:2021-01-31 14:59:28
【问题描述】:

关于:Convert Decimal to Double

现在,我遇到了很多与 C# 浮点类型 decimal 相关的问题,并且我看到了它与 floatdouble 的区别,这让我开始思考是否有与这种类型等效的类型在 C 中。

在指定的问题中,我得到了一个我想转换为 C 的答案:

double trans = trackBar1.Value / 5000.0;
double trans = trackBar1.Value / 5000d;

当然,唯一的变化是第二行不见了,但是关于 decimal 类型的东西,我想知道它是 C 等价的。

问题:什么是 C# 的 decimal 的 C 等价物?

【问题讨论】:

标签: c floating-point decimal


【解决方案1】:

C2X 会将十进制浮点数标准化为_Decimal<i>N</i>: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2573.pdf

另外,GCC implements decimal floating point作为扩展名;它目前支持 32 位、64 位和 128 位十进制浮点数。

【讨论】:

    【解决方案2】:

    编辑:正如 cmets 中的 phuclv 所指出的,我在下面所说的大部分内容都只是错误。即便如此,我认为阅读该答案可以获得有价值的信息,因此我将在下面不进行编辑。

    简而言之:是的, 支持标准 C 语言中的Decimal 浮点值和算术。只需查看phuclv 的评论和S.S. Anne 的答案即可。


    正如其他人评论的那样,在 C 编程语言中,没有 Decimal 类型这样的东西,也没有像它一样实现的类型。最接近它的最简单的类型是double,它最常见地实现为符合 IEEE-754 的 64 位浮点类型。它包含一个 1 位符号、一个 11 位指数和一个 52 位尾数/分数。下图很好地代表了它(来自wikipedia):

    所以你有以下格式:

    更详细的解释可以阅读here,但是可以看到指数部分是2的幂,也就是说在处理除以10的时候会出现不精确的情况。一个简单的解释是因为除以任何不是 2 的幂的东西肯定会以 2 为底数无限地重复数字。示例:1/10 = 0.1(以 10 为底数)= 0.00011001100110011...(以 2 为底数)。而且,由于计算机无法存储无限数量的零,因此您的运算将不得不被截断/近似。

    以C#的Decimal为例,来自documentation

    十进制数的二进制表示由一个 1 位符号、一个 96 位整数和一个比例因子组成,该比例因子用于划分整数并指定它的哪一部分是小数。

    最后一部分很重要,因为它不是乘以 2 的幂,而是乘以 10 的幂。所以你有以下格式:

    您可以清楚地看到,这是与上面完全不同的实现!

    例如,如果您想除以 10 的幂,您可以完全正确地进行,因为这只涉及增加指数部分 (N)。但是,您必须注意Decimal 可以表示的数字的限制,最多为 7.922816251426434e+28,而double 可以达到 1.79769e+308。

    鉴于在 C 中(还没有)与Decimal 等效,您可能想知道“我该怎么办?”。这得看情况。首先,使用Decimal 类型对你来说真的很重要吗?你不能用double吗?要回答这个问题,首先了解为什么创建该类型会很有帮助。同样,来自Microsoft's documentation

    Decimal 值类型适用于需要大量有效整数和小数位数且无舍入错误的财务计算

    而且,就在下一句:

    Decimal 类型并不能消除舍入的需要。相反,它可以最大限度地减少由于四舍五入引起的错误

    因此,您不应将Decimal 视为具有“无限精度”,而对于通常需要在十进制系统中进行的计算(如财务计算,如上所述),它是一种更合适的类型。

    如果您仍然想要 C 中的 Decimal 数据类型,您必须开发一个库来支持加法、减法、乘法等 --- 因为 C 不支持运算符重载。此外,它仍然没有硬件支持(例如来自 x64 指令集),因此您的所有操作都会比 double 的操作慢,例如。最后,如果您仍然想要支持其他语言的Decimal(在您的最后一个问题中),您可以查看Decimal TR in C++

    【讨论】:

    • there's no such thing as a Decimal type 这是完全错误的。 C 标准允许浮点类型使用任何整数基数,并且某些实现可以设置 FLT_RADIX == 10 并使用类似于 C# 的 Decimal 的某种格式。 nor are there types implemented like it 这也是错误的。允许编译器具有支持其他十进制浮点类型的扩展。如上所述,C2X 将有 _DecimalN,尽管它们可能不是 C# 的十进制
    • @phuclv 好吧,我今天刚刚学到了一些东西!您能建议编辑并添加来源/参考吗?我很乐意将其添加到我的答案中。
    • 您可以在任何 C 标准中找到 FLT_RADIX 引用,包括 S.S. Anne 答案中的 C2X 草案链接。您还可以在该链接中了解_DecimalN
    【解决方案3】:

    正如其他人指出的那样,C 标准中没有任何内容,例如 .NET 的十进制,但是,如果您在 Windows 上工作并拥有 Windows SDK,则它已被定义:

    DECIMAL structure (wtypes.h)

    表示十进制数据类型,为 数字(如坐标)。

    十进制变量存储为 96 位(12 字节)无符号整数 按 10 的可变幂缩放。10 的幂缩放因子 指定小数点右侧的位数,以及 范围从 0 到 28。

    typedef struct tagDEC {
      USHORT wReserved;
      union {
        struct {
          BYTE scale;
          BYTE sign;
        } DUMMYSTRUCTNAME;
        USHORT signscale;
      } DUMMYUNIONNAME;
      ULONG  Hi32;
      union {
        struct {
          ULONG Lo32;
          ULONG Mid32;
        } DUMMYSTRUCTNAME2;
        ULONGLONG Lo64;
      } DUMMYUNIONNAME2;
    } DECIMAL;
    

    DECIMAL is used to represent an exact numeric value with a fixed precision and fixed scale.

    这种类型的起源是 Windows 的 COM/OLE 自动化(为 VB/VBA/Macros 等引入,所以它早于 .NET,它有很好的 COM 自动化支持),官方记录在这里:[MS-OAUT]: OLE Automation Protocol, 2.2.26 DECIMAL

    它也是 VARIANT 类型 (VT_DECIMAL) 之一。在 x86 架构中,它的大小正好适合 VARIANT(16 字节)。

    【讨论】:

      【解决方案4】:

      使用 C# 中的 Decimal 类型,精度为 28-29 位,大小为 16 个字节。C 中甚至没有与 C# 最接近的等价物。在 Java 中,有一个 BigDecimal 数据类型最接近于C# 十进制数据类型。C# 十进制为您提供如下数字:

      +/- someInteger / 10 ^ someExponent
      

      其中 someInteger 是 96 位无符号整数,而 someExponent 是 0 到 28 之间的整数。

      Is Java's BigDecimal the closest data type corresponding to C#'s Decimal?

      【讨论】:

      猜你喜欢
      • 2021-02-10
      • 2012-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多