将双值与零比较时,我们需要小心吗?
if ( someAmount <= 0){ ..... }
Crashworks.. 18
如果你想要非常小心,你可以用类似的东西测试它是否在零的epsilon中
double epsilon = 0.0000001; if ( f <= ( 0 - epsilon ) ) { .. } else if ( f >= ( 0 + epsilon ) ) { .. } else { /* f "equals" zero */ }
或者,您可以在分支之前简单地将双打舍入到指定的精度.
有关比较浮点数误差的一些有趣细节,这是Bruce Dawson的一篇文章.
如果你想要非常小心,你可以用类似的东西测试它是否在零的epsilon中
double epsilon = 0.0000001; if ( f <= ( 0 - epsilon ) ) { .. } else if ( f >= ( 0 + epsilon ) ) { .. } else { /* f "equals" zero */ }
或者,您可以在分支之前简单地将双打舍入到指定的精度.
有关比较浮点数误差的一些有趣细节,这是Bruce Dawson的一篇文章.
对于平等:(即==
或!=
)是.
对于其它比较运算符(<
,>
,<=
,>=
),这取决于是否是关于边缘的情况下,例如是否<
是相当于<=
,这是平等的另一种情况.如果你不关心边缘情况,它通常无关紧要,尽管它取决于输入数字的来源以及它们的使用方式.
如果您期望(3.0/10.0) <= 0.3
评估为true
(如果浮点错误导致3.0/10.0评估为略大于0.3的数字,如0.300000000001,则可能不会),并且如果计算结果,您的程序将表现不佳false
- 这是一个边缘情况,并且你需要小心.
好的数值算法几乎不应该依赖于相等和边缘情况.如果我有一个算法作为输入' x
',它是0到1之间的任何数字,一般来说无论是否为0 < x < 1
或者0 <= x <= 1
.但也有例外:在评估具有分支点或奇点的函数时必须小心.
如果我有一个中间数量y
而且我期待y >= 0
,并且我评估sqrt(y)
,那么我必须确定浮点错误不会导致y成为一个非常小的负数和sqrt()
抛出错误的函数.(假设这是一个不涉及复数的情况.)如果我不确定数值误差,我可能会评估sqrt(max(y,0))
.
对于像1/y
或者这样的表达式log(y)
,在实际意义上,y是否为零(在这种情况下,你得到奇点误差)或者y是一个非常接近零的数字并不重要(在这种情况下,你会得到一个非常大的数字,其大小是y的值非常敏感) -这两种情况下都是"坏"从数字的角度来看,我需要重新评估它就是我想要做的,什么行为我正在寻找,当y
值在零附近.
根据您someAmount
的计算方式,您可能会发现浮点/双精度的一些奇怪行为
基本上,使用float/double将数值数据转换为二进制表示是容易出错的,因为有些数字不能用螳螂/指数表示.
有关这方面的一些细节,您可以阅读这篇小文章
您应该考虑使用java.lang.Math.signum
或java.math.BigDecimal
特别是货币和税收计算
注意自动拆箱:
Double someAmount = null; if ( someAmount <= 0){
Boom,NullPointerException.