パイこね変換
「渋滞学」という本を読んでなかなか面白かった。その中で、「パイこね変換」というのが、「コンピュータが簡単な計算でも間違える例」として紹介されていた。
http://tftf-sawaki.cocolog-nifty.com/blog/2006/11/post_b8e3.html
(*)本書に出てくる「パイこね変換」の例
(1) まず0から1までの範囲の数xを決める
(2) xが0.5よりも小さければ y=2xとし、そうでなければ y=2-2xとする
(3) 求めたyをxに代入し、(2)に戻って計算を繰り返す
例えば最初に x=0.1とすると、本来は0.4と0.8でずっと振動するはずが、数十回の計算で0になってしまう
Javaで書くとこんな感じ
public class Pankone {
public static void main(String[] args) {
double num = 0.1;
for(int i=0; i<1000; i++){
num = calc(num);
System.out.println(i + "回目:" + num);
if(num == 0){
break;
}
}
}
static double calc(double num){
if(num > 0.5){
return 2 - 2 * num;
}else{
return 2 * num;
}
}
}
実行結果。たしかに100回もやらずに0になる。
0回目:0.2 1回目:0.4 2回目:0.8 3回目:0.3999999999999999 4回目:0.7999999999999998 5回目:0.40000000000000036 6回目:0.8000000000000007 ...(中略) 50回目:0.8125 51回目:0.375 52回目:0.75 53回目:0.5 54回目:1.0 55回目:0.0
ちゅうか、それって単に浮動小数点の丸め誤差の問題じゃないか。
例えば10倍して整数にしてやると、
public class Pankone2 {
final static long MP = 10;
public static void main(String[] args) {
long num = (long)(0.1 * MP);
for(int i=0; i<1000; i++){
num = calc(num);
System.out.println(i + "回目:" + num);
if(num == 0){
break;
}
}}
static long calc(long num){
if(num > 0.5 * MP){
return 2*MP - 2 * num;
}else{
return 2 * num;
}
}
}
ちゃんと、4と8を繰り返すよー
0回目:2 1回目:4 2回目:8 3回目:4 4回目:8 ...(以下略)
それはコンピュータが計算を正しく行えないのでなく、弱点をついて変な計算をやらしてるだけ?ある意味
int a = (int)0.5
が0になるコンピュータなんて!みたいな。
と、書いてみて、「コンピュータは素早く正確に計算するもんだ」という一般常識に「必ずしもそうでない場合もある」というという例を示しているだけのとこに、しょうもないつっこみをしたなー、という気もしたりして。
いや、なんかモンティーホールパラドックスみたいな驚きを求めていたのだが、いまいちだった。。。