【问题标题】:Why use decimal(int [ ]) constructor?为什么要使用 decimal(int [ ]) 构造函数?
【发布时间】:2016-08-07 13:03:37
【问题描述】:

我正在使用 Visual Studio 2013 在 Windows 7 上维护 C# 桌面应用程序。代码中的某处有以下行,它尝试使用 Decimal(Int32[]) 构造函数创建 0.01 十进制值:

decimal d = new decimal(new int[] { 1, 0, 0, 131072 });

第一个问题是,和下面的有区别吗?

decimal d = 0.01M;

如果没有什么不同,为什么开发者会遇到这样的编码麻烦?

我需要更改此行以创建动态值。比如:

decimal d = (decimal) (1 / Math.Pow(10, digitNumber));

我会以这种方式引起一些不受欢迎的行为吗?

【问题讨论】:

  • 我想你想要:decimal[] d = new decimal[] {1,0,0,131072};构造函数“new decimal()”不接受数组作为参数。
  • 提交给thedailywtf.com
  • @jdweng 否 - 构造函数接受一个长度必须正好为 4 项的数组,并使用它来构造一个 single decimal object
  • @jdweng 那是一个不同的构造函数。采用 4 个 ints 数组的那个将 isNegativescale 组合成第 4 个 int

标签: c# .net refactoring decimal


【解决方案1】:

当小数的来源由位组成时,这对我来说似乎很有用。

.NET 中使用的小数有一个基于位参数序列的实现(而不仅仅是像int 那样的一个位流),因此在通信时用位构造一个小数会很有用与其他通过字节块返回小数的系统(套接字,来自一块内存等)。

现在很容易将一组位转换为十进制。无需花哨的转换代码。此外,您可以从标准中定义的输入构造一个小数,这也便于测试 .NET 框架。

【讨论】:

  • 似乎很可能,特别是因为没有BitConverter.ToDecimal() 等。我认为Decimal.GetBits() 是另一个难题。
  • 我认为 .NET Decimal 类型与 Wiki 页面上描述的类型之间没有任何关系。该类型具有比 .NET 类型更大的精度和范围,它看起来像是由不了解具有固定精度的固定十进制类型的重要性的人设计的固定十进制类型的替代品[除其他事项外,当使用固定-精度类型,如果 (x+y)+z 和 x+(y+z) 可以在没有溢出陷阱的情况下进行评估,则两者将产生相同的结果;这不适用于任何浮点类型,包括Decimal]。
【解决方案2】:

您正在谈论的特定构造函数从四个 32 位值生成一个小数。不幸的是,较新版本的公共语言基础结构 (CLI) 未指定其确切格式(可能是为了允许实现支持不同的十进制格式),现在仅保证至少有特定的精度和十进制数字范围。但是,早期版本的 CLI 确实像 Microsoft 的实现那样定义了该格式,因此它可能在 Microsoft 的实现中保持这种方式以实现向后兼容性。但是,不排除 CLI 的其他实现会对 Decimal 构造函数的四个 32 位值进行不同的解释。

【讨论】:

    【解决方案3】:

    xml中的定义是

        //
        // Summary:
        //     Initializes a new instance of System.Decimal to a decimal value represented
        //     in binary and contained in a specified array.
        //
        // Parameters:
        //   bits:
        //     An array of 32-bit signed integers containing a representation of a decimal
        //     value.
        //
        // Exceptions:
        //   System.ArgumentNullException:
        //     bits is null.
        //
        //   System.ArgumentException:
        //     The length of the bits is not 4.-or- The representation of the decimal value
        //     in bits is not valid.
    

    因此,出于某种未知原因,最初的开发人员想以这种方式初始化他的小数。也许他只是想在未来迷惑某人。

    如果您将其更改为,它可能不会影响您的代码

    decimal d = 0.01m;
    

    因为

    (new decimal(new int[] { 1, 0, 0, 131072})) == 0.01m
    

    【讨论】:

    • 有一个 IEEE 标准描述 decimal,这里没有混淆。
    • 为什么微软不能自己命名。 Patrick 提供的链接已尽一切努力避免将 IEEE 浮点数称为浮点数。
    • 使用== 推理不是一个好主意:(new decimal(new int[] { 10, 0, 0, 0x30000})) == 0.01m 也返回true。虽然这两个值代表相同的数字,但它们不是相同的decimal 值(它是 0.010,而不是 0.01)。
    • 有0.010 != 0.01的情况吗?
    【解决方案4】:

    decimal(int[] bits) 构造函数允许您按位定义要创建的小数位必须是 4 int 数组,其中:

    位 0、1 和 2 构成 96 位整数。

    位 3 包含比例因子和符号

    从你的例子来看,它只是让你对小数的定义非常精确,我认为你不需要那种精确度。

    请参阅here 了解有关使用该构造函数的更多详细信息,或参阅here 了解可能更适合您的其他构造函数

    如果 digitNumber 是 16 位指数,则更具体地回答您的问题,那么 decimal d = new decimal(new int[] { 1, 0, 0, digitNumber << 16 }); 会执行您想要的操作,因为指数位于数组中最后一个 int 的第 16 - 23 位

    【讨论】:

    • “位 0、1 和 2 构成 96 位整数”我认为这是一个非常令人困惑的公式,因为听起来您将 3 位组合起来得到 96 位。 (.Net 的作者没有通过命名参数 bits 来帮助您。)
    【解决方案5】:

    你应该确切地知道decimal是如何存储在内存中的。

    您可以使用此方法生成所需的值

    public static decimal Base10FractionGenerator(int digits)
    {
        if (digits < 0 || digits > 28)
            throw new ArgumentException($"'{nameof(digits)}' must be between 0 and 28");
    
        return new decimal(new[] { 1, 0, 0, digits << 16 });
    }
    

    像这样使用它

    Console.WriteLine(Base10FractionGenerator(0));
    Console.WriteLine(Base10FractionGenerator(2));
    Console.WriteLine(Base10FractionGenerator(5));
    

    这是结果

    1
    0.01
    0.00001

    【讨论】:

      【解决方案6】:

      小数是精确的数字,您可以使用 == 或 != 来测试是否相等。

      也许,这行代码来自其他在某个特定时间点有意义的地方。

      我会清理它。

      【讨论】:

      • 好吧。此类代码是在 Windows 窗体中生成的代码。不容易清理而且完全没用,因为它会恢复到原来的样子。
      • 并不意味着它是好的代码 =) 我敢打赌,如果我打开带有 ReSharper 的表单自动生成的代码,整个滚动条将是橙色 =)
      • decimal 数字“精确数字”在什么意义上?
      • 我不太确定这是如何回答这个问题的。
      • Decimal 可以精确表示的一组值比Double 可以精确表示的一组值更符合人类可读的符号,但两者都不是或多或少“精确”在一般情况下。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-08
      • 1970-01-01
      • 2019-12-21
      • 1970-01-01
      • 1970-01-01
      • 2018-06-02
      相关资源
      最近更新 更多