ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

ActionScript Loungeコミュの丸め誤差(roundoff error)

  • mixiチェック
  • このエントリーをはてなブックマークに追加
Flashcodersの話題より。
[Flashcoders] floor() + ,probably, Math.LN10 bug
http://chattyfig.figleaf.com/pipermail/flashcoders/2005-October/150943.html

var x:Number = 1000;
var nAns0:Number = Math.log(x)/Math.LN10;
trace(nAns0); // 出力: 3
trace(Math.floor(nAns0)); // 出力: 2

いわゆる「丸め誤差(roundoff error)」でしょう。しかし、端数が表示されないと、発見はひと苦労ですね。

参考: F-site「演算結果が半端な値になる(丸め誤差) 」
http://f-site.org/articles/2001/09/18073026.html

trace([Math.log(x), Math.LN10]);
// 出力: 6.90775527898214,2.30258509299405
var nAns1:Number = Math.log(x)*Math.pow(10, 14)/Math.LN10;
trace(nAns1);
// 出力: 300000000000000
trace(Math.floor(nAns1));
// 出力: 299999999999999
trace(nAns0<2.9999999999999998); // 出力: true
trace(nAns0 == 2.9999999999999998); // 出力: false
trace(nAns0 == 2.9999999999999997); // 出力: true
trace(nAns0 == 2.9999999999999996); // 出力: true
trace(nAns0 == 2.9999999999999995); // 出力: true
trace(nAns0 == 2.9999999999999994); // 出力: true
trace(nAns0 == 2.9999999999999993); // 出力: false
trace(nAns0>2.9999999999999993); // 出力: true

なお、Math.log(x)/Math.LN10は、対数の「底の変換」と呼ばれる計算です。Math.log(x)はxの自然対数(底e)、Math.LN10は同じく10の自然対数を表わします。

参考:「対数の性質」
http://www.geocities.co.jp/Milano/1115/juken/taisu_seishitsu.html

log(e)x / log(e)10 = log(10)x …ここでは括弧()は底の意
x = 1000のとき
log(10)1000 = 3

つまり、10を1,000にするには、3乗すればよいということです。

コメント(5)

丸め誤差に関する議論が、FLASH-japanとFlashcodersにそれぞれ上がりましたので、参照として加えておきます。

FLASH-japan「MovieClipの座標の比較について」
http://www.flash-jp.com/modules/newbb/viewtopic.php?viewmode=flat&topic_id=4846&forum=6

[Flashcoders] Flash Maths bug???
http://chattyfig.figleaf.com/pipermail/flashcoders/2006-April/thread.html#164862
FLASH-japanで話題になっています。ただ、少々迷走気味のようです。

「四捨五入(Math.round )の挙動・・?」
http://www.flash-jp.com/modules/newbb/viewtopic.php?viewmode=flat&topic_id=5436&forum=6

0.5以上を切上げて0.5未満を切捨てる「四捨五入」と、0.5を足して小数値を除く「切捨て」は「論理的に」同値です。0.5を加えることによって丸め誤差が回避できる言語があるのでしょうか? そのあたりの情報がありましたら、お教えください。

文字列に変換するというのは、多少強引ですが、場合によっては採りうる手段のひとつでしょう。もっとも、0.5を加える必要など、もちろんありません。

var a = 100.0;
var b2 = 1.255;
trace(Math.round(a*b2)); // 出力: 125
trace(Math.round(parseFloat((a*b2).toString()))); // 出力: 126

けれど、一番確実なのは、必要な桁数より小さく、誤差の生じる桁数よりは大きい桁で四捨五入することだと思います。

var a = 100.0;
var b2 = 1.255;
var diff = a*b2-125.5;
trace(diff); // 出力 -1.4210854715202e-14
var n = Math.pow(10, 13);
trace(diff*n); // 出力 -0.14210854715202
trace(Math.round(Math.round(a*b2*n)/n)); // 出力 126
>> 3: ホンさん
情報ありがとうございます。

> 丸め誤差が生じないように設計された「通貨型(Currency型)」というデータ型が用意されています。
_____
有効桁数は、どれくらいなのですか? 想像するに、十分な桁数で計算はしつつ、結果として使用・表示する桁数を制限することで、誤差を回避しているのではないかという感じがするのですけど。

> 上記の言語でも浮動小数点数型 (Single、Double)は丸め誤差が生じます。これはIEEE 754の規定通りです。
_____
そうですよね。コンピュータの処理する桁数が有限であるかぎり、論理上生じる結果だと思います。

> コンピューターの指も10本ならいいのに、現状では仕方ないですね。
_____
10進法でも、誤差は発生すると思います。ただ、その誤差が人間にとって納得しやすく、そんな誤差が「許されるわけない」といった勘違いにはつながりにくいということですね。逆に、10進法なら生じる誤差が、防げる場合もあります。

a = 1;
b = 3;
c = a/b;
trace(c); // 出力: 0.333333333333333
d = c*b;
trace(d); // 出力: 1

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

ActionScript Lounge 更新情報

ActionScript Loungeのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。