Channel J

電脳硬化症気味な日記です。まとまった情報は wiki にあります。

2010.7.23 (Friday)

at 15:02  

JavaScriptの2進数演算による誤差   [ICTメモ]

 JavaScriptの2進数演算による誤差についてメモ。

  a = 4.321 * 100;

を計算すると、期待値「432.1」に反して、「432.099999999999996」になります。
 四捨五入で対応しようとして、

  b = Math.round(4.321 * 100 * 10) / 10;

とすると、「432.1」が得られますが、同じ式で

  c = Math.round(4.9999 * 100 * 10) / 10;

の結果は、期待値「499.99」ではなく「500」になってしまいます。
 そこで、Decimal的(文字列)操作を関数化したもの(decimaloperater.js)を使って、

  d = trimFixed(4.9999 * 100);

とすると、正しく「499.99」が得られるようです。動作している処理系で扱える有効桁数を目一杯使っているかどうかで、丸めるかどうかを判定しています。演算結果に対しての処理なので、これなら除算もOK。すばらしい!

 もっと、厳密にやりたいってヒトは、JavaScript用のBigDecimalクラスを使うのがいいのでしょうかね。版権的にどうなのかわからないのですけど。。。IBM?

  e = new BigDecimal("4.321").multiply(new BigDecimal("100"))

« 牛丼戦争(真夏編) MySQL upgrade »

Comments

  1. 御記事を見て、trimFixedの短縮版を思いついたので書き込みます。ご笑覧ください。

    function trimFixed(value) {
    // 与えられた数値の整数部または小数部の桁数を返す
    function l(v, p){ return (v + ‘’).split(’.')[p].length; }

    // 1/3の有効桁数からvalueの整数部の桁数を引く
    var digits = l(1 / 3, 1) - l(Math.abs(value), 0);
    var pow = Math.pow(10, digits);
    return Math.round(value * pow) / pow;
    }

    Comment by 2010.7.28 (Wednesday) @ 00:47

  2.  おぉっ! とても短く洗練されてますね!
     Math.round()するときに、処理系最大有効桁数で丸めれば良いってことですね、なるほど。桁数算出処理も短いコードで素晴らしい!
     恐縮ながら、想定どおりの結果が出力されることを確認しました。コード量が少ないこちらの方が、実利用するには格段に良いですね。勉強させて頂きありがとうございます。(mathHelper.js)

    Comment by じょもら 2010.7.28 (Wednesday) @ 02:27

  3. 【追伸】短縮版において、

    f = trimFixed(5.4 - 3.21);

    等の減算で誤差が出てしまう("2.190000000000001"になる)ようです。利用可能桁数を1減らすのがよいかと思っています。

    var digits = l(1 / 3, 1) - l(Math.abs(value), 0) - 1;

    Comment by じょもら 2010.8.3 (Tuesday) @ 12:00

Leave a Comment

改行や段落は自動です URLとE-mailは自動的にリンクされますので、<a>タグは不要です。
HTML allowed: <b> <i> <strong> <em> <code> <blockquote> <p> <br> <strike> <a>


Go back.
Edit this post.