Java Puzzlers 之Puzzle 1: Oddity

Puzzle 1: Oddity

下面的方法就是用来判断唯一的一个参数是否为奇数,这个方法生效吗?

 

public static boolean isOdd(int i) {
        
        
    return i % 2 == 1;
        
        

}

 

Solution 1: Oddity

可以这样来判断奇数:一个整数被2除后余数为1。表达式i%2就是计算i2除后的余数,所以这个程序似乎看起来应该生效。不幸的是,它没有;它有四分之一的时间返回了错误的答案。

为什么是四分之一? 因为一半的int值是负数,所以isOdd方法对所有的负奇数判断失败。对于任何负数,甚至为奇数时,它也始终返回false。这是java对于取余操作符(%)的逻辑定义。它按照以下的恒等式来定义任何inta和任何非零intb

 

(a / b) * b + (a % b) == a

 

换句话说,如果你用b来除a,再用b来乘以商,然后加上ab的余数,你就能得到原来的数a。这个等式说明的很清楚,但是结合Java截取整型除法运算来看,它暗示了当取余操作返回一个非零的结果时,它同操作符左边的数具有同样的符号。

isOdd方法以及对于奇数的定义都是在假设所有的余数为正数的基础上的。尽管这种假设很符合某些形式的除法,但是Java取余操作符是完全与整型除法运算一致,它抛弃了结果的小数部分。

如果i是一个负奇数,i%2就等于-1而不是1,因此isOdd方法就会错误的返回false,相反地比较如下:

 

public static boolean isOdd(int i) {

 

    return i % 2 != 0;

 

}

 

如果你在把isOdd方法使用在一个临界的设置中,你最好使用按位AND操作符(&)来代替取余操作符:

 

public static boolean isOdd(int i) {

    return (i & 1) != 0;

}

 

第二个版本中可能运行的比第一个版本快,这得依赖于运行的平台和你使用的虚拟机,但是不可能运行的更慢。总的来说,除法和取余操作要比其他算术和逻辑运算慢。过早的优化并不是个好主意,但是在上面这个情形下,运行较快的版本是很清晰明白的,没有理由更喜欢这种原始的计算。

总之,在你使用取余操作时,你总是得思考操作数的符号以及计算的结果。当操作数为非负数时,这个很明显,但是当其中一个或者两个操作数都是负数时,就不是那么明显了。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值