2016/05/17 このエントリーをはてなブックマークに追加 はてなブックマーク - BigDecimalというやつ、意外と知らないから見つめなおす

BigDecimalというやつ、意外と知らないから見つめなおす



java.math.BigDecimalは、扱う場面になればなるほど
「あれ、なんだっけ?」とか「そうだったのか…」とか新たな発見があります。僕は。


ごめん、BigDecimalのこと全然知らんかったわ…と毎回思うので、BigDecimalのソースを呼んだりしてみた。

Oracleのjdk1.80_51です。








0〜15のscaleで0の値を持つBigDecimalをBigDecimal自体がキャッシュしている。
内部でstatic finalな配列を持っている。
scale0の0〜10の値を持つBigDecimalも同様にキャッシュしている。

ソースを読むに、こいつらはBigDecimalの生成時に利用可能であれば積極的に利用されている感じがする。




内部にStringBuilderHelperというクラスがいる。
StringBuilderHelperはBigDecimalの持つThreadLocal内でインスタンス生成を行っている。
だから、スレッド毎にインスタンスあるんかな、多分。
StringBuilderHelperが何をやっているかというとtoStringとtoEngineeringStringなどで頑張っている。
これも処理の高速化のためのものであるって感じ。詳しくソースを読んでみてください。




divideは色々罠がある。
divideの結果、つまり戻り値が無限小数になる場合スケールを指定していない場合は例外が発生する。
まぁ、固定小数のBigDecimalなので当然といえば当然なんですが。


あと、現在ではRoundingModeを引数として取るのだけど、
昔はBigDecimalの定数のint値が丸めモードを指定する引数になっていた。






MutableIntegerというのがjava.mathパッケージ内でパッケージプライベートなクラスとしてあるっぽい。
このクラスは多倍長整数というものを表現するために使われているよう。
このMutableIntegerがBigIntegerを生成する。ということからも分かるようにBigIntegerはイミュータブルらしい。
BigDecimalもイミュータブル。javadocの先頭に書いてあったと思う。

ちなみにBigDecimalの実際の値の保持はBigIntegerかlong値として
上手く境界値を判定しつつ持ってる感じがした。





BigDecimalはSerializableインターフェースは実装していない。
ただし、readObjectメソッドとwriteObjectメソッドを独自実装しているので
シリアライズ・デシリアライズは可能。詳しくはSerializableのjavadocとかひしだまさんのサイトとか見るとわかると思います。

Java直列化メモ(Hishidama's Java Serializable Memo)

追記:
javadoc上では実装インターフェースにSerializableが入っているのですが、
Numberがimplements SerializableしているのでBigDecimalからはimplements Serializableしていないんですね。
(backpaper0さんに補足いただきました)

https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html




BigDecimalのソースを読んでテキトーに思ったことを言ってみました。
読んで解釈しただけなので結構間違ってるかも。。。間違ってたら指摘をくださるとありがたいです。


実装を見る限りだと処理の高速化、値の持ち回し(というか精度)はかなり気にしているなぁという感じがしました。

たまにワイルドな実装とか入ってたりするけど、
色々罠を知っていればBigDecimalに任せてたら安心って感じはするなーと思いました。




0 件のコメント:

コメントを投稿