9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

BigDecimal.valueOf(double)の話

Last updated at Posted at 2019-06-14

BigDecimalでの小数

javaで小数計算する場合はBigDecimalがデファクトスタンダードです。
double型やfloat型で計算しようものならあっと言う間に誤差が出てひどいことになります。

しかも、このBigDecimalは性質の悪いことに新人が一番使ってしまいそうな
以下のようなコードを書くと結局誤差が出てしまいます。
double型で宣言した時点で誤差が出ているので、
それを基にBigDecimalを作っても誤差がそのまま保持されてしまうからです。
新人の頃、先輩から下のように書けと散々叩き込まれたものです。


BigDecimal bad = new BigDecimal(1.3);
//内部的に1.3000000000000000444089209850062616169452667236328125

BigDecimal good = new BigDecimal("1.3");

BigDecimal.valueOf(double)

というわけで、BigDecimalで小数を扱う時は引数は文字列だと完全に体に染み込んでいるのですが、
最近ちょっと検索してみると、BigDecimal.valueOf(double)でdouble型は問題なく扱えるという風に書いてある解説ページが結構ありました。

しかし、new BigDecimal(double) がdouble型の時点で正確な10進数の小数を保持できないために誤差が出てしまうということを考えると、
BigDecimal.valueOf(double)も誤差が出てしまうはずです。

しかし、意外なことに確かに大抵のケースでBigDecimal.valueOf(double) は正しく動きます。

BigDecimal fromValueOf = BigDecimal.valueOf(1.3);
//これはnew BigDecimal("1.3") と同じ値になる

これはどういうことでしょうか。

BigDecimal.valueOfの実装

BigDecimal.valueOf(double) の実装を見てみると、以下の通りでした。
(OpenJdk より引用)

    public static BigDecimal valueOf(double val) {
        //コメント部分は省略
        return new BigDecimal(Double.toString(val));
    }

意外と実装はシンプルで、Double.toString(double)でdouble型を文字列化した値を使って文字列からBigDecimalを生成しています。
よって、Double.toString(double)がそのdouble値の元となったリテラルの値(またはそれに対応する数値表現)をきちんと返してくれる限り、意図した通りのBigDecimalを返してくれそうです。

Double.toString()はきちんと値を復元してくれるのか?

ほとんどの場合大丈夫ですが、非常に小数点以下の桁数の多い数の場合完璧には戻らないようです。

BigDecimal.valueOf(1.0000000003000003)
//1.0000000003000002

とはいっても、狙って出さないと基本的にずれませんし、
これだけ細かい桁数を使うことはほぼないと思われます。

まとめ

  • BigDecimal.valueOf(double)は一度文字列変換しているので信頼性が高い
  • 滅多にない誤差まで気になるのなら文字列で宣言できるところは文字列で宣言を

余談

ちなみに、これはリテラルで宣言したdoubleをそのまま使った場合の話です。
double型で演算した後の値を使うとうまく行きません。

BigDecimal.valueOf(1.3 + 1.5 + 1.4)
///4.199999999999999

演算はBigDecimalにしてからですね。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?