Java精密計算:BigDecimalクラス

4084 ワード

1.「Effactive Java」という本を引用すると、floatとdoubleタイプの主な設計目標は科学計算とエンジニアリング計算である.広域数値範囲でより正確な高速近似計算を提供するために丹念に設計されたバイナリ浮動小数点演算を実行した.しかし、それらは完全に正確な結果を提供していないので、正確な結果を要求する場合に使用されるべきではない.しかし、ビジネスコンピューティングでは結果の正確さが求められることが多いので、BigDecimalが役に立ちます.
2.BigDecimal概要BigDecimalは、任意の精度の整数非スケール値と32ビットの整数スケール(scale)からなる.ゼロまたは正の場合、スケールは小数点以下の桁数です.負数の場合、その数の非スケール値に10の負のscale乗を乗算します.したがって、BigDecimalが表す数値は(unscaledValue)× 10-scale).
3.テストコード3.1コンストラクション関数(主なテストパラメータタイプはdoubleとStringの2つの共通コンストラクション関数)BigDecimal aDouble=new BigDecimal(1.22);System.out.println(“construct with a double value: ” + aDouble); BigDecimal aString = new BigDecimal(“1.22”); System.out.println(“construct with a String value: ” + aString); 出力結果はどうなると思いますか?最初に1.22が出力されると思っていない場合は、おめでとうございます.出力結果は、construct with a doublevalue:1.219999999999999999999733546474089962430298328399658203125 construct with a String value:1.22 JDKの説明:1、パラメータタイプがdoubleの構造方法の結果に一定の予知性があります.JavaにnewBigDecimal(0.1)を書き込んで作成されたBigDecimalは、ちょうど0.1(スケール値1ではなく、スケール値1)に等しいと考えられているかもしれませんが、実際には0.100000000000555123125782702181583404541015625に等しくなります.これは、0.1をdoubleと正確に表すことができないためである(または、この場合、任意の限られた長さのバイナリ小数として表すことができない).これにより、構造方法に入力される値は、表面的には0.1に等しくない.2.一方、String構造方法は完全に予知可能である:newBigDecimal(「0.1」)を書き込むと、予想される0.1に等しいBigDecimalが作成される.したがって、比較的には、通常、String構造方法を優先的に使用することが推奨される.3、doubleがBigDecimalのソースとして使用する必要がある場合、この構造方法は正確な変換を提供することに注意してください.Double.toString(double)メソッドを使用してからBigDecimal(String)コンストラクションメソッドを使用してdoubleをStringに変換すると、次の操作と同じ結果は得られません.この結果を取得するには、static valueOf(double)メソッドを使用します.3.2加算操作BigDecimal a=new BigDecimal(「1.22」)System.out.println(“construct with a String value: ” + a); BigDecimal b =new BigDecimal(“2.22”); a.add(b); System.out.println(“aplus b is : ” + a); 出力:construct with a Stringvalue:1.22 a plus b is:3.44しかし実際にはa plus b is:1.22 4.ソースコード分析4.1 valueOf(doubleval)方法public static BigDecimal valueOf(double val)//Reminder:a zero double returns‘0.0’,so we cannotfastpath//to use the constant ZERO.This might be important enough to//justify a factory approach,a cache,or a few private//constants,later.returnnew BigDecimal(Double.toString(val);//3.1 JDK記述の第3点}4.2 add(BigDecimal augend)を参照方法public BigDecimal add(BigDecimal augend){long xs=this.intCompact;//整数数字で表されるBigDecimal、例aのintCompact値は122 long ys=augend.intCompact;//同上BigInteger fst=(this.intCompact!=INFLATED)?null:this.intVal;//BigIntegerの値を初期化し、intValはBigDecimalのBigIntegerタイプの属性BigInteger snd=(augend.intCompact!=INFLATED)?null:augend.intVal;int rscale=this.scale;//小数位数
      long sdiff = (long)rscale - augend.scale;//      
      if (sdiff != 0) {//               
          if (sdiff < 0) {
             int raise =checkScale(-sdiff);
             rscale =augend.scale;
             if (xs ==INFLATED ||
                 (xs = longMultiplyPowerTen(xs,raise)) ==INFLATED)
                 fst =bigMultiplyPowerTen(raise);
            }else {
               int raise =augend.checkScale(sdiff);
               if (ys ==INFLATED ||(ys =longMultiplyPowerTen(ys,raise)) ==INFLATED)
                   snd = augend.bigMultiplyPowerTen(raise);
           }
      }
      if (xs !=INFLATED && ys !=INFLATED) {
          long sum = xs + ys;
          if ( (((sum ^ xs) &(sum ^ ys))) >= 0L)//      
             return BigDecimal.valueOf(sum,rscale);//    BigDecimal          BigDecimal  
       }
       if (fst ==null)
           fst =BigInteger.valueOf(xs);//BigInteger       
       if (snd ==null)
           snd =BigInteger.valueOf(ys);
       BigInteger sum =fst.add(snd);
       return (fst.signum == snd.signum) ?new BigDecimal(sum,INFLATED, rscale, 0) :
          new BigDecimal(sum,compactValFor(sum),rscale, 0);//             BigDecimal  
   }

                ,                BigDecimal  ,  BigInteger BigDecimal      (immutable) ,         ,          ,  a.add(b);        ,  a           ,        a=a.add(b);
5.まとめ(1)ビジネスコンピューティングではBigDecimalを使用する.(2)パラメータタイプがStringのコンストラクション関数をできるだけ使用する.(3)BigDecimalは可変であり、ステップごとに演算を行うと新しいオブジェクトが生成されるので、加算減算演算を行う際には操作後の値を絶対に保存する.(4)JDKの下位層の実装の詳細を無視しがちで、エラーが発生し、注意が必要です.