BigDecimal の挙動が #Scala 2.10.0 と 2.9 で異なる件

0
Kenji Yoshida @xuwei_k

unfiltered2.10対応しようとするも、dispatch-classisがでていないことに気づいて、dispatchいじってたらこのバグ https://t.co/bXmQQcSe のせいで、dispatchのテストが通らなくなってあばばばば。なんだよこのひどいバグ・・・

2012-12-21 15:11:12
Kenji Yoshida @xuwei_k

Scala2.10.0.finalでは、BigDecimal のisValidDoubleとisValidFloatの動作および、BigDecimalとFloatやDoubleを比べたときの挙動が2.9.2と変わってるので気をつけてください。っていうか仕様はどうあるべきなのだろう

2012-12-21 15:16:19
Kenji Yoshida @xuwei_k

Scala2.10.0.finalだとBigDecimal(0.5).isValidFloat、 BigDecimal(0.25).isValidFloatなど浮動小数点としてきりよく表せる場合はtrueで、BigDecimal(0.2).isValidFloatだとfalse

2012-12-21 15:19:53
Kenji Yoshida @xuwei_k

BigIntのisValidLongも2.9のときバグってたし http://t.co/MGsbgIIX BigIntやBigDecimal使ってて、このあたり理解せずにScala2.9から2.10に上げると危険だし、ハマった場合に原因特定するのめんどくさそう・・・

2012-12-21 15:28:35

まとめ Scala の BigInt に関しての既知のBug(?)に遭遇したけど最新版ではなおってるらしい・・・というメモ これまとめた時点の情報なので、 2.8.2 や 2.9.2 、 2.10.0 のfinalが出るときはどーなるかわかりませんが、現状 2.8.1.finalも2.9.1.final もこんな動作らしいので気をつけましょう 3934 pv 2

Yasushi Abe @yasushia

うええ。ふつう valid な double、っていうとdoubleとして正しいビット列、とかNaNじゃない、あたりじゃないかと思うんだけど。完全にdouble/floatに変換できるか、ならcanDoubleとかにすべきなんじゃ。

2012-12-21 15:52:22
Kenji Yoshida @xuwei_k

.@yasushia あ、最初自分は「NaNやInfinityでない場合はtrue返すように実装したつもりがバグった」のかと思ってましたが、コメント https://t.co/tTp8cOlo みると意図した仕様なんですかね・・・?でもissueはopenのままだし謎

2012-12-21 15:59:08
Yasushi Abe @yasushia

@xuwei_k BigDecimal.isValidInt が within the range of Int MinValue and MaxValue; otherwise returns false なんで意図した仕様だと思いますね。欲しい人はいないような気がしますが…

2012-12-21 16:02:32
Kenji Yoshida @xuwei_k

.@yasushia でも、それをequalsで使っていることにより、Scala2.10.0においては、 BigDecimal(0.1) == 0.1はfalseで、BigDecimal(0.5) == 0.5はtrue になるという・・・(Scala2.9では両方true)

2012-12-21 16:05:40
Yasushi Abe @yasushia

@xuwei_k あー。なるほど。やっと理解しました。Float/DoubleにMin/Maxがないから、その意図にすらなってないんですね。うーん。Javaのほう確認してみます

2012-12-21 16:09:12
Yasushi Abe @yasushia

浮動小数の比較に==つかうな、という基本的なミスなんですなこれ。

2012-12-21 16:09:39
tomo🐧@learning @cocoatomo

@yasushia @xuwei_k Java の方だと, Long, Double は -∞ < any value < ∞ < NaN という奇妙な全順序になってます. ところが Scala だと NaN は他の値とは比較できないようになってます.

2012-12-21 16:12:24
tomo🐧@learning @cocoatomo

@yasushia @xuwei_k 話題をつかみ切れてないので, ズレてたこと言ってたらすみません.

2012-12-21 16:12:43
Yasushi Abe @yasushia

http://t.co/hHdg8QmG !isInfinity だけでよさげに見える。

2012-12-21 16:15:00
tomo🐧@learning @cocoatomo

@xuwei_k @yasushia あ, BigDecimal の話題でしたか. ズレてましたm(__)m

2012-12-21 16:17:01
Yasushi Abe @yasushia

@cocoatomo @xuwei_k BitDecimal.isValidDoubleという関数が追加されていて、これの仕様が「正しくDoubleに変換できるBigDecimal値」という仕様のようなんですが、無限小数(0.1とか)は不正と判定してて、これなに?、という

2012-12-21 16:17:53
Yasushi Abe @yasushia

これが影響うけるのは、BigDecimalとDouble/Floatを比較してる場合、かなぁ。でもこのisValidDoubleがfalseになるような値だと結局==は失敗しそうだから、それほど影響ない?

2012-12-21 16:20:49
Kenji Yoshida @xuwei_k

@yasushia @cocoatomo まぁJavaのものを参考にするにしても、Scalaでは違うclassなわけで(javaのBigDecimalを継承してるわけじゃない) 必ずしも従う必要はないとは思いますが、とにかく仕様が曖昧でどの状態がバグなのかがわからなくてあれですね

2012-12-21 16:21:37
tomo🐧@learning @cocoatomo

@yasushia @xuwei_k あぁーなるほど. その「正しく Double」が Infinity, NaN 含むかどうかはあやしそうですね.

2012-12-21 16:21:44
Yasushi Abe @yasushia

@cocoatomo @xuwei_k Infは排除してるみたいですね。ただ0.1もisValidDouble==falseなのは、なんかヘンな気がします

2012-12-21 16:25:12
tomo🐧@learning @cocoatomo

@yasushia @xuwei_k とすると, -∞ < any value < ∞ という判定をすればいいんじゃないかなぁ……

2012-12-21 16:28:29
Yasushi Abe @yasushia

2.9.0だと BigDecimal("0.1") == 0.1 はtrueだった。大丈夫なんだ

2012-12-21 16:28:42
Yasushi Abe @yasushia

@cocoatomo @xuwei_k ですね。ただ、toDoubleがJavaのdoubleValueをそのままつかっているので、その時点で範囲外はInfで返ってくるので、isValidDoubleは!isInfinityだけで十分そうです。

2012-12-21 16:35:22