仔细观察下面这个语句:
char c = (char)(Math.random() * 26 + 'a');
Math.random()会产生一个 double 值,所以 26 会转换成 double 类型,以便执行乘法
运算。这个运算也会产生一个 double 值。这意味着为了执行加法,必须将'a'转换成一个
double。最后使用显式的类型转换将 double 结果转换回 char。
// What happens when you cast a float
// or double to an integral value?
import com.bruceeckel.simpletest.*;
public class CastingNumbers {
static Test monitor = new Test();
public static void main(String[] args) {
double
above = 0.7,
below = 0.4;
System.out.println("above: " + above);
System.out.println("below: " + below);
System.out.println("(int)above: " + (int)above);
System.out.println("(int)below: " + (int)below);
System.out.println("(char)('a' + above): " +
(char)('a' + above));
System.out.println("(char)('a' + below): " +
(char)('a' + below));
monitor.expect(new String[] {
"above: 0.7",
"below: 0.4",
"(int)above: 0",
"(int)below: 0",
"(char)('a' + above): a",
"(char)('a' + below): a"
});
}
} ///:~
所以答案就是:将一个 float 或 double 值转型成整数值后,总是将小数部分“砍掉”(而不是
四舍五入)。
第二个问题与 Math.random()有关。它会产生 0 和 1 之间的值,但是否包括值'1'呢?用正
规的数学语言表达,它到底是(0,1)、[0,1]、(0,1),还是[0,1)呢(方括号表示“包括”,圆括号
表示“不包括”)?同样地,一个示范程序向我们揭示了答案:
//: c03:RandomBounds.java
// Does Math.random() produce 0.0 and 1.0?
// {RunByHand}
public class RandomBounds {
static void usage() {
System.out.println("Usage: \n\t" +
"RandomBounds lower\n\tRandomBounds upper");
System.exit(1);
}
public static void main(String[] args) {
if(args.length != 1) usage();
if(args[0].equals("lower")) {
while(Math.random() != 0.0)
; // Keep trying
System.out.println("Produced 0.0!");
}
else if(args[0].equals("upper")) {
while(Math.random() != 1.0)
; // Keep trying
System.out.println("Produced 1.0!");
}
else
usage();
}
} ///:~
为运行这个程序,只需在命令行键入下述命令即可:
java RandomBounds lower
或
java RandomBounds upper
在这两种情况下,我们都必须人工中断程序,所以会发现Math.random()“似乎”永远都不
会产生 0.0 或 1.0。但这正是实验可能欺骗我们的地方。要知道 0 和 1 之间有 262个不同
的双精度小数2,如果产生全部的数字,花费的时间会超过一台电脑,甚至做此试验的人的
char c = (char)(Math.random() * 26 + 'a');
Math.random()会产生一个 double 值,所以 26 会转换成 double 类型,以便执行乘法
运算。这个运算也会产生一个 double 值。这意味着为了执行加法,必须将'a'转换成一个
double。最后使用显式的类型转换将 double 结果转换回 char。
寿命。事实是,在Math.random()的输出中包括了 0.0,用数学语言,输出值范围是[0,1)。
//: c03:CastingNumbers.java// What happens when you cast a float
// or double to an integral value?
import com.bruceeckel.simpletest.*;
public class CastingNumbers {
static Test monitor = new Test();
public static void main(String[] args) {
double
above = 0.7,
below = 0.4;
System.out.println("above: " + above);
System.out.println("below: " + below);
System.out.println("(int)above: " + (int)above);
System.out.println("(int)below: " + (int)below);
System.out.println("(char)('a' + above): " +
(char)('a' + above));
System.out.println("(char)('a' + below): " +
(char)('a' + below));
monitor.expect(new String[] {
"above: 0.7",
"below: 0.4",
"(int)above: 0",
"(int)below: 0",
"(char)('a' + above): a",
"(char)('a' + below): a"
});
}
} ///:~
所以答案就是:将一个 float 或 double 值转型成整数值后,总是将小数部分“砍掉”(而不是
四舍五入)。
第二个问题与 Math.random()有关。它会产生 0 和 1 之间的值,但是否包括值'1'呢?用正
规的数学语言表达,它到底是(0,1)、[0,1]、(0,1),还是[0,1)呢(方括号表示“包括”,圆括号
表示“不包括”)?同样地,一个示范程序向我们揭示了答案:
//: c03:RandomBounds.java
// Does Math.random() produce 0.0 and 1.0?
// {RunByHand}
public class RandomBounds {
static void usage() {
System.out.println("Usage: \n\t" +
"RandomBounds lower\n\tRandomBounds upper");
System.exit(1);
}
public static void main(String[] args) {
if(args.length != 1) usage();
if(args[0].equals("lower")) {
while(Math.random() != 0.0)
; // Keep trying
System.out.println("Produced 0.0!");
}
else if(args[0].equals("upper")) {
while(Math.random() != 1.0)
; // Keep trying
System.out.println("Produced 1.0!");
}
else
usage();
}
} ///:~
为运行这个程序,只需在命令行键入下述命令即可:
java RandomBounds lower
或
java RandomBounds upper
在这两种情况下,我们都必须人工中断程序,所以会发现Math.random()“似乎”永远都不
会产生 0.0 或 1.0。但这正是实验可能欺骗我们的地方。要知道 0 和 1 之间有 262个不同
的双精度小数2,如果产生全部的数字,花费的时间会超过一台电脑,甚至做此试验的人的
寿命。事实是,在Math.random()的输出中包括了 0.0,用数学语言,输出值范围是[0,1)。