diff options
author | Rex Kerr <ichoran@gmail.com> | 2013-12-29 07:52:08 -0800 |
---|---|---|
committer | Rex Kerr <ichoran@gmail.com> | 2014-01-14 01:28:08 -0800 |
commit | 29541ce3961a797836b232ccc12a60cc09f5de3e (patch) | |
tree | d2503fdb387659c91bc821fe2643b361e19d2f00 /test/files | |
parent | ef4c5d2f43e912b5562c1372228e9c6ec9f25bb0 (diff) | |
download | scala-29541ce3961a797836b232ccc12a60cc09f5de3e.tar.gz scala-29541ce3961a797836b232ccc12a60cc09f5de3e.tar.bz2 scala-29541ce3961a797836b232ccc12a60cc09f5de3e.zip |
Quasi-comprehensive BigDecimal soundness/correctness fix.
This fixes issues SI-6153, SI-6173, SI-6456, SI-6699, and SI-8116, along with a number of other similar possible issues.
Relevant changes include
* Changes to avoid heap explosion when working with BigInt
- to isWhole
- to hashCode
- to equals
- to BigInt's equals
* Changes to enable equality matching hashCode
- Only for sufficiently small BigInt
- For identical values with different precision
* Changes to isValidDouble
- Takes precision into account now
- New methods added to test whether even if the Double is not represented exactly, it's a representation of a certain type
- New companion methods added to allow intended expansion of Double (binary/decimal difference)
* Changes to constructor
- Null arguments are not allowed (these can throw NPEs later at awkward/unexpected times)
* New JUnit test to test all these things
* Fixed existing tests to expect new behavior
* Modified scaladocs to explain the issues
* Deprecated problematic methods
* Made application of MathContext more consistent (it is where you expect it and not where you don't)
These changes are coordinated, for the most part, hence the monolithic
commit.
Diffstat (limited to 'test/files')
-rw-r--r-- | test/files/jvm/bigints.scala | 1 | ||||
-rw-r--r-- | test/files/run/bigDecimalTest.check | 2 | ||||
-rw-r--r-- | test/files/run/is-valid-num.scala | 28 | ||||
-rw-r--r-- | test/files/run/numbereq.scala | 27 |
4 files changed, 39 insertions, 19 deletions
diff --git a/test/files/jvm/bigints.scala b/test/files/jvm/bigints.scala index f0d05f8b71..06197cbb43 100644 --- a/test/files/jvm/bigints.scala +++ b/test/files/jvm/bigints.scala @@ -31,7 +31,6 @@ object Test_BigDecimal { val xi: BigDecimal = 1 val xd: BigDecimal = 1.0 - val xf: BigDecimal = BigDecimal(1.0f) val xs: BigDecimal = BigDecimal("1.0") val xbi: BigDecimal = BigDecimal(scala.BigInt(1)) diff --git a/test/files/run/bigDecimalTest.check b/test/files/run/bigDecimalTest.check index 6d11c23fcd..36db6aaafe 100644 --- a/test/files/run/bigDecimalTest.check +++ b/test/files/run/bigDecimalTest.check @@ -3,4 +3,4 @@ 0 0 0 -14 +15 diff --git a/test/files/run/is-valid-num.scala b/test/files/run/is-valid-num.scala index d314015dd4..65e8ceeca6 100644 --- a/test/files/run/is-valid-num.scala +++ b/test/files/run/is-valid-num.scala @@ -19,25 +19,27 @@ object Test { assert(!x.isValidChar, x) assert(!x.isValidShort, x) assert(!x.isValidByte, x) -// assert(y.isWhole, y) + assert(y.isWhole, y) assert(!y.isValidShort, y) assert(y.isValidChar, y) assert(y.isValidInt, y) - assert(y.isValidFloat, y) - assert(y.isValidDouble, y) + assert(y.isDecimalFloat, y) + assert(y.isDecimalDouble, y) assert(y.isValidLong, y) assert(!y.isValidByte, y) -// assert(!y1.isWhole) + assert(!y1.isWhole) assert(!y1.isValidLong, y1) - assert(!y1.isValidFloat, y1) - assert(!y1.isValidDouble, y1) + assert(y1.isDecimalFloat, y1) + assert(y1.isDecimalDouble, y1) + assert(!y1.isExactFloat, y1) + assert(!y1.isExactDouble, y1) assert(!y1.isValidInt, y1) assert(!y1.isValidChar, y1) assert(!y1.isValidShort, y1) assert(!y1.isValidByte, y1) assert(!y2.isValidLong, y2) - assert(y2.isValidFloat, y2) - assert(y2.isValidDouble, y2) + assert(y2.isExactFloat, y2) + assert(y2.isExactDouble, y2) assert(!l1.isValidInt && (l1 - 1).isValidInt, l1) assert(!l2.isValidInt && (l2 + 1).isValidInt, l2) @@ -170,8 +172,8 @@ object Test { if (!d.isInfinity) { val bd = BigDecimal(new java.math.BigDecimal(d)) // assert(!bd.isWhole, bd) - assert(bd.isValidDouble, bd) - assert(bd.isValidFloat == isFloat, bd) + assert(bd.isExactDouble, bd) + assert(bd.isExactFloat == isFloat, bd) assert(!bd.isValidLong, bd) assert(!bd.isValidInt, bd) assert(!bd.isValidChar, bd) @@ -210,9 +212,9 @@ object Test { val isFloat = !bi.toFloat.isInfinity && bd.compare(BigDecimal(new java.math.BigDecimal(bi.toFloat))) == 0 val isDouble = !bi.toDouble.isInfinity && bd.compare(BigDecimal(new java.math.BigDecimal(bi.toDouble))) == 0 -// assert(bd.isWhole, bd) - assert(bd.isValidDouble == isDouble, bd) - assert(bd.isValidFloat == isFloat, bd) + assert(bd.isWhole, bd) + assert(bd.isBinaryDouble == isDouble, bd) + assert(bd.isBinaryFloat == isFloat, bd) assert(bd.isValidLong == isLong, bd) assert(bd.isValidInt == isInt, bd) assert(bd.isValidChar == isChar, bd) diff --git a/test/files/run/numbereq.scala b/test/files/run/numbereq.scala index d50db6d049..7ce4b23cf8 100644 --- a/test/files/run/numbereq.scala +++ b/test/files/run/numbereq.scala @@ -31,6 +31,24 @@ object Test { ).flatten } + // Don't necessarily expect BigDecimal created from BigInt to agree with Double here. + def isIffy(x: Any, y: Any, canSwap: Boolean = true): Boolean = x match { + case bd: BigDecimal => y match { + case _: Float | _: Double => bd.toString.length > 15 + case _ => false + } + case _ => canSwap && isIffy(y, x, false) + } + + // Don't necessarily expect BigInt to agree with Float/Double beyond a Long + def isIffyB(x: Any, y: Any, canSwap: Boolean = true): Boolean = x match { + case bi: BigInt => y match { + case _: Float | _: Double => bi < Long.MinValue || bi > Long.MaxValue + case _ => false + } + case _ => canSwap && isIffyB(y, x, false) + } + def main(args: Array[String]): Unit = { val ints = (0 to 15).toList map (Short.MinValue >> _) val ints2 = ints map (x => -x) @@ -46,7 +64,6 @@ object Test { val sets = setneg1 ++ setneg2 ++ List(zero) ++ setpos1 ++ setpos2 for (set <- sets ; x <- set ; y <- set) { - // println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##)) assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) } @@ -64,9 +81,11 @@ object Test { val sets2 = setneg1 ++ setneg1b ++ setneg2 ++ setneg2b ++ List(zero) ++ setpos1 ++ setpos1b ++ setpos2 ++ setpos2b for (set <- sets2 ; x <- set ; y <- set) { -// println("'%s' == '%s' (%s == %s) (%s == %s)".format(x, y, x.hashCode, y.hashCode, x.##, y.##)) - assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) -// assert(x.## == y.##, "%s != %s".format(x.getClass, y.getClass)) Disable until Double.## is fixed (SI-5640) + if (!isIffy(x,y)) { + assert(x == y, "%s/%s != %s/%s".format(x, x.getClass, y, y.getClass)) + // The following is blocked by SI-8150 + // if (!isIffyB(x,y)) assert(x.## == y.##, "%x/%s != %x/%s from %s.## and %s.##".format(x.##, x.getClass, y.##, y.getClass, x, y)) + } } } } |