spire
spire copied to clipboard
Error in rational.toDouble
The toDouble method on Rational instances returns incorrectly for certain inputs. To reproduce,
import spire.math.Rational
def bld(numStr: String, denomStr: String): (Double, Double) = {
val num = BigInt(numStr)
val denom = BigInt(denomStr)
val expected = (BigDecimal(num) / BigDecimal(denom)).toDouble
val actual = Rational(num, denom).toDouble
(expected, actual)
}
println(
bld(
"179709322496314735297382168733437804616092100361307360024524978382010425322923559",
"179709322496314735297382168733483632988275016201074155389238170380281177201180672"
))
println(
bld(
"-1257965257474203147081675181125850088132776039278857905825424935347911159685302509",
"1257965257474203147081675181134385430917925113407519087724667192661968240408264704"
))
println(bld(
"3618502788666131106986593281458997943466459808578940660043329292438660832363",
"3618502788666131106986593281521497120414687020801267626233049500247285301248"
))
spire version: 0.14.1 scala version: 2.12.4 javac: 1.8.0_152 jvm: Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode) OS: Ubuntu 16.04
That's probably due to the algorithm used in Rational.toDouble
.
-
We should have principled approximations, i.e. laws that such conversions such obey. For example, decide to map to the nearest float.
-
Help is needed to turn this code in a test case. We should avoid using BigDecimal division as a comparison (so much can go wrong with the approximation in use). However, it is clear that the ratio of very close (big) integers cannot be approximated by 0.5.
This and #870 look like the same issue (or at least the same class of issue). Arguably they should be tackled together.