1.3.32 Ramanujan的出租车
Srinivasa Ramanujan是著名的印第安数学家,他以对数字的直觉而闻名。一天当英国数学家G.H.Hardy来拜访他,Hardy谈论他乘坐的出租车号是1729,一个相当无趣的数字。而Ramanujan回答,”不,Hardy!不,Hardy!“,这是一个非常有趣的数字。在两种不同方式中,这是可以表示成两个数的立方和的最小数字。验证这个断言。通过编写程序,使用命令行参数N,并显示所有小于或等于N的整数,这些整数可以使用两种不同的方式来表达两个数立方和。换句话说,找到不同正整数a b c d,如a^3+b^3=c^3+d^3。
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
for (int a = 1; a < n; a++) {
for (int b = 1; b < n; b++) {
for (int c = 1; c < n; c++) {
for (int d = 1; d < n; d++) {
if (a == b || a == c || a == d || b == c || b == d || c == d)
continue;
int sum = a * a * a + b * b * b;
if (sum == c * c * c + d * d * d) {
System.out.printf("%d = %d^3+%d^3 = %d^3+%d^3\n", sum, a, b, c, d);
}
}
}
}
}
}
}
1.3.33 检验和
国际标准书号(ISBN)是独特地指定书的10位数代码。最右的位是校验和位,它可以根据其他9位数确定,条件是d1+2d2+3d3+..+10d10必须是11的倍数。校验和位di可以是从0到10的任何一个值。国际标准书号的惯例是使用字符X表示10。编写一个程序,使用来自命令行的9位整数,计算校验和并打印国际标准书号的数字。
public class Main {
public static void main(String[] args) {
String s = args[0];
if (s != null && s.length() != 9) {
System.out.println("error");
return;
}
int sum = 0;
for (int i = 0; i < 9; i++) {
int n = s.charAt(i) - '0';
sum += (i + 1) * n;
}
for (int i = 0; i <= 10; i++) {
if ((sum + 10 * i) % 11 == 0) {
if (i < 10)
System.out.println(s + i);
else
System.out.println(s + "X");
}
}
}
}
1.3.34 计算素数
编写程序,使用来自命令行参数N,找到小于或等于N的素数。运行这个程序来打印小于或等于1亿的素数。
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
if (n > 2)
System.out.print(2 + " ");
for (int i = 3; i < n; i += 2) {
boolean isprime = true;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
isprime = false;
break;
}
}
if (isprime)
System.out.print(i + " ");
}
}
}
1.3.35 二维随机行走
二维随机行走模拟微粒在点栅格移动的行为。在每一步,随机行走可以直到北部、南部、东部或西部,概率均为1/4,独立前面的移动。编写一个程序,使用命令行参数并估计从2N*2N的正方形中心出发,到正方形边界,行走需要多长时间。
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
int count = 0;
int x = 0, y = 0;
while (x != n && x != -n && y != n && y != -n) {
double rand = Math.random();
if (rand < 0.25)
++x;
else if (rand < 0.50)
--x;
else if (rand < 0.75)
++y;
else
--y;
++count;
}
System.out.println(count);
}
}
1.3.36 指数函数
假设x是double类型的正变量。编写程序,使用泰勒级数扩展来计算e^x。
public class Main {
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double term = 1.0;
double sum = 0.0;
for (int i = 1; sum != sum + term ; i++) {
sum += term;
term *= x / i;
}
System.out.println(sum);
System.out.println(Math.exp(x));
}
}
1.3.37 三角函数
使用泰勒级数计算sin x。
public class Main {
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double term = x;
double sum = 0.0;
double sign = 1;
for (int i = 1; sum != sum + term ; i += 2) {
sum += term * sign;
term *= x * x / ((i + 1) * (i + 2));
sign = -sign;
}
System.out.println(sum);
System.out.println(Math.sin(x));
}
}
1.3.39 Pepys问题
在1693 Samuel Pepys问Isaac Newton,哪个更有可能:投6次骰子,至少1次可得到1,或投12次骰子,至少得到2次1。编写一个程序,能让牛顿快速地回答这个问题。
public class Main {
public static void main(String[] args) {
int count1 = 0, count2 = 0;
for (int i = 0; i < 1000000; i++) {
for (int j = 0; j < 6; j++) {
long n = Math.round(Math.random() * 100) % 10;
if (n == 0)
++count1;
}
for (int j = 0; j < 12; j++) {
long n = Math.round(Math.random() * 100) % 10;
if (n == 0)
++count2;
}
}
System.out.printf("%d %d\n", count1, count2);
}
}
1.3.40 游戏模拟
在20世纪70年代电视知识竞赛”让我们做个交易“,给竞争者提供3个门。在其中的一扇门后有可观的奖金。在竞争者选择一扇门之后,主持人打开另外两个门之一(当然从未出现过奖金)。然后给竞争都提供机会来换成另一个未打开的门。竞争者应该如何做呢?直觉可能认为竞争者最初挑选的门和另一扇未打开的门都同样可能包含奖金,因此不需要换一扇门。编写一个程序MonteHall来测试这种直觉的模拟。程序应该使用命令行参数N,并使用两个策略之一(换门或不换门)来玩N次这个游戏,并打印每一种策略的成功机会。
public class Main {
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
int count1 = 0, count2 = 0;
for (int i = 0; i < n; i++) {
int door = (int) (Math.random() * 100) % 3;
int choice = (int) (Math.random() * 100) % 3;
int rest = 0;
if (door == choice) {
switch (door) {
case 0:
rest = 1;
break;
case 1:
rest = 2;
break;
case 2:
rest = 0;
break;
}
} else {
rest = door;
}
if (choice == door) ++count1;
if (rest == door) ++count2;
}
System.out.println("不换门:" + count1);
System.out.println("换门:" + count2);
}
}
1.3.41 五个数的中值。
编写一个程序,使用5个来自命令行的不同整数,并打印中值(这个值比其中的两个小但比其余的两个大)。
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] num = new int[args.length];
for (int i = 0; i < num.length; i++) {
num[i] = Integer.parseInt(args[i]);
}
Arrays.sort(num);
System.out.println(num[num.length / 2]);
}
}