You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2016/07/25 09:58:47 UTC
groovy git commit: GROOVY-7636: Fall back to BigDecimalMath for
custom Numbers (closes #151)
Repository: groovy
Updated Branches:
refs/heads/master 679eb23ce -> de9c8803c
GROOVY-7636: Fall back to BigDecimalMath for custom Numbers (closes #151)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/de9c8803
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/de9c8803
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/de9c8803
Branch: refs/heads/master
Commit: de9c8803c72175a758df8492e504ab3b582ba730
Parents: 679eb23
Author: Thibault Kruse <th...@gmx.de>
Authored: Mon Oct 19 19:34:52 2015 +0200
Committer: paulk <pa...@asert.com.au>
Committed: Mon Jul 25 19:57:18 2016 +1000
----------------------------------------------------------------------
.../groovy/runtime/typehandling/NumberMath.java | 34 ++-
src/test/groovy/NumberMathTest.groovy | 180 --------------
.../runtime/typehandling/NumberMathTest.groovy | 232 +++++++++++++++++++
3 files changed, 259 insertions(+), 187 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/de9c8803/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java b/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java
index c953ffd..37fa65f 100644
--- a/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java
+++ b/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java
@@ -147,6 +147,14 @@ public abstract class NumberMath {
return number instanceof Integer;
}
+ public static boolean isShort(Number number) {
+ return number instanceof Short;
+ }
+
+ public static boolean isByte(Number number) {
+ return number instanceof Byte;
+ }
+
public static boolean isLong(Number number) {
return number instanceof Long;
}
@@ -179,27 +187,35 @@ public abstract class NumberMath {
* F D D D D D D
* L bD bI D D L L
* I bD bI D D L I
- *
+ *
* Note that for division, if either operand isFloatingPoint, the result will be floating. Otherwise,
* the result is BigDecimal
*/
public static NumberMath getMath(Number left, Number right) {
+ // FloatingPointMath wins according to promotion Matrix
if (isFloatingPoint(left) || isFloatingPoint(right)) {
return FloatingPointMath.INSTANCE;
}
- if (isBigDecimal(left) || isBigDecimal(right)) {
+ NumberMath leftMath = getMath(left);
+ NumberMath rightMath = getMath(right);
+
+ if (leftMath == BigDecimalMath.INSTANCE || rightMath == BigDecimalMath.INSTANCE) {
return BigDecimalMath.INSTANCE;
}
- if (isBigInteger(left) || isBigInteger(right)) {
+ if (leftMath == BigIntegerMath.INSTANCE || rightMath == BigIntegerMath.INSTANCE) {
return BigIntegerMath.INSTANCE;
}
- if (isLong(left) || isLong(right)) {
+ if (leftMath == LongMath.INSTANCE || rightMath == LongMath.INSTANCE) {
return LongMath.INSTANCE;
}
- return IntegerMath.INSTANCE;
+ if (leftMath == IntegerMath.INSTANCE || rightMath == IntegerMath.INSTANCE) {
+ return IntegerMath.INSTANCE;
+ }
+ // also for custom Number implementations
+ return BigDecimalMath.INSTANCE;
}
- private static NumberMath getMath(Number number) {
+ /* package private */ static NumberMath getMath(Number number) {
if (isLong(number)) {
return LongMath.INSTANCE;
}
@@ -212,7 +228,11 @@ public abstract class NumberMath {
if (isBigInteger(number)) {
return BigIntegerMath.INSTANCE;
}
- return IntegerMath.INSTANCE;
+ if (isInteger(number) || isShort(number) || isByte(number)) {
+ return IntegerMath.INSTANCE;
+ }
+ // also for custom Number implementations
+ return BigDecimalMath.INSTANCE;
}
//Subclasses implement according to the type promotion hierarchy rules
http://git-wip-us.apache.org/repos/asf/groovy/blob/de9c8803/src/test/groovy/NumberMathTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/NumberMathTest.groovy b/src/test/groovy/NumberMathTest.groovy
deleted file mode 100644
index 686a5ee..0000000
--- a/src/test/groovy/NumberMathTest.groovy
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package groovy
-
-/**
- * Basic NumberMath test.
- * @see org.codehaus.groovy.runtime.typehandling.NumberMath
- */
-class NumberMathTest extends GroovyTestCase {
-
- void testPromotions() {
- def C = '1'.toCharacter()
- def B = new Byte("1")
- def I = new Integer(1)
- def L = new Long(1)
- def F = new Float("1.0")
- def D = new Double("1.0")
- def BI = new BigInteger("1")
- def BD = new BigDecimal("1.0")
-
- //+, -, and * all promote the same way, so sample the matrix
- assert C + B instanceof Integer
- assert C - BD instanceof BigDecimal
- assert B + C instanceof Integer
- assert B + I instanceof Integer
- assert B + F instanceof Double
-
- assert I + I instanceof Integer
- assert I - F instanceof Double
- assert I * D instanceof Double
- assert I + BI instanceof BigInteger
- assert I - BD instanceof BigDecimal
-
- assert F * L instanceof Double
- assert D + L instanceof Double
- assert BI - L instanceof BigInteger
- assert BD * L instanceof BigDecimal
-
- assert F + F instanceof Double
- assert F - BI instanceof Double
- assert F * BD instanceof Double
-
- assert F + D instanceof Double
- assert BI - D instanceof Double
- assert BD * D instanceof Double
-
- assert BI + BI instanceof BigInteger
- assert BD - BI instanceof BigDecimal
- assert BD * BD instanceof BigDecimal
-
- //Division (/) promotes differently so change the expected results:
- assert I / I instanceof BigDecimal
- assert I / F instanceof Double
- assert I / D instanceof Double
- assert I / BI instanceof BigDecimal
- assert I / BD instanceof BigDecimal
-
- assert F / L instanceof Double
- assert D / L instanceof Double
- assert BI / L instanceof BigDecimal
- assert BD / L instanceof BigDecimal
-
- assert F / F instanceof Double
- assert F / BI instanceof Double
- assert F / BD instanceof Double
-
- assert F / D instanceof Double
- assert BI / D instanceof Double
- assert BD / D instanceof Double
-
- assert BI / BI instanceof BigDecimal
- assert BD / BI instanceof BigDecimal
- assert BD / BD instanceof BigDecimal
- }
-
- void testOperations() {
- def I1 = new Integer(1)
- def I2 = new Integer(2)
- def I3 = new Integer(3)
- def L1 = new Long(1)
- def L2 = new Long(2)
- def L3 = new Long(3)
- def F1 = new Float("1.0")
- def F2 = new Float("2.0")
- def D1 = new Double("1.0")
- def D2 = new Double("2.0")
- def BI1 = new BigInteger("1")
- def BI2 = new BigInteger("2")
- def BD1 = new BigDecimal("1.0")
- def BD2 = new BigDecimal("2.0")
- def BD20 = new BigDecimal("2.00")
-
- assert I1 / I2 instanceof BigDecimal
- assert I1 / I2 == new BigDecimal("0.5")
- assert F1 / F2 instanceof Double
- assertEquals F1 / F2, 0.5, 0.0000000001
- assert D1 / D2 instanceof Double
- assertEquals D1 / D2, 0.5, 0.0000000001
-
- assert I1.intdiv(I2) instanceof Integer
- assert I1.intdiv(I2) == 0
-
- assert I3.intdiv(I2) instanceof Integer
- assert I3.intdiv(I2) == 1
-
- assert L1.intdiv(I2) instanceof Long
- assert L1.intdiv(I2) == 0
-
- assert L3.intdiv(L2) instanceof Long
- assert L3.intdiv(L2) == 1
-
- assert BI1.intdiv(BI2) instanceof BigInteger
- assert BI1.intdiv(BI2) == 0
-
- assert I1 / I3 instanceof BigDecimal
- assert I1 / I3 == new BigDecimal("0.3333333333")
-
- assert I2 / I3 instanceof BigDecimal
- assert I2 / I3 == new BigDecimal("0.6666666667")
-
- assert I1 / BD2 instanceof BigDecimal
-
- //Test keeping max scale of (L, R or 10)
- def BBD1 = new BigDecimal("0.12345678901234567")
- assert BD1 + BBD1 == new BigDecimal("1.12345678901234567")
-
- def BBD2 = new BigDecimal(".000000000000000008")
- assert BBD1 + BBD2 == new BigDecimal("0.123456789012345678")
- }
-
- void testUnsupportedIntDivision() {
- try {
- 1.0.intdiv(3)
- } catch (UnsupportedOperationException ignore) {
- return
- }
- fail("Should catch an UnsupportedOperationException")
-
- try {
- 1.0G.intdiv(3)
- } catch (UnsupportedOperationException ignore) {
- return
- }
- fail("Should catch an UnsupportedOperationException")
- }
-
- void testGetMath() {
- assert 20 == new Short("10") << 1
- assert 2 == new Byte("1") << 1
- }
-
- void testLongDivAssign() {
- long d = 100L
- d /= 33L
- assert d.class == Long.class
- }
-
- void testIntegerPlusCastException() {
- shouldFail(ClassCastException) {
- Integer i = 12
- i += " angry men"
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/de9c8803/src/test/org/codehaus/groovy/runtime/typehandling/NumberMathTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/runtime/typehandling/NumberMathTest.groovy b/src/test/org/codehaus/groovy/runtime/typehandling/NumberMathTest.groovy
new file mode 100644
index 0000000..eff11ce
--- /dev/null
+++ b/src/test/org/codehaus/groovy/runtime/typehandling/NumberMathTest.groovy
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.codehaus.groovy.runtime.typehandling
+
+import static org.codehaus.groovy.runtime.typehandling.NumberMath.getMath
+
+/**
+ * Basic NumberMath test.
+ * @see org.codehaus.groovy.runtime.typehandling.NumberMath
+ */
+class NumberMathTest extends GroovyTestCase {
+
+ void testPromotions() {
+ def C = '1'.toCharacter()
+ def B = new Byte("1")
+ def I = new Integer(1)
+ def L = new Long(1)
+ def F = new Float("1.0")
+ def D = new Double("1.0")
+ def BI = new BigInteger("1")
+ def BD = new BigDecimal("1.0")
+
+ //+, -, and * all promote the same way, so sample the matrix
+ assert C + B instanceof Integer
+ assert C - BD instanceof BigDecimal
+ assert B + C instanceof Integer
+ assert B + I instanceof Integer
+ assert B + F instanceof Double
+
+ assert I + I instanceof Integer
+ assert I - F instanceof Double
+ assert I * D instanceof Double
+ assert I + BI instanceof BigInteger
+ assert I - BD instanceof BigDecimal
+
+ assert F * L instanceof Double
+ assert D + L instanceof Double
+ assert BI - L instanceof BigInteger
+ assert BD * L instanceof BigDecimal
+
+ assert F + F instanceof Double
+ assert F - BI instanceof Double
+ assert F * BD instanceof Double
+
+ assert F + D instanceof Double
+ assert BI - D instanceof Double
+ assert BD * D instanceof Double
+
+ assert BI + BI instanceof BigInteger
+ assert BD - BI instanceof BigDecimal
+ assert BD * BD instanceof BigDecimal
+
+ //Division (/) promotes differently so change the expected results:
+ assert I / I instanceof BigDecimal
+ assert I / F instanceof Double
+ assert I / D instanceof Double
+ assert I / BI instanceof BigDecimal
+ assert I / BD instanceof BigDecimal
+
+ assert F / L instanceof Double
+ assert D / L instanceof Double
+ assert BI / L instanceof BigDecimal
+ assert BD / L instanceof BigDecimal
+
+ assert F / F instanceof Double
+ assert F / BI instanceof Double
+ assert F / BD instanceof Double
+
+ assert F / D instanceof Double
+ assert BI / D instanceof Double
+ assert BD / D instanceof Double
+
+ assert BI / BI instanceof BigDecimal
+ assert BD / BI instanceof BigDecimal
+ assert BD / BD instanceof BigDecimal
+ }
+
+ void testOperations() {
+ def I1 = new Integer(1)
+ def I2 = new Integer(2)
+ def I3 = new Integer(3)
+ def L1 = new Long(1)
+ def L2 = new Long(2)
+ def L3 = new Long(3)
+ def F1 = new Float("1.0")
+ def F2 = new Float("2.0")
+ def D1 = new Double("1.0")
+ def D2 = new Double("2.0")
+ def BI1 = new BigInteger("1")
+ def BI2 = new BigInteger("2")
+ def BD1 = new BigDecimal("1.0")
+ def BD2 = new BigDecimal("2.0")
+ def BD20 = new BigDecimal("2.00")
+
+ assert I1 / I2 instanceof BigDecimal
+ assert I1 / I2 == new BigDecimal("0.5")
+ assert F1 / F2 instanceof Double
+ assertEquals F1 / F2, 0.5, 0.0000000001
+ assert D1 / D2 instanceof Double
+ assertEquals D1 / D2, 0.5, 0.0000000001
+
+ assert I1.intdiv(I2) instanceof Integer
+ assert I1.intdiv(I2) == 0
+
+ assert I3.intdiv(I2) instanceof Integer
+ assert I3.intdiv(I2) == 1
+
+ assert L1.intdiv(I2) instanceof Long
+ assert L1.intdiv(I2) == 0
+
+ assert L3.intdiv(L2) instanceof Long
+ assert L3.intdiv(L2) == 1
+
+ assert BI1.intdiv(BI2) instanceof BigInteger
+ assert BI1.intdiv(BI2) == 0
+
+ assert I1 / I3 instanceof BigDecimal
+ assert I1 / I3 == new BigDecimal("0.3333333333")
+
+ assert I2 / I3 instanceof BigDecimal
+ assert I2 / I3 == new BigDecimal("0.6666666667")
+
+ assert I1 / BD2 instanceof BigDecimal
+
+ //Test keeping max scale of (L, R or 10)
+ def BBD1 = new BigDecimal("0.12345678901234567")
+ assert BD1 + BBD1 == new BigDecimal("1.12345678901234567")
+
+ def BBD2 = new BigDecimal(".000000000000000008")
+ assert BBD1 + BBD2 == new BigDecimal("0.123456789012345678")
+ }
+
+ void testUnsupportedIntDivision() {
+ try {
+ 1.0.intdiv(3)
+ } catch (UnsupportedOperationException ignore) {
+ return
+ }
+ fail("Should catch an UnsupportedOperationException")
+
+ try {
+ 1.0G.intdiv(3)
+ } catch (UnsupportedOperationException ignore) {
+ return
+ }
+ fail("Should catch an UnsupportedOperationException")
+ }
+
+
+ private static class MyNumber extends Number {
+ def n
+
+ MyNumber(n) {
+ this.n = n
+ }
+
+ int intValue() { n }
+
+ long longValue() { n }
+
+ float floatValue() { n }
+
+ double doubleValue() { n }
+
+ int hashCode() { -n }
+
+ boolean equals(other) {
+ if (other instanceof MyNumber) {
+ return n == other.n
+ }
+ return false
+ }
+
+ String toString() { return Double.toString(floatValue()) }
+ }
+
+ void testGetMathCustom() {
+ assert getMath(1G) == BigIntegerMath.INSTANCE;
+ assert getMath(1.0G) == BigDecimalMath.INSTANCE;
+ assert getMath(Long.valueOf(1)) == LongMath.INSTANCE;
+ assert getMath(Integer.valueOf(1)) == IntegerMath.INSTANCE;
+ assert getMath(Short.valueOf("1")) == IntegerMath.INSTANCE;
+ assert getMath(Byte.valueOf("1")) == IntegerMath.INSTANCE;
+ assert getMath(Double.valueOf(1.0)) == FloatingPointMath.INSTANCE;
+ assert getMath(Float.valueOf(1.0f)) == FloatingPointMath.INSTANCE;
+
+ MyNumber num = new MyNumber(42);
+ assert getMath(num) == BigDecimalMath.INSTANCE;
+
+ assert getMath(num, Integer.valueOf(25)) == BigDecimalMath.INSTANCE;
+ assert getMath(num, Double.valueOf(25.0)) == FloatingPointMath.INSTANCE;
+ assert getMath(Integer.valueOf(25), num) == BigDecimalMath.INSTANCE;
+ assert getMath(Double.valueOf(25.0), num) == FloatingPointMath.INSTANCE;
+ assert getMath(num, 25) == BigDecimalMath.INSTANCE;
+ assert getMath(25, num) == BigDecimalMath.INSTANCE;
+ }
+
+ void testGetMath() {
+ assert 20 == new Short("10") << 1
+ assert 2 == new Byte("1") << 1
+ }
+
+ void testLongDivAssign() {
+ long d = 100L
+ d /= 33L
+ assert d.class == Long.class
+ }
+
+ void testIntegerPlusCastException() {
+ shouldFail(ClassCastException) {
+ Integer i = 12
+ i += " angry men"
+ }
+ }
+}