spire icon indicating copy to clipboard operation
spire copied to clipboard

Error in rational.toDouble

Open harshad-deo opened this issue 7 years ago • 2 comments

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

harshad-deo avatar Dec 21 '17 06:12 harshad-deo

That's probably due to the algorithm used in Rational.toDouble.

  1. We should have principled approximations, i.e. laws that such conversions such obey. For example, decide to map to the nearest float.

  2. 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.

denisrosset avatar Mar 21 '18 18:03 denisrosset

This and #870 look like the same issue (or at least the same class of issue). Arguably they should be tackled together.

kschwarz1116 avatar May 27 '22 15:05 kschwarz1116