CodeGym /Java Blog /ランダム /JavaのBigDecimal
John Squirrels
レベル 41
San Francisco

JavaのBigDecimal

ランダム グループに公開済み
やあ!今日のレッスンでは大数について話します。いいえ、本当に大きいという意味です。私たちはこれまでに、プリミティブ データ型の値の範囲のテーブルに繰り返し遭遇しました。次のようになります。
プリミティブ型 メモリ内のサイズ 値の範囲
バイト 8ビット -128~127
短い 16ビット -32768 ~ 32767
文字 16ビット 0~65536
整数 32ビット -2147483648 ~ 2147483647
長さ 64ビット -9223372036854775808 ~ 9223372036854775807
浮く 32ビット (2 の -149 乗) ~ ((2 の -23 乗) * 2 の 127 乗)
ダブル 64ビット (-2の63乗) ~ ((2の63乗) - 1)
ブール値 8 (配列で使用される場合)、32 (配列で使用されない場合) 正しいか間違っているか
最も余裕のある整数データ型は、longです。浮動小数点数に関して言えば、それはdoubleです。しかし、必要な数値が大きすぎて、 long 型にさえ収まらない場合はどうなるでしょうか? Long データ型には非常に広い範囲の値を指定できますが、依然として 64 ビットに制限されています。非常に大きな数に 100 ビットが必要な場合、何を考え出す必要があるでしょうか? 幸いなことに、私たちは何も発明する必要はありません。このような場合に備えて、Java にはBigInteger (整数用) とBigDecimalという 2 つの特別なクラスがあります。(浮動小数点数の場合)。何が彼らを特別にするのでしょうか?まず、理論上、最大サイズはありません。「理論上」と言うのは、無限のメモリを備えたコンピューターは存在しないためです。そして、プログラムが利用可能なメモリの量よりも大きな数値を作成した場合、当然のことながら、プログラムは動作しなくなります。しかし、そのようなケースは考えにくいです。結果として、BigIntegerBigDecimal は事実上無制限のサイズの数値を表現できると言えます。これらのクラスは何に使用されますか? まず第一に、非常に厳密な精度要件が必要な計算です。たとえば、人間の命は一部のプログラム (飛行機、ロケット、医療機器を制御するソフトウェアなど) の計算の精度に依存する場合があります。したがって、小数点以下 150 位が重要な場合は、BigDecimal になります。が最良の選択です。さらに、このクラスのオブジェクトは金融の世界でよく使用され、最小値であっても正確に計算することも非常に重要です。BigIntegerオブジェクトとBigDecimalオブジェクトをどのように操作しますか?また、それらについて知っておく必要がありますか? これらのクラスのオブジェクトは次のように作成されます。

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
コンストラクターに文字列を渡すことは、可能なオプションの 1 つにすぎません。ここでは、数値がlongdoubleの最大値を超えているため、文字列を使用します。また、どの数値を作成するかをコンパイラーに説明する何らかの方法が必要です:) 数値 1111111111111111111111111111111111111111111111111111111111111111111111111111を渡すだけです。 11111111111111111111111111111111111111111111111111111111111111111 Java は渡された数値をプリミティブ データ型の 1 つに詰め込もうとしますが、どのデータ型にも適合しません。そのため、文字列を使用して必要な数値を渡すことが良い選択肢となります。どちらのクラスも、渡された文字列から数値を自動的に抽出できます。大きな数のクラスを扱うときに覚えておくべきもう 1 つの重要な点は、そのオブジェクトが不変 ( Immutable ) であるということです。Stringクラスとプリミティブ型 (Integer、Long など) のラッパー クラスの 経験により、不変性についてはすでによく理解されています。

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
コンソール出力:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 
ご想像のとおり、番号は変わっていません。加算操作を実行するには、操作の結果を受け取る新しいオブジェクトを作成する必要があります。

import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
コンソール出力:

11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
ほら、これですべてが正常に動作するようになりました :) ところで、加算演算がいかに珍しいかに気づきましたか?

BigInteger result = integer.add(BigInteger.valueOf(33333333));
これも重要なポイントです。大きな数のクラスでは + - * / 演算子は使用されません。代わりに、一連のメソッドが提供されます。主なメソッドを見てみましょう (いつものように、メソッドの完全なリストは Oracle ドキュメントで見つけることができます:こちらこちら)。
  1. 算術演算のメソッド: add()subtract()multiply()divide()。これらのメソッドは、それぞれ加算、減算、乗算、除算を実行するために使用されます。

  2. doubleValue()intValue()floatValue()longValue()などは、大きな数値を Java のプリミティブ型の 1 つに変換するために使用されます。これらの方法を使用する場合は注意してください。ビットサイズの違いを忘れないでください。

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }
    

    コンソール出力:

    
    8198552921648689607
    
  3. min()max() を使用すると、 2 つの大きな数値の最小値と最大値を見つけることができます。
    これらのメソッドは静的ではないことに注意してください。

    
    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }
    

    コンソール出力:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    

BigDecimal の丸め動作

大きな数値の四捨五入と丸め動作の構成はそれほど単純ではないため、このトピックには別のセクションがあります。setScale()メソッドを使用して、BigDecimalの小数点以下の桁数を設定できます。たとえば、数値111.5555555555を小数点以下 3 桁にしたいとします。ただし、数値 3 を引数としてsetScale()メソッドに渡しても、目的を達成することはできません。前述したように、BigDecimal計算精度に厳しい要件がある数値を表現するためのものです。現在の形式では、番号は小数点以下 10 桁になります。そのうち 7 つを削除し、3 つだけを残しておきたいと考えています。したがって、数値 3 に加えて、丸めモードを通過する必要があります。 BigDecimal には、合計 8 つの丸めモードがあります。それは多いです!ただし、計算の精度を本当に微調整する必要がある場合は、必要なものがすべて揃っています。BigDecimalが提供する 8 つの丸めモードは次のとおりです。
  1. ROUND_CEILING — 切り上げ

    
    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
    
  2. ROUND_DOWN — ゼロに向かって丸めます

    
    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
    
  3. ROUND_FLOOR — 切り捨て

    
     111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
    
    

  4. ROUND_HALF_UP — 小数点以下の数値が 0.5 以上の場合に切り上げます。

    
    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
    
  5. ROUND_HALF_DOWN — 小数点以下の数値が 0.5 を超える場合に切り上げます。

    
    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
    
  6. ROUND_HALF_EVEN — 丸めは小数点の左側の数値に応じて異なります。左側の数値が偶数の場合、四捨五入されます。小数点左側の数値が奇数の場合は四捨五入となります。

    
    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2
    

    小数点以下の数字は 2 (偶数) です。数値は切り捨てられます。小数点以下の桁数は 0 にする必要があるため、結果は 2 になります。

    
    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4
    

    小数点の左側の数値は 3 (奇数) です。数値は切り上げられます。小数点以下の桁数は 0 にする必要があるため、結果は 4 になります。

  7. ROUND_UNNECCESSARY — このモードは、丸めモードをメソッドに渡す必要があるが、数値を丸める必要がない場合に使用されます。ROUND_UNNECCESSARY モードを設定して数値を丸めようとすると、ArithmeticException がスローされます。

    
    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
    
  8. ROUND_UP — ゼロから離れる方向に丸めます。

    
    111.5551 -> setScale(3, ROUND_UP) -> 111.556
    

大きな数字を比較する

これも重要です。Java ではオブジェクトを比較するために、 equals()メソッドを使用していることを思い出してください。実装は、言語自体 (標準 Java クラスの場合) によって提供されるか、プログラマによってオーバーライドされます。ただし、 BigDecimalオブジェクトの場合、比較にequals()メソッドを使用することはお勧めできません。これは、BigDecimal.equals()メソッドが 2 つの数値の値とスケールが同じである場合にのみ true を返すためです。 DoubleクラスとBigDecimalクラスのequals()メソッドの動作を比較してみましょう。

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));
      
   }
}
コンソール出力:

true 
false
ご覧のとおり、BigDecimalの場合、数値 1.5 と 1.50 は等しくないことが判明しました。これはまさに、 BigDecimalクラスのquals()メソッドの実装の詳細によるものでした。2 つのBigDecimalオブジェクトをより正確に比較するには、 compareTo()メソッドを使用することをお勧めします。

import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
コンソール出力:

0
CompareTo ()メソッドは 0 を返しました。これは、1.5 と 1.50 が等しいことを意味します。そしてこれが私たちが期待していた結果です!:) 今日のレッスンはこれで終わりです。さあ、タスクに戻りましょう! :)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION