15

私のJavaプログラムは高精度の計算を中心としており、小数点以下120桁以上の精度が必要です。
その結果、整数以外のすべての数値は、プログラム内でBigDecimalsによって表されます。

明らかに、無限小数式などを避けるために、BigDecimalsの丸めの精度を指定する必要があります。
現在、BigDecimalのすべてのインスタンス化または数学演算で精度を指定しなければならないのは非常に厄介です。

すべてのBigDecimal計算に「グローバル精度」を設定する方法はありますか?
( PythonContext.prec()Decimalモジュールなど)

ありがとう


仕様:
Java jre7 SE
Windows 7(32)

4

7 に答える 7

13

(ほぼ)オリジナル

それほど単純ではありませんが、を作成して、すべてのコンストラクターと操作を実行するメソッドMathContextに渡すことができます。BigDecimal

改訂

または、右を指定し、次の丸めバージョンを使用することで、使用する操作を拡張BigDecimalおよびオーバーライドできます。MathContextdivide

public class MyBigDecimal extends BigDecimal {

      private static MathContext context = new MathContext(120, RoundingMode.HALF_UP);

      public MyBigDecimal(String s) {
           super(s, context);
      }
      public MyBigDecimal(BigDecimal bd) {
           this(bd.toString()); // (Calls other constructor)
      }
      ...
      public MyBigDecimal divide( BigDecimal divisor ){
           return new MyBigDecimal( super.divide( divisor, context ) );
      }
      public MyBigDecimal add( BigDecimal augend ){
           return new MyBigDecimal( super.add( augend ) );
      }
      ...
}
于 2012-04-08T03:39:24.613 に答える
4

インスタンスがファクトリ内にあり、起動時に静的に初期化されることを除いて、BigDecimalFactory受け入れるすべてのコンストラクタに一致する静的ファクトリ メソッドを持つクラスを作成します。ここにフラグメントがあります:MathContextMathContext

public class BigDecimalFactory {
    public static BigDecimal newInstance (BigInteger unscaledVal, int scale) {
        return new BigDecimal (unscaledVal, scale, _mathContext);
    }

    // . . . other factory methods for other BigDecimal constructors

    private static final MathContext _mathContext = 
        new MathContext (120, BigDecimal.ROUND_HALF_UP);
}
于 2012-04-08T03:45:21.193 に答える
3

すべてのBigDecimal計算に「グローバル精度」を設定する方法はありますか?

いいえ。

MathContext追加の属性としてを含むラッパークラスを作成する必要があります。次のことが必要になります。

  • これmcを、デフォルトのセマンティクスを使用する数学演算ごとに使用し、

  • ラップされた操作が通常のインスタンスを返すたびに、別のラップされたインスタンスを作成して返します。

(バリエーションとして、静的を使用して「グローバル」を実装できますがMathContext、それでも、が使用されるようにラッパーを使用する必要がありますmc。)

(拡張BigDecimalも機能します。これは、ラッパークラスよりも優れていると言えます。)


あなたはコメントでこれを言いました:

私は本当に自分のDecimalモジュールを書きたくありません。BigDecimalがなぜそれほど非協力的であるのかを理解したいだけです。

(設計に関する質問には、設計チームのみが明確に回答できます。ただし...)

すべての複雑なユーティリティクラスと同様に、BigDecimalの設計は、幅広いユースケースの要件を満たすように設計された妥協案です。これは、「強力さ」と「シンプルさ」という競合するメタ要件(間違った言葉)の間の妥協点でもあります。

あなたが持っているのは、特に十分にサポートされていないユースケースです。しかし、それが十分にサポートされている場合(たとえば、MathContextすべてをグローバルに制御したり、MathContextそれぞれに接続したりする場合BigDecimal)、他のあらゆる種類の複雑さが生じると思います。たとえば、考慮すべき2つ以上の競合するコンテキストオブジェクトがある操作を処理します。このような問題は対処できますが、プログラマーにとって「驚き」につながる可能性があり、それは良いことではありません。

MathContext現在のアプローチは単純で理解しやすいものであり、より複雑なものが必要な場合は、それを実装できます...それを必要とする操作にを明示的に指定することによって。

于 2012-04-08T04:28:25.820 に答える
2

BigDecimal精度を自動的に拡張および設定するクラスを作成できます。次に、そのクラスを使用します。

public class MyBigDecimal extends BigDecimal {
      public MyBigDecimal(double d) {
           super(d);
           this.setScale(120, BigDecimal.ROUND_HALF_UP);
      }
      ...
}
于 2012-04-08T03:40:27.150 に答える
0

BigDecimalsのラッパーを作成できます。これにより、次の作業が実行されます。

 class BigDecimalWrapper {
     BigDecimal bd;   

     BigDecimalWrapper add(BigDecimalWrapper another) {
         BigDecimal r = this.bd.add(another.bd);
         r.setScale(...);
         bd = r;
         return this;
     }
     // and so on for other operations
 }

この場合、BigDecimalのすべての操作(拡張の場合)をオーバーライドする必要はなく、使用する操作だけをオーバーライドします。これにより、すべてのインスタンスを制御でき、BigDecimalコントラクトに従うように強制されることはありません。

于 2012-04-08T03:40:45.393 に答える
-4

BigDecimal setScale関数を使用できます!

BigDecimal db = new BigDecimal(<number>).setScale(120, BigDecimal.ROUND_HALF_UP); (or down)
于 2012-04-08T03:38:15.570 に答える