为什么要使用十进制(int [ ])构造函数?

29

我正在维护一个使用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()' 不接受数组作为参数。 - jdweng
8
这个重载函数的作用可以在此链接中查看:https://msdn.microsoft.com/zh-cn/library/t1de0ya1(v=vs.110).aspx。 - James Thorpe
1
将以下关于编程的内容从英语翻译成中文。只返回已翻译的文本:提交到http://thedailywtf.com/ - John Alexiou
1
@jdweng 不是的 - 构造函数需要一个长度为4的数组,并使用它来构造一个单一 decimal 对象 - James Thorpe
1
@jdweng 这是一个不同的构造函数。接受一个包含4个int的数组,将isNegativescale组合成第四个int - James Thorpe
显示剩余2条评论
6个回答

12

在十进制数的来源由位组成时,我认为这很有用。

.NET中使用的十进制数实现是基于一系列的位参数(不仅仅是像int一样的一个比特流),因此在与其他通过字节块(套接字、内存片段等)返回十进制数的系统进行通信时,使用位构造十进制数可能是有用的。

现在可以轻松地将一组位转换为十进制数了,无需花哨的转换代码。此外,您还可以根据标准中定义的输入构造一个十进制数,这对于测试.NET框架也很方便。


3
看起来很有可能,特别是因为没有BitConverter.ToDecimal()等方法。我认为Decimal.GetBits()是谜题的另一部分。 - Matthew Watson
我认为.NET的Decimal类型和维基页面上描述的类型之间没有任何关系。那种类型具有比.NET类型更大的精度和范围,看起来像是由一个不理解固定小数类型具有固定精度重要性的人设计的固定小数类型的替代品[在使用固定精度类型时,如果(x+y)+z和x+(y+z)可以在不触发溢出陷阱的情况下计算,两者将产生相同的结果;这对于包括Decimal在内的任何浮点类型都不成立]。 - supercat

9
decimal(int[] bits)构造函数允许您以位方式定义要创建的十进制数,其中bits必须是一个4个整数的数组,其中:
bits 0、1和2组成96位整数。
bits 3包含比例因子和符号。
它允许您根据您的示例非常精确地定义十进制数,但我认为您不需要那种精度级别。
有关使用该构造函数的更多详细信息,请参见此处,或者此处获取其他可能更适合您的构造函数。
更具体地回答您的问题,如果digitNumber是16位指数,则decimal d = new decimal(new int[] { 1, 0, 0, digitNumber << 16 });会执行您想要的操作,因为指数在数组中的最后一个整数的第16-23位。

3
“bits 0、1和2组成了96位整数”这个说法很容易让人产生混淆,因为听起来像是将3个比特组合在一起得到了96比特。(.Net的作者通过将参数命名为“bits”没有帮助你。) - svick

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

1
有一个IEEE标准描述了“十进制”,这里没有什么混淆的。 - Patrick Hofman
为什么微软不能称呼玫瑰为玫瑰并创造他们自己的名称。Patrick提供的链接已经尽力避免称呼IEEE浮点数为浮点数。 - jdweng
使用 == 进行推理并不是一个好主意:(new decimal(new int[] { 10, 0, 0, 0x30000})) == 0.01m 也会返回 true。虽然这两个值表示相同的数字,但它们不是相同的 decimal 值(它是 0.010,而不是 0.01)。 - svick
在任何情况下,0.010 != 0.01吗? - CathalMF

2
你所提到的构造函数从四个32位值生成一个十进制数。不幸的是,新版本的公共语言基础设施(CLI)未指定其确切格式(可能是为了允许实现支持不同的十进制格式),现在只保证具有特定精度和范围的十进制数。然而,早期版本的CLI确切地定义了微软实现的格式,因此微软的实现可能为了向后兼容而保留了这种方式。但是,不能排除CLI的其他实现将以不同的方式解释Decimal构造函数的四个32位值的可能性。

2

您需要准确地了解内存中的十进制数

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

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));

Here is the result

1
0.01
0.00001


1

十进制数是精确数值,您可以使用==或!=测试相等性。

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

我会清理它。


嗯,这段代码在Windows Forms生成的代码中。很难清理并且完全没有用,因为它会被重新生成回原来的样子。 - Patrick Hofman
并不意味着它是好的代码 =) 我敢打赌,如果我用ReSharper打开自动生成的表单代码,整个滚动条都会变成橙色 =) - Dmitri Trofimov
2
“decimal” 数字在什么意义上是“精确数值”? - Codor
5
我不太确定这个回答是否符合问题。 - helrich
Decimal可以精确表示的值集比Double更符合人类可读的表述方式,但通常情况下两者都没有更或少“精确”。 - supercat

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