C# - 增加一个双精度值(1.212E + 25)

时间:2010-05-28 08:54:21

标签: c# .net types floating-point

我的双重值等于1.212E + 25

当我把它扔到文本时,我做myVar.ToString(“0000000000000000000000”)

问题是,即使我做myVar ++ 3或4倍,价值也似乎保持不变。

为什么?

5 个答案:

答案 0 :(得分:3)

这是因为双精度不够。它根本无法容纳那么多有效数字。

它不适合长,但可能是十进制。

但是......你真的需要这种精确度吗?

答案 1 :(得分:2)

要扩展另一个答案,你可以对double进行最小的增加是最后一个位置的一个单位,或ULP,因为double是一个浮点类型,然后ULP的大小发生变化,在1E + 25它会约1E + 10。

正如您所看到的,与1E + 10相比,增加1真的可能不会增加任何东西。这正是双重会做的事情,所以如果你试了10 ^ 25次就没关系它仍然不会增加,除非你试图增加至少1 ULP

如果通过ULP递增是有用的,你可以通过将位转换为long来实现这一点,这里是一个快速扩展方法来做到这一点

  public static double UlpChange(this double val, int ulp)
  {
    if (!double.IsInfinity(val) && !double.IsNaN(val))
    {
      //should probably do something if we are at max or min values 
      //but its not clear what
      long bits = BitConverter.DoubleToInt64Bits(val);
      return BitConverter.Int64BitsToDouble(bits + ulp);
    }
    return val;
  }

答案 2 :(得分:1)

您可能需要阅读the Floating-Point Guide以了解doubles的工作原理。

基本上,double只有大约16个十进制数字的精度。在10 ^ 25的量级上,增加1.0低于精度阈值并且丢失。由于二进制表示,这可能不是很明显。

答案 3 :(得分:1)

doubleDouble)约有16位精度,longInt64)约有18位数。

这些似乎都没有足够的精确度满足您的需求。

但是decimalDecimal)最多可容纳30位精度。虽然这似乎足以满足您的需求,但如果您的需求变得更大,我建议您谨慎行事。在这种情况下,您可能需要第三方数字库。

相关的StackOverflow条目是:
How can I represent a very large integer in .NET?
Big integers in C#

答案 4 :(得分:0)

工作的最小增量为2 ^ 30 + 1,实际上将双倍增加2 ^ 31。你可以使用LINQPad轻松测试这种东西:

double inc = 1.0;
double num = 1.212e25;
while(num+inc == num) inc*=2;

inc.Dump(); //2147483648 == 2^31
(num+inc == num).Dump(); //false due to loop invariant
(num+(inc/2.0) == num).Dump();//true due to loop invariant
(num+(inc/2.0+1.0) == num).Dump();//false - 2^30+1 suffices to change the number
(num+(inc/2.0+1.0) == num + inc).Dump();//true - 2^30+1 and 2^31 are equiv. increments
((num+(inc/2.0+1.0)) - num == inc ).Dump();//true - the effective increment is 2^31

由于double本质上是一个精度有限的二进制数,这意味着最小可能的增量本身总是2的幂(这个增量可以直接从double的位模式确定,但它可能更清晰使用上面的循环来执行此操作,因为它可以在floatdouble和其他浮点表示(.NET中不存在)中移植。