DRILL-799: Use static constants instead of Math.pow() to compute powers of 10 
while adjusting scale of decimal data type.


Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/aad2c4ff
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/aad2c4ff
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/aad2c4ff

Branch: refs/heads/master
Commit: aad2c4ff29a5246b55b1640a29e04fc51066a63b
Parents: 5746032
Author: Mehant Baid <[email protected]>
Authored: Thu Jun 5 09:23:28 2014 -0700
Committer: Jacques Nadeau <[email protected]>
Committed: Thu Jun 5 20:08:19 2014 -0700

----------------------------------------------------------------------
 .../drill/common/util/DecimalUtility.java       | 54 ++++++++++++++++++++
 exec/java-exec/src/main/codegen/data/Casts.tdd  |  4 +-
 .../templates/Decimal/CastDecimalFloat.java     |  2 +-
 .../templates/Decimal/CastDecimalInt.java       |  2 +-
 .../templates/Decimal/CastDecimalVarchar.java   |  4 +-
 .../templates/Decimal/CastIntDecimal.java       |  2 +-
 .../templates/Decimal/CastSrcDecimalSimple.java |  6 +--
 .../templates/Decimal/CastVarCharDecimal.java   |  6 +--
 .../templates/Decimal/DecimalFunctions.java     | 29 ++++++-----
 9 files changed, 82 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java
----------------------------------------------------------------------
diff --git 
a/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java 
b/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java
index ff8725f..ae2af54 100644
--- a/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java
+++ b/common/src/main/java/org/apache/drill/common/util/DecimalUtility.java
@@ -45,6 +45,60 @@ public class DecimalUtility {
             "00000000",
             "000000000"};
 
+    public final static long[] scale_long_constants = {
+        1,
+        10,
+        100,
+        1000,
+        10000,
+        100000,
+        1000000,
+        10000000,
+        100000000,
+        1000000000,
+        10000000000l,
+        100000000000l,
+        1000000000000l,
+        10000000000000l,
+        100000000000000l,
+        1000000000000000l,
+        10000000000000000l,
+        100000000000000000l,
+        1000000000000000000l};
+
+    /*
+     * Simple function that returns the static precomputed
+     * power of ten, instead of using Math.pow
+     */
+    public static long getPowerOfTen(int power) {
+      assert power >= 0 && power < scale_long_constants.length;
+      return scale_long_constants[(power)];
+    }
+
+    /*
+     * Math.pow returns a double and while multiplying with large digits
+     * in the decimal data type we encounter noise. So instead of multiplying
+     * with Math.pow we use the static constants to perform the multiplication
+     */
+    public static long adjustScaleMultiply(long input, int factor) {
+      int index = Math.abs(factor);
+      assert index >= 0 && index < scale_long_constants.length;
+      if (factor >= 0) {
+        return input * scale_long_constants[index];
+      } else {
+        return input / scale_long_constants[index];
+      }
+    }
+
+    public static long adjustScaleDivide(long input, int factor) {
+      int index = Math.abs(factor);
+      assert index >= 0 && index < scale_long_constants.length;
+      if (factor >= 0) {
+        return input / scale_long_constants[index];
+      } else {
+        return input * scale_long_constants[index];
+      }
+    }
 
     /* Given the number of actual digits this function returns the
      * number of indexes it will occupy in the array of integers

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/data/Casts.tdd
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/codegen/data/Casts.tdd 
b/exec/java-exec/src/main/codegen/data/Casts.tdd
index 73cdede..e49df93 100644
--- a/exec/java-exec/src/main/codegen/data/Casts.tdd
+++ b/exec/java-exec/src/main/codegen/data/Casts.tdd
@@ -147,8 +147,8 @@
     {from: "Decimal38Sparse", to: "Float8", major: "DecimalComplexDouble", 
javatype: "double"},
     {from: "Decimal38Dense", to: "Float8", major: "DecimalComplexDouble", 
javatype: "double"},
 
-    {from: "VarChar", to: "Decimal9", major: "VarCharDecimalSimple"},
-    {from: "VarChar", to: "Decimal18", major: "VarCharDecimalSimple"},
+    {from: "VarChar", to: "Decimal9", major: "VarCharDecimalSimple", javatype: 
"int"},
+    {from: "VarChar", to: "Decimal18", major: "VarCharDecimalSimple", 
javatype: "long"},
     {from: "VarChar", to: "Decimal28Sparse", major: "VarCharDecimalComplex", 
arraySize: "5"},
     {from: "VarChar", to: "Decimal38Sparse", major: "VarCharDecimalComplex", 
arraySize: "6"},
 

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalFloat.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalFloat.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalFloat.java
index 9e2e48d..b259cb3 100644
--- a/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalFloat.java
+++ b/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalFloat.java
@@ -52,7 +52,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
     public void eval() {
 
         // Divide the decimal with the scale to get the floating point value
-        out.value = (${type.javatype}) (in.value / Math.pow(10, in.scale));
+        out.value = (${type.javatype}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleDivide(in.value, (int) 
in.scale));
     }
 }
 <#elseif type.major == "DecimalComplexFloat" || type.major == 
"DecimalComplexDouble"> <#-- Cast function template for conversion from 
Decimal9, Decimal18 to Float4 -->

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalInt.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalInt.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalInt.java
index 646f52c..a89965f 100644
--- a/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalInt.java
+++ b/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalInt.java
@@ -53,7 +53,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
     public void eval() {
 
         // Assign the integer part of the decimal to the output holder
-        out.value = (${type.javatype}) ((in.value / Math.pow(10, in.scale)));
+        out.value = (${type.javatype}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleDivide(in.value, (int) 
in.scale));
     }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalVarchar.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalVarchar.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalVarchar.java
index 52e5513..783165f 100644
--- a/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalVarchar.java
+++ b/exec/java-exec/src/main/codegen/templates/Decimal/CastDecimalVarchar.java
@@ -67,7 +67,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
             in.value *= -1;
         }
 
-        ${type.javatype} separator = (${type.javatype}) Math.pow(10, in.scale);
+        ${type.javatype} separator = (${type.javatype}) 
org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) in.scale);
 
         str.append(in.value / separator);
 
@@ -192,7 +192,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
             if (actualDigits != 0) {
 
                 // Strip padded zeroes at the end that is not part of the scale
-                lastFractionalDigit /= (int) (Math.pow(10, 
org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - actualDigits));
+                lastFractionalDigit /= (int) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) 
(org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - actualDigits)));
                 
str.append(org.apache.drill.common.util.DecimalUtility.toStringWithZeroes(lastFractionalDigit,
 actualDigits));
             } else {
                 // Last digit does not have any padding print as is

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/CastIntDecimal.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastIntDecimal.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastIntDecimal.java
index 525566a..979e7e2 100644
--- a/exec/java-exec/src/main/codegen/templates/Decimal/CastIntDecimal.java
+++ b/exec/java-exec/src/main/codegen/templates/Decimal/CastIntDecimal.java
@@ -66,7 +66,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
         out.value = (${type.javatype}) in.value;
 
         // converting from integer to decimal, pad zeroes if scale is non zero
-        out.value = (${type.javatype}) (out.value * Math.pow(10, scale.value));
+        out.value = (${type.javatype}) 
org.apache.drill.common.util.DecimalUtility.adjustScaleMultiply(out.value, 
(int) scale.value);
 
         <#else>
         out.start = 0;

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/CastSrcDecimalSimple.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastSrcDecimalSimple.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastSrcDecimalSimple.java
index 36a6ef3..b298c66 100644
--- 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastSrcDecimalSimple.java
+++ 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastSrcDecimalSimple.java
@@ -189,10 +189,10 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc{
             if (power == 0) {
                 power = 9;
             } else {
-                padding = (int) (Math.pow(10, 
(org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - power)));
+                padding = (int) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) 
(org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - power)));
             }
 
-            int mask = (int) Math.pow(10, power);
+            int mask = (int) 
org.apache.drill.common.util.DecimalUtility.getPowerOfTen(power);
 
             out.setInteger(index, (int) ((value % mask) * padding));
 
@@ -254,7 +254,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
         out.value = in.value;
 
         // Truncate or pad additional zeroes if the output scale is different 
from input scale
-        out.value = (${type.javatype}) (out.value * ((int) Math.pow(10, 
(out.scale - in.scale))));
+        out.value = (${type.javatype}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleMultiply(out.value, 
(int) (out.scale - in.scale)));
     }
 }
 </#if>

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/CastVarCharDecimal.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/CastVarCharDecimal.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/CastVarCharDecimal.java
index 8441298..9ca0533 100644
--- a/exec/java-exec/src/main/codegen/templates/Decimal/CastVarCharDecimal.java
+++ b/exec/java-exec/src/main/codegen/templates/Decimal/CastVarCharDecimal.java
@@ -134,7 +134,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
 
         // Pad the number with zeroes if number of fractional digits is less 
than scale
         if (fractionalDigits < scale.value) {
-            out.value *= Math.pow(10, scale.value - fractionalDigits);
+            out.value = (${type.javatype}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleMultiply(out.value, 
(int) (scale.value - fractionalDigits)));
         }
 
         // Negate the number if we saw a -ve sign
@@ -292,7 +292,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
 
             next = (byte) Character.digit(next, radix);
 
-            int value = (((int) Math.pow(10, ndigits)) * next) + 
(out.getInteger(decimalBufferIndex));
+            int value = (((int) 
org.apache.drill.common.util.DecimalUtility.getPowerOfTen(ndigits)) * next) + 
(out.getInteger(decimalBufferIndex));
             out.setInteger(decimalBufferIndex, value);
 
             ndigits++;
@@ -337,7 +337,7 @@ public class Cast${type.from}${type.to} implements 
DrillSimpleFunc {
                 ndigits++;
             }
             // Pad zeroes in the fractional part so that number of digits = 
MAX_DIGITS
-            int padding = (int) Math.pow(10, 
org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - ndigits);
+            int padding = (int) 
org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) 
(org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - ndigits));
             out.setInteger(decimalBufferIndex, 
out.getInteger(decimalBufferIndex) * padding);
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/aad2c4ff/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java
----------------------------------------------------------------------
diff --git 
a/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java 
b/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java
index cff122e..b294396 100644
--- a/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java
+++ b/exec/java-exec/src/main/codegen/templates/Decimal/DecimalFunctions.java
@@ -236,10 +236,10 @@ import org.apache.drill.exec.expr.annotations.Workspace;
             int adjustment = 0;
 
             if (left.scale < right.scale) {
-                left.value = (${javaType}) (left.value * Math.pow(10, 
(right.scale - left.scale)));
+                left.value = (${javaType}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleMultiply(left.value, 
(int) (right.scale - left.scale)));
                 left.scale = right.scale;
             } else if (right.scale < left.scale) {
-                right.value = (${javaType}) (right.value * Math.pow(10, 
(left.scale - right.scale)));
+                right.value = (${javaType}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleMultiply(right.value, 
(int) (left.scale - right.scale)));
                 right.scale = left.scale;
             }
 </#macro>
@@ -800,7 +800,7 @@ public class ${type.name}Functions {
             // We truncated the decimal digit. Now we need to truncate within 
the base 1 billion fractional digit
             int truncateFactor = 
org.apache.drill.common.util.DecimalUtility.MAX_DIGITS - (right.value % 
org.apache.drill.common.util.DecimalUtility.MAX_DIGITS);
             if (truncateFactor != 
org.apache.drill.common.util.DecimalUtility.MAX_DIGITS) {
-              truncateFactor = (int) Math.pow(10, truncateFactor);
+              truncateFactor = (int) 
org.apache.drill.common.util.DecimalUtility.getPowerOfTen(truncateFactor);
               int fractionalDigits = result.getInteger(${type.storage} - 1);
               fractionalDigits /= truncateFactor;
               result.setInteger(${type.storage} - 1, fractionalDigits * 
truncateFactor);
@@ -1305,7 +1305,7 @@ public class ${type.name}Functions {
 
         public void eval() {
 
-            out.value =(${type.storage}) (in.value / (Math.pow(10, in.scale)));
+            out.value =(${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleDivide(in.value, (int) 
in.scale));
             out.precision = out.maxPrecision;
             out.scale = 0;
         }
@@ -1322,7 +1322,7 @@ public class ${type.name}Functions {
 
         public void eval() {
 
-            out.value = (${type.storage}) (left.value / ( Math.pow(10, 
(left.scale - right.value))));
+            out.value = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleDivide(left.value, 
(int) (left.scale - right.value)));
             out.precision = out.maxPrecision;
             out.scale = right.value;
         }
@@ -1339,7 +1339,7 @@ public class ${type.name}Functions {
         }
 
         public void eval() {
-          ${type.storage} scaleFactor = (${type.storage}) (Math.pow(10, 
in.scale));
+          ${type.storage} scaleFactor = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) in.scale));
 
           // Get the integer part
           ${type.storage} integerPart = in.value / scaleFactor;
@@ -1366,7 +1366,7 @@ public class ${type.name}Functions {
 
         public void eval() {
 
-          ${type.storage} scaleFactor = (${type.storage}) (Math.pow(10, 
in.scale));
+          ${type.storage} scaleFactor = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) in.scale));
           out.scale = 0;
           out.value = (in.value / scaleFactor);
 
@@ -1391,7 +1391,7 @@ public class ${type.name}Functions {
 
         public void eval() {
 
-          ${type.storage} scaleFactor = (${type.storage}) (Math.pow(10, 
in.scale));
+          ${type.storage} scaleFactor = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) in.scale));
           ${type.storage} extractDigit = scaleFactor / 10;
 
           out.scale = 0;
@@ -1426,13 +1426,14 @@ public class ${type.name}Functions {
 
         public void eval() {
 
-          ${type.storage} scaleFactor = (${type.storage}) (Math.pow(10, 
left.scale));
-          ${type.storage} newScaleFactor = (${type.storage}) (Math.pow(10, 
right.value));
-          ${type.storage} truncScaleFactor = (${type.storage}) (Math.pow(10, 
left.scale - right.value));
+          ${type.storage} scaleFactor = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) left.scale));
+          ${type.storage} newScaleFactor = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen((int) right.value));
+          ${type.storage} truncScaleFactor = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.getPowerOfTen( Math.abs(left.scale 
- right.value)));
+          int truncFactor = (int) (left.scale - right.value);
 
           // If rounding scale is >= current scale
           if (right.value >= left.scale) {
-            out.value = (${type.storage}) (left.value * (int) Math.pow(10, 
(right.value - left.scale)));
+            out.value = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleMultiply(left.value, 
(int) (right.value - left.scale)));
           }
           else {
             out.scale = right.value;
@@ -1443,12 +1444,12 @@ public class ${type.name}Functions {
             ${type.storage} fractionalPart = left.value % scaleFactor;
 
             // From the entire fractional part extract the digits upto which 
rounding is needed
-            ${type.storage} newFractionalPart = fractionalPart / 
truncScaleFactor;
+            ${type.storage} newFractionalPart = (${type.storage}) 
(org.apache.drill.common.util.DecimalUtility.adjustScaleDivide(fractionalPart, 
truncFactor));
             ${type.storage} truncatedFraction = fractionalPart % 
truncScaleFactor;
 
 
             // Get the truncated fractional part and extract the first digit 
to see if we need to add 1
-            int digit = Math.abs((int) (truncatedFraction / (truncScaleFactor 
/ 10)));
+            int digit = Math.abs((int) 
org.apache.drill.common.util.DecimalUtility.adjustScaleDivide(truncatedFraction,
 truncFactor - 1));
 
             if (digit > 4) {
               if (left.value > 0) {

Reply via email to