为什么我从双倍到十进制时丢失数据

时间:2015-01-09 15:46:25

标签: c#

我有以下代码,我无法改变......

 public static decimal Convert(decimal value, Measurement currentMeasurement, Measurement targetMeasurement,  bool roundResult = true)
 {
     double result = Convert(System.Convert.ToDouble(value), currentMeasurement, targetMeasurement, roundResult);
     return System.Convert.ToDecimal(result);
 }

现在result返回-23.333333333333336,但转换为decimal后,它变为-23.3333333333333M

我认为decimal s可以包含更大的值,因此更准确,因此我如何丢失从doubledecimal的数据?

1 个答案:

答案 0 :(得分:9)

这是设计的。引用Convert.ToDecimal的文档:

  

此方法返回的Decimal值最多包含   15位有效数字。如果参数包含的值超过15   有效数字,使用舍入到最近的四舍五入。该   下面的例子说明了Convert.ToDecimal(Double)方法   使用舍入到最近值以使用15返回Decimal值   有效数字。

Console.WriteLine(Convert.ToDecimal(123456789012345500.12D));  // Displays 123456789012346000
Console.WriteLine(Convert.ToDecimal(123456789012346500.12D));  // Displays 123456789012346000

Console.WriteLine(Convert.ToDecimal(10030.12345678905D));      // Displays 10030.123456789 
Console.WriteLine(Convert.ToDecimal(10030.12345678915D));      // Displays 10030.1234567892

原因主要是double无论如何都只能保证15位十进制数。在它们之后显示的所有内容(转换为字符串,它是17位数,因为这是double在内部使用的内容,因为这是您可能需要从字符串中精确重建每个可能的double值的数字)并不保证成为所代表的确切价值的一部分。所以Convert采取唯一明智的路线并将它们四舍五入。毕竟,如果你的类型可以准确地表示十进制值,那么你不希望以不准确的数字开头。

所以你本身并没有丢失数据。事实上,你只是在丢失垃圾。你认为是垃圾的垃圾。

编辑:从评论中澄清我的观点:不同数字数据类型之间的转换可能会导致精度损失。 doubledecimal之间的情况尤其如此,因为这两种类型都能够表示其他类型无法表示的值。此外,doubledecimal都有相当具体的用例,从文档中可以看出这一点(强调我的):

  

Double值类型表示带有的双精度64位数   价值从负1.79769313486232e308到正数   1.79769313486232e308,以及正零或负零,PositiveInfinity,NegativeInfinity,而不是数字(NaN)。 是的   旨在表示非常大的值(例如   行星或星系之间的距离)或极小(   物质的分子量,以千克为单位),通常是   不精确(例如从地球到另一个太阳系的距离)。   Double类型符合IEC 60559:1989(IEEE 754)标准   用于二进制浮点运算。

     

十进制值类型表示范围从的十进制数   为负数为79,228,162,514,264,337,593,543,950,335   79,228,162,514,264,337,593,543,950,335。 十进制值类型是   适用于需要大量资金的财务计算   显着的积分和小数位数,没有舍入误差。   Decimal类型不会消除舍入的需要。相反,它   最大限度地减少因四舍五入造成的错误。

这基本上意味着对于不会增长不合理的数量并且您需要准确的十进制表示的数量,您应该使用decimal(当以这种方式编写时听起来相当明显)。在实践中,这通常意味着财务计算,正如文档已经说明的那样。

另一方面,在绝大多数其他情况下,double是正确的方法,通常不会作为默认选择(Lua和JavaScript等语言获得)只需将double作为唯一的数字数据类型)即可。

在您的具体案例中,由于您在评论中提到这些是温度读数,因此非常非常非常简单:只需使用double。你有温度读数。维基百科建议高度专业化的温度计达到10 -3 °C精度。这基本上意味着你在这里担心的大约10 -13 (!)的价值差异根本无关紧要。你的温度计给你(让我们慷慨)五个准确的数字,你担心随后垃圾的十位数。只是不要。

我确信物理学家或其他科学家可以在这里适当处理测量及其精确度,但我们在学校教过,甚至给出比测量值更精确的值也是完全废话。并且计算可能会影响(并降低)该精度。