C#-增加一个双精度值(1.212E+;25)
我有一个双倍值,等于1.212E+25 当我将它抛出到文本时,我执行myVar.ToString(“0000000000000000”) 问题是,即使我使用myVar++3或4倍,该值似乎保持不变C#-增加一个双精度值(1.212E+;25),c#,.net,types,floating-point,C#,.net,Types,Floating Point,我有一个双倍值,等于1.212E+25 当我将它抛出到文本时,我执行myVar.ToString(“0000000000000000”) 问题是,即使我使用myVar++3或4倍,该值似乎保持不变 为什么会这样?那是因为双精度是不够的。它不能容纳那么多有效数字 它不适合长字符,但可能适合小数 但是。。。您真的需要这样的精度吗?您可能需要阅读以了解倍增的工作原理 基本上,double只有大约16位小数精度。当震级为10^25时,1.0的增量低于精度阈值并丢失。由于二进制表示,这可能不明显。要展开另
为什么会这样?那是因为双精度是不够的。它不能容纳那么多有效数字 它不适合长字符,但可能适合小数 但是。。。您真的需要这样的精度吗?您可能需要阅读以了解
倍增的工作原理
基本上,double
只有大约16位小数精度。当震级为10^25时,1.0的增量低于精度阈值并丢失。由于二进制表示,这可能不明显。要展开另一个答案,您可以对double进行的最小增加是最后一位的一个单位,或ULP,因为double是浮点类型,那么ULP的大小会发生变化,在1E+25时,它将大约为1E+10
正如您所看到的,与1E+10相比,增加1实际上可能等于不增加任何内容。这正是double所能做的,所以如果你尝试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^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的位模式来确定,但是使用上面的循环可能更清楚,因为它可以跨float
、double
和其他浮点表示(在.NET中不存在)。double
(double
)可容纳约16位精度和约18位长度(Int64
)
这两种方法似乎都没有足够的精度满足您的需要
但是,decimal
(decimal
)最多可容纳30位精度。尽管这似乎足以满足您的需要,但我建议您在您的需求进一步增长时谨慎。在这种情况下,您可能需要第三方数字库
相关StackOverflow条目为:
如果将其设为长整数,那么就可以了吗?along
是一个64位有符号整数,其值1.2E25太大,无法放入其中。(最大值为9223372036854775807=2^63-1)不是双1.7E+/-308(15位)的大小@Dimitar:是的,范围最多可以达到10^308…但如果精度只有15位,25位数字加1怎么会有区别呢?@Dimitar没有人提出过相反的说法