当我运行以下代码时,我在两行上都打印出0:
Double a = 9.88131291682493E-324;
Double b = a*0.1D;
Console.WriteLine(b);
Console.WriteLine(BitConverter.DoubleToInt64Bits(b));
如果操作结果超出范围,我希望得到Double.NaN。相反,我得到0.它看起来能够检测到这种情况发生时我必须检查:
这相当笨拙。有没有更好的办法? Double.NaN的目的是什么?我假设某些操作必须归还它,当然设计师并没有把它放在那里以防万一?这可能是BCL中的一个错误吗? (我知道不太可能,但是,这就是为什么我想了解Double.NaN应该如何工作的原因)
更新
顺便说一句,这个问题不是双重的。十进制暴露它们都是一样的:
Decimal a = 0.0000000000000000000000000001m;
Decimal b = a* 0.1m;
Console.WriteLine(b);
这也给零。
在我的情况下,我需要加倍,因为我需要他们提供的范围(我正在进行概率计算)并且我并不担心精度。
我需要的是能够检测到我的结果何时停止意味着什么,也就是说当计算值降低到这么低时,它就不能再用双倍表示。
有没有实用的方法来检测这个?
答案 0 :(得分:6)
Double
完全符合浮点数规范IEEE 754.所以不,它不是BCL中的错误 - 它只是IEEE 754浮点的工作方式。 / p>
当然,原因在于它根本不是浮子的设计。 相反,您可能希望使用 decimal
,这是精确十进制数,与float
/ double
不同。
浮点数中有一些特殊值,含义不同:
1f / 0f
。-1f / 0f
。0f / 0f
或Math.Sqrt(-1)
但是,正如下面的评论者指出的那样,虽然decimal
实际上确实检查了溢出,但是过于接近零是不被认为是溢出,就像浮点数一样。因此,如果您确实需要检查此内容,则必须制作自己的*
和/
方法。但是,对于十进制数字,您不应该非常关心。
如果你需要这种乘法和除法的精度(也就是说,你希望你的除法可以通过乘法来反转),你可能应该使用有理数 - 两个整数(如果需要的话可以是大整数)。并使用checked
上下文 - 这将在溢出时产生异常。
因此,如果您真的关心可逆性等,请坚持理性数字。 decimal
和double
都不起作用,C#也不起作用。如果您 ,那么您无论如何都不应该关心下溢 - 只需选择最低的合理数字,并在其下面声明任何内容,因为"无效&#34 ;;可以肯定你远离实际的最大精度 - double.Epsilon
显然无济于事。
答案 1 :(得分:5)
您需要的只是epsilon
。
这是一个“小数字”,足够小,所以你不再感兴趣了。
您可以使用:
double epsilon = 1E-50;
每当你的一个因素变得比epislon小时,你就会采取行动(例如将其视为0.0)