スポンサーサイト

  • --------(--:--)
  • 上記の広告は1ヶ月以上更新のないブログに表示されています。
    新しい記事を書く事で広告が消せます。

    JavaScriptと小数点の演算誤差と対策

  • 2015-10-06(12:48)
  • 前回の演算誤差の話の続き

    <<結論>>
    ①JavaScriptでは数値は64ビット浮動小数点数形式である。
    よって小数点を含む計算を行うと演算誤差(丸め)が発生する。

    数値が64ビット浮動小数点数形式である根拠
    ECMAScript® 2015 Language Specification
    4.3.20 Number value
    primitive value corresponding to a double-precision 64-bit binary format IEEE 754-2008 value

    NOTE A Number value is a member of the Number type and is a direct representation of a number.


    ②演算誤差対策
    ライブラリ:decimal.jsを使用することに。
    →JavaScript側でDecimalクラスが使用可能になる。

    ■ダウンロード
    https://github.com/MikeMcl/decimal.js/

    ■decimal.jsの使用方法
    1、ダウンロードしたファイルを解凍して、フォルダ内のファイルdecimal.jsをblogにアップロード。
    2、HTML側
    <script type="text/javascript" src="./decimal.js">
    </script>
    3、JavaScript側
     3-1、使い方
      var dec = new Decimal(0.5);
      dec = dec.plus(0.1); // 四則演算子:+
      dec = dec.minus(0.2); // 四則演算子:-
      dec = dec.times(0.3); // 四則演算子:*
      dec = dec.div(0.4); // 四則演算子:/
      var n = dec.toNumber(); // 数字化

    ■その他
    1、Decimalクラスのコンストラクタに非数値を渡すと、例外(Decimal Error)が発生する。
    →Decimalクラスのプロパティ:errorsにfalseを設定すると例外ではなく値:NaNになる。
     Decimal.config({ errors: false });
    2、Decimalクラスは値が変わらない 不変クラスのため、よく使う定数はDecimalクラスに追加する。
     Decimal.ZERO = Decimal.ZERO || new Decimal(0);
     Decimal.HUNDRED = Decimal.HUNDRED || new Decimal(100);

    ■テストパターン
    NGがJavaScriptでの小数点の計算結果
    OKがライブラリのDecimalクラスを使った計算結果
    //--------テストパターン1---------------------
    var NG1 = 0.1 * 0.1; // 0.010000000000000002
    var OK1 = new Decimal(0.1).times(0.1).toNumber(); // 0.01
    //--------テストパターン2---------------------
    var NG2 = 1 - (70/ 100) + (90 / 100); // 1.2000000000000001
    var OK2 = Decimal.ONE.minus(new Decimal(70).div(100)).plus(new Decimal(90).div(100)).toNumber(); // 1.2
    //--------テストパターン3---------------------
    var NG3 = 1 - (84 /100); // 0.16000000000000003
    var OK3 = Decimal.ONE.minus(new Decimal(84).div(100)).toNumber(); // 0.16
    //----------テストパターン4-------------------
    var NG4 = 1 + -51 * 0.02; // -0.020000000000000018
    var OK4 = Decimal.ONE.plus(new Decimal(-51).times(0.02)).toNumber(); //-0.02
    //----------テストパターン5-------------------
    var NG5 = 24716*0.7; // 17301.199999999997
    var OK5 = new Decimal(24716).times(0.7).toNumber(); // 17,301.2
    //----------テストパターン6--------------------
    var NG6 = (0.6179+0.06) * 100; // 67.78999999999999
    var OK6 = new Decimal(0.6179).plus(0.06).times(100).toNumber(); // 67.79
    //--------------------------------------------

    ■検索される方が多いので追記(2016/12/31)
    1,ライブラリ:decimal.jsを使用しているソースコードHTML
    2,Decimalクラスの値を比較時は、string型への暗黙の型変換を抑止するためにDecimal#comparedToメソッドを使用してください。

    ○JavaScript関連
    JavaScriptでemum型ぽいの

    テーマ : プログラミング
    ジャンル : コンピュータ

    コメントの投稿

    非公開コメント

    カテゴリ
    銃 (3)
    琴 (5)
    砲 (9)
    プロフィール

    うみゅ

    Author:うみゅ
    備忘録代わりのメモブログです。
    憶測が大量に含まれています。

    最新記事
    月別アーカイブ
    人気ページ
    検索フォーム
    リンク
    QRコード
    QR
    RSSリンクの表示
    上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。