最近查看一段代码时,我遇到了一条让我思考的问题:
if a*b > 0:
# do stuff
应该假设a
和b
是浮点数。
问题:
是否存在a
和b
的非常小的,正的,可能接近~ep_mach的值,使得它们的产品是负的?如果没有,我们可能a*b==0
同时没有a==0
或b==0
。
不要完全懈怠,这是我的想法:
不可以,因为在FP算术中,产品很可能被定义为a
和b
的符号位确定a*b
的符号位。因此,在某些基级,计算运行“a
的注释符号位为正。注意b
的符号位为正。将a*b
的符号位设置为正。”我想这个约定是指定的,并且在它存在的情况下被普遍分类某处。
a*b==0
a!=0
和b!=0
似乎无疑是可能的。
答案取决于计算机和语言。
这引出了一个子问题:
问题:
实现下面的代码会更安全吗?如果它不安全,那该怎么办呢?
if (a>0 and b>0) or (a<0 and b<0):
# do stuff
答案 0 :(得分: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();
}
}
答案 1 :(得分:2)
根据IEEE-754标准(使用默认舍入模式),任何浮点运算(blah blah transcendentals)的结果四舍五入到最接近的可表示数字。任何两个正数的乘积都是正数,因此最坏的情况是,最接近的可表示数字为零。最接近的可表示数字无法为负数。
您建议的替代代码是正确的。对于具有sgn
/ signum
功能的语言,您还可以执行if sgn(a)*sgn(b) > 0
之类的操作。