4
3

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の罠 〜doubleから変換はvalueOf使え〜

Last updated at Posted at 2019-01-23

腹立ったので記事化。

BigDecimalという、不動小数点を扱うときに精密に計算する際に利用することを推奨されるクラスがあります。
んで、これのインスタンス化のときにDouble使うとズレることがある、という話。

背景

一種の会計ソフトのレシート出力を作っていて、
111.11 円を8つ、つまり 888.88 を出力しようとすると
なぜか 888.87... になってしまって怒り狂っていた

原因

BigDecimalのインスタンス化のときにdoubleを利用すると、
その時点で正確な値にはならない場合があるようです

追記:
エライ人たちにご指摘いただき、潜ってみたら書いてた ^q^
0.1 とかをdoubleで渡すと、正確な不動小数点表現(64bit表現)に変換されてしまい 0.100...551..とかになるらしい

    /**
     * Constructs a new {@code BigDecimal} instance from the 64bit double
     * {@code val}. The constructed big decimal is equivalent to the given
     * double. For example, {@code new BigDecimal(0.1)} is equal to {@code
     * 0.1000000000000000055511151231257827021181583404541015625}. This happens
     * as {@code 0.1} cannot be represented exactly in binary.
     * <p>
     * To generate a big decimal instance which is equivalent to {@code 0.1} use
     * the {@code BigDecimal(String)} constructor.
     *
     * @param val
     *            double value to be converted to a {@code BigDecimal} instance.
     * @throws NumberFormatException
     *             if {@code val} is infinity or not a number.
     */
    public BigDecimal(double val) {

import java.math.BigDecimal

fun main(args: Array<String>) {
    val seed = 888.88
    val fromDouble = BigDecimal(seed)
    val fromValueOf = BigDecimal.valueOf(seed)
    println("from double  -> $fromDouble")
    println("from valueOf -> $fromValueOf")
}
from double  -> 888.8799999999999954525264911353588104248046875
from valueOf -> 888.88

解決策

Stringにしてインスタンス化のときに渡してやると、ズレずにできました。よかったよかった。
BigDecimal.valueOf(double) とすると正確にdoubleから変換できるようです。
@blhsrwznrghfzpr さん、ご指摘ありがとうございました!)

みんなちゃんとドキュメント読もう ( ^ω^)

4
3
3

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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?