2017-09-30 41 views
1

当一段代码最近看,我碰到一条线,让我思考:两个正漂浮物的产物是否为负?

if a*b > 0: 
    # do stuff 

应当假定ab是浮动。

问:
是否可能存在(非常小的,积极的,并有可能接近〜eps_mach)的a价值观和b,使得他们的产品是负的?如果不是,是否可以是a*b==0既不是a==0也不是b==0

为了不成为一个完整的懈怠,这里是我的想法:

  1. 不,这是可能的,因为在FP算术产品以这样的方式可能定义的a符号位和b确定a*b的符号位。因此,在一些基本级别上,计算运行“a的注释符号位是正值,注意符号位b是正值,将符号位a*b设置为正值。我想象这个约定被指定和普遍分类某处只要它存在。

  2. a*b==0a!=0b!=0似乎当然有可能。

  3. 答案将取决于计算机和语言。

这使我一个子问题:

问:
难道是更安全的实施,因为下面的代码?如果不安全,那该怎么办?

if (a>0 and b>0) or (a<0 and b<0): 
    # do stuff 
+0

@old_timer为什么你会想到为NaN,而不是正无穷大? –

+0

@old_timer IEEE754要求无穷大,正如Java语言规范一样。其他语言可能会做一些奇怪的事情,但我通常会期待无限。它有所不同,因为NaN> 0与所有NaN比较一样是错误的。 –

+0

我删除我的意见。 –

回答

2

根据IEEE-754标准(默认舍入模式),任何浮点操作的结果(等等等等超越数)被舍入到最接近的表示的数。任何两个正数的乘积都是正数,所以最坏的情况下,最接近的数字是零。无法将最接近的可表示数字设为负数。

您提出的替代代码是正确的。对于具有sgn/signum函数的语言,您还可以执行诸如if sgn(a)*sgn(b) > 0之类的操作。

+0

非常好!非常感谢你。 – floater

3

这两段代码并不等价,因为两个正数但小数的乘积确实可以为零。

这是正确的取决于测试的真正内容。

如果后续代码需要产品严格肯定,则需要a*b > 0表单,而不是测试各个值。

如果每个值都需要严格肯定,请对此进行测试。

如果要求它们都是非零且具有相同符号,那么您提出的测试是正确的。

下面是一些测试的情况下,包括Java程序都很小,但严格正:

public class Test { 
    public static void main(String[] args) { 
    testit(Double.MIN_VALUE, Double.MIN_VALUE); 
    testit(-Double.MIN_VALUE, -Double.MIN_VALUE); 
    testit(1e-320, 1e-320); 
    testit(1e300, 1e300); 
    } 

    public static void testit(double a, double b) { 
    System.out.println("a="+a+" b="+b); 
    System.out.println("a*b > 0 " + (a * b > 0)); 
    System.out.println("(a>0 && b>0) " + (a > 0 && b > 0)); 
    System.out.println("(a<0 && b<0) " + (a < 0 && b < 0)); 
    System.out.println(); 
    } 
} 
+0

啊,是的。我的问题有一个呃逆。我列出的最初测试是确定a或b中的一个是否定的“捷径”。它现在已经被证实是危险的,它越过了我的想法。 – floater