将双精度浮点数转换为长整型改变了数值

3

我注意到当要转换的数字很大但仍然远低于long的最大值时,从doublelong的转换会改变值。 例如,有人能解释一下为什么这个转换并没有按预期工作吗:

Convert.ToInt64(600000000000040000d)
// Return => 600000000000039936
Convert.ToInt64(600000000000040000L)
// Return => 600000000000040000

这会导致我的公式出现问题...谢谢。


1
double文档中得知:"Double值具有高达15位小数精度"。您正在使用19位数字。 - Matthew Watson
3个回答

5

好的,double 只有 52尾数(详见https://zh.wikipedia.org/wiki/IEEE_浮点数算术);这就是为什么 double 可以表示最大为 2**53 - 1 == 9007199254740991精确 整数值。

 600000000000040000 > 9007199254740991

这就是为什么“舍入误差”是不可避免的原因:

  double d = 600000000000040000d;

  long l = (long)d;

  double d2 = l;

  Console.WriteLine($"{d:r} : {l} : ({d == d2 ? "Equal" : "Different"})");

结果:

  6.0000000000004E+17 : 600000000000039936 : Equal

如果你在处理金融数据,可以尝试使用decimal代替double

  decimal d = 600000000000040000m; // m suffix

  long l = (long)d;

  decimal d2 = l;

  Console.WriteLine($"{d} : {l} : ({d == d2 ? "Equal" : "Different"})");

结果:
  600000000000040000 : 600000000000040000 : Equal

这正是我一直在寻找的。十进制解决了我的问题,更重要的是,我理解了这种行为的原因。谢谢。 - Corabox

1
我希望这能帮到你:
当将double或float值转换为整数类型时,该值会向零舍入至最近的整数值。如果生成的整数值超出目标类型的范围,则结果取决于溢出检查上下文。在已检查的上下文中,会引发OverflowException异常,而在未经检查的上下文中,结果是目标类型的未指定值。
来源:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/explicit-numeric-conversions-table 注意:long是一种整数类型,它是Int64:在C#中,Int64和long有什么区别? 此外,float和double是浮点类型。它们以不同的方式存储在内存中浮点数在内存中如何存储?

维基百科:https://en.wikipedia.org/wiki/Single-precision_floating-point_format(单精度浮点数格式)


1
我希望这能更好地帮助你。
// Double to long
           double av = 600000000000040000L;
            long lg = (long)av;
            long g1 = Convert.ToInt64(av);
// long to Double
            double dbl = (double)g1;
            double d = Convert.ToDouble(g1);

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