Java的困惑-1

来源:互联网 发布:换手机壁纸的软件 编辑:程序博客网 时间:2024/05/21 04:22

是不是觉得国产翻译很多经典书籍都搞杂了,我见这本Java Puzzle不错。网上有英文下载,台湾有个蔡先生好像翻译了繁体《java解惑》 。我决定用一种简单的中文语法来翻译,让初学java的人都能看懂我在说什么。如果你看到我在翻译中有误认子弟的严重错误,请务必通知我。因为我也不是很懂哈。email:goddie2046@gmail.com

这本书有很多章节,慢慢来。

英文原文:

--------------------------------------------

Puzzle 1: Oddity

The following method purports to determine whether its sole argument is an odd number. Does the method work?

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


 

Solution 1: Oddity

An odd number can be defined as an integer that is divisible by 2 with a remainder of 1. The expression i % 2 computes the remainder when i is divided by 2, so it would seem that this program ought to work. Unfortunately, it doesn't; it returns the wrong answer one quarter of the time.

Why one quarter? Because half of all int values are negative, and the isOdd method fails for all negative odd values. It returns false when invoked on any negative value, whether even or odd.

This is a consequence of the definition of Java's remainder operator (%). It is defined to satisfy the following identity for all int values a and all nonzero int values b:

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


 

In other words, if you divide a by b, multiply the result by b, and add the remainder, you are back where you started [JLS 15.17.3]. This identity makes perfect sense, but in combination with Java's truncating integer division operator [JLS 15.17.2], it implies that when the remainder operation returns a nonzero result, it has the same sign as its left operand.

The isOdd method and the definition of the term odd on which it was based both assume that all remainders are positive. Although this assumption makes sense for some kinds of division [Boxing], Java's remainder operation is perfectly matched to its integer division operation, which discards the fractional part of its result.

When i is a negative odd number, i % 2 is equal to -1 rather than 1, so the isOdd method incorrectly returns false. To prevent this sort of surprise, test that your methods behave properly when passed negative, zero, and positive values for each numerical parameter.

The problem is easy to fix. Simply compare i % 2 to 0 rather than to 1, and reverse the sense of the comparison:

public static boolean isOdd(int i) {    return i % 2 != 0;}


 

If you are using the isOdd method in a performance-critical setting, you would be better off using the bitwise AND operator (&) in place of the remainder operator:

public static boolean isOdd(int i) {    return (i & 1) != 0;}


 

The second version may run much faster than the first, depending on what platform and virtual machine you are using, and is unlikely to run slower. As a general rule, the divide and remainder operations are slow compared to other arithmetic and logical operations. It's a bad idea to optimize prematurely, but in this case, the faster version is as clear as the original, so there is no reason to prefer the original.

In summary, think about the signs of the operands and of the result whenever you use the remainder operator. The behavior of this operator is obvious when its operands are nonnegative, but it isn't so obvious when one or both operands are negative.

 

-------------------------

 

goddie翻译

-----------------------------

Puzzle 1:  Oddity 
困惑1 : 奇数?

 

下面的isOdd(int i)方法是用来判断i是否是一个奇数。有没用啊?请看:

public static boolean isOdd(int i) {

    return i % 2 == 1;

}

Solution 1: Oddity  (奇数)
解决方案1: 奇数

奇数的定义是:被2除余1的整数。连火星人都知道,表达式: i % 2 是用来计算i被2除所得余数,你会说来上面那个代码不是挺好吗?其实不是

,或者说效果不是很好。这段代码有四分之一的情况要返回一个错误的结果。

为什么是四分之一?

因为二分之一的整数是负数,二分之一的整数是正数。而上面这个 isOdd(int i) 方法,当i是负数的时候就运行不正确了。如果i是负数,无

论i是负奇数还是负偶数,这个方法都是返回 false 。

下面是一个关于Java求余运算符(%)的判定式。

求余运算符(%)是从这个式子反推出来的(其中a是整数,b是非零整数):

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

也就是说 % 运算满足这个条件:如果a除以b,商乘以b,再加上 a % b 的值,最终结果必须等于a。

这个式子不仅非常合理,而且是刚好用到了Java中的整除运算符。
从这个判定式还能推出:当求余运算得到一个非零结果c的时候,求余运算符(%)左边的数a和这个结果c应该是同符号(同为正数,或者同为负

数,或者零)。

上面的 isOdd(int i) 方法和当中所谓的“奇数”都是假定求余运算所得的值都是正数。虽然这个假设适用于一部分情况,但是Java中的求余

运算是和她的整除是完美统一的,而Java中的整除并没有限定整数的符号。

如果isOdd(int i)方法中的 i 是一个负奇数,i % 2 结果应该是 -1 而不是 1 ,这时候 isOdd(int i) 返回的就是一个错误的结果:false。

为了避免这种错误,应该在代码写好之后用各种数字(整数,负数,零)来完整测试你的代码。

这个 isOdd(int i) 方法存在的问题很容易搞定。只要判断 i % 2 是不是等于零。

public static boolean isOdd(int i) {

    return i % 2 != 0;

}

如果你要在一个性能要求很苛刻的环境中使用 isOdd(int i) 方法的话,使用“逻辑与”运算符(&)来取代求余运算符(%)会更好一些:

public static boolean isOdd(int i) {

    return (i & 1) != 0;

}


第二种版本运行起来一般会比第一种版本快。至于快多少取决于你的虚拟机,总不可能会比第一版慢吧。一般规律都是:除法运算和求余运算

都比其他的算术运算和逻辑运算速度慢(CPU都是做加法运算的。乘法不用做太多转换,相当于几个加法。)。时时刻刻都想着优化代码并不是

好事,别人会看不懂你写的代码。我们这个例子比较好,第二个快的版本和第一版都比较易读,因此没理由还使用第一版。

最后概括一下好不?

1.当你使用求余运算的时候记得多考虑运算数和结果的符号。
2.当运算数都是非负数的时候,求余运算代码的执行动作都是很明显;但是如果有些数字是负数的时候代码的执行就不是那么明显了。


goddie:

看不惯国产的垃圾翻译,很多经典都被糟蹋了。完全是翻译来好玩,如果你觉得有误人子弟的地方请务必通知我: goddie2046@gmail.com

------------------------------

 

完成