You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by mm...@apache.org on 2016/12/22 08:32:31 UTC

[02/10] hive git commit: HIVE-15335: Fast Decimal (Matt McCline, reviewed by Sergey Shelukhin, Prasanth Jayachandran, Owen O'Malley)

http://git-wip-us.apache.org/repos/asf/hive/blob/4ba713cc/storage-api/src/test/org/apache/hadoop/hive/common/type/TestHiveDecimal.java
----------------------------------------------------------------------
diff --git a/storage-api/src/test/org/apache/hadoop/hive/common/type/TestHiveDecimal.java b/storage-api/src/test/org/apache/hadoop/hive/common/type/TestHiveDecimal.java
new file mode 100644
index 0000000..f8a36e5
--- /dev/null
+++ b/storage-api/src/test/org/apache/hadoop/hive/common/type/TestHiveDecimal.java
@@ -0,0 +1,3404 @@
+/**
+ * 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.apache.hadoop.hive.common.type;
+
+import java.sql.Timestamp;
+import java.util.Random;
+import java.util.Arrays;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.apache.hadoop.hive.serde2.io.HiveDecimalWritableV1;
+import org.apache.hadoop.hive.serde2.io.HiveDecimalWritable;
+import org.apache.hadoop.hive.common.type.RandomTypeUtil;
+import org.apache.hadoop.hive.ql.exec.vector.expressions.StringExpr;
+import org.apache.hadoop.hive.ql.util.TimestampUtils;
+
+import org.junit.*;
+
+import static org.junit.Assert.*;
+
+public class TestHiveDecimal extends HiveDecimalTestBase {
+
+  @Test
+  public void testInvalidStringInput() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimalV1 resultOldDec;
+    HiveDecimal dec;
+    HiveDecimal resultDec;
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("-");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("-");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("+");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("+");
+    Assert.assertTrue(dec == null);
+
+    // Naked dot.
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(".");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create(".");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("-.");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("-.");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("+.");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("+.");
+    Assert.assertTrue(dec == null);
+
+    // Naked E/e.
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("E");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("E");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(".E");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create(".E");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("-E");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("-E");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("+E");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("+E");
+    Assert.assertTrue(dec == null);
+ 
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(".e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create(".e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("-e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("-e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("+e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("+e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("error");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("error");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("0x0");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("0x0");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("0e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("0e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("7e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("7e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("233e-");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("233e-");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("32e+");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("32e+");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(".0e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create(".0e");
+    Assert.assertTrue(dec == null);
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(".4e");
+    Assert.assertTrue(oldDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create(".4e");
+    Assert.assertTrue(dec == null);
+  }
+
+  @Test
+  public void testVariousCases() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimalV1 resultOldDec;
+    HiveDecimal dec;
+    HiveDecimal resultDec;
+
+    BigDecimal bigDecimal = new BigDecimal("-99999999999999999999999999999999999999.99999999999999999");
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(bigDecimal);
+    Assert.assertEquals("-100000000000000000000000000000000000000", oldDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(bigDecimal);
+    Assert.assertTrue(dec == null);
+
+    // One less integer digit...
+    bigDecimal = new BigDecimal("-9999999999999999999999999999999999999.99999999999999999");
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(bigDecimal);
+    Assert.assertEquals("-10000000000000000000000000000000000000", oldDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(bigDecimal);
+    Assert.assertEquals("-10000000000000000000000000000000000000", dec.toString());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("101");
+    resultOldDec = HiveDecimalV1.enforcePrecisionScale(oldDec, 10, 0);
+    Assert.assertEquals("101", resultOldDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create("101");
+    resultDec = HiveDecimal.enforcePrecisionScale(dec, 10, 0);
+    Assert.assertEquals("101", resultDec.toString());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("1");
+    resultOldDec = oldDec.scaleByPowerOfTen(-99);
+    Assert.assertEquals("0", resultOldDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create("1");
+    resultDec = dec.scaleByPowerOfTen(-99);
+    Assert.assertEquals("0", resultDec.toString());
+  }
+
+  @Test
+  public void testCreateFromBigIntegerRounding() {
+
+    BigInteger bigInt;
+    HiveDecimalV1 oldDec;
+    HiveDecimal dec;
+
+    // 1786135888657847525803324040144343378.09799306448796128931113691624
+    bigInt = new BigInteger(
+                        "178613588865784752580332404014434337809799306448796128931113691624");
+    Assert.assertEquals("178613588865784752580332404014434337809799306448796128931113691624", bigInt.toString());
+    //                   12345678901234567890123456789012345678
+    //                            1         2         3
+    //                                                        12345678901234567890123456789
+    dec = HiveDecimal.create(bigInt, 29);
+    Assert.assertEquals("1786135888657847525803324040144343378.1", dec.toString());
+
+    // 8.090000000000000000000000000000000000000123456
+    bigInt = new BigInteger(
+                        "8090000000000000000000000000000000000000123456");
+    //                   123456789012345678901234567890123456789012345
+    //                             1         2         3         4
+    Assert.assertEquals("8090000000000000000000000000000000000000123456", bigInt.toString());
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(bigInt, 45);
+    Assert.assertEquals("8.09", oldDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(bigInt, 45);
+    Assert.assertEquals("8.09", dec.toString());
+
+    // 99999999.99999999999999999999999999999949999
+    // MAX_DECIMAL 9's WITH NO ROUND (longer than 38 digits)
+    bigInt = new BigInteger(
+                        "9999999999999999999999999999999999999949999");
+    //                   12345678901234567890123456789012345678
+    //                             1         2         3
+    //                   99999999.99999999999999999999999999999949999
+    Assert.assertEquals("9999999999999999999999999999999999999949999", bigInt.toString());
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(bigInt, 35);
+    Assert.assertEquals("99999999.999999999999999999999999999999", oldDec.toString());
+    //---------------------------------------------------
+    // Without the round, this conversion fails.
+    dec = HiveDecimal.create(bigInt, 35);
+    Assert.assertEquals("99999999.999999999999999999999999999999", dec.toString());
+
+    // MAX_DECIMAL 9's WITH ROUND.
+    bigInt = new BigInteger(
+                        "9999999999999999999999999999999999999979999");
+    //                   12346678.901234667890123466789012346678
+    //                             1         2         3
+    Assert.assertEquals("9999999999999999999999999999999999999979999", bigInt.toString());
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(bigInt, 35);
+    Assert.assertEquals("100000000", oldDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(bigInt, 35);
+    Assert.assertEquals("100000000", dec.toString());
+  }
+
+  @Test
+  public void testCreateFromBigDecimal() {
+
+    BigDecimal bigDec;
+    HiveDecimalV1 oldDec;
+    HiveDecimal dec;
+
+    bigDec = new BigDecimal("0");
+    Assert.assertEquals("0", bigDec.toString());
+    dec = HiveDecimal.create(bigDec);
+    Assert.assertEquals("0", dec.toString());
+
+    bigDec = new BigDecimal("1");
+    Assert.assertEquals("1", bigDec.toString());
+    dec = HiveDecimal.create(bigDec);
+    Assert.assertEquals("1", dec.toString());
+
+    bigDec = new BigDecimal("0.999");
+    Assert.assertEquals("0.999", bigDec.toString());
+    dec = HiveDecimal.create(bigDec);
+    Assert.assertEquals("0.999", dec.toString());
+
+    // HiveDecimal suppresses trailing zeroes.
+    bigDec = new BigDecimal("0.9990");
+    Assert.assertEquals("0.9990", bigDec.toString());
+    dec = HiveDecimal.create(bigDec);
+    Assert.assertEquals("0.999", dec.toString());
+  }
+
+  @Test
+  public void testCreateFromBigDecimalRounding() {
+
+    BigDecimal bigDec;
+    HiveDecimalV1 oldDec;
+    HiveDecimal dec;
+
+    bigDec = new BigDecimal(
+                        "1786135888657847525803324040144343378.09799306448796128931113691624");
+    Assert.assertEquals("1786135888657847525803324040144343378.09799306448796128931113691624", bigDec.toString());
+    //                   1234567890123456789012345678901234567.8
+    //                            1         2         3
+    // Without the round, this conversion fails.
+    dec = HiveDecimal.create(bigDec, false);
+    Assert.assertTrue(dec == null);
+    dec = HiveDecimal.create(bigDec, true);
+    Assert.assertEquals("1786135888657847525803324040144343378.1", dec.toString());
+
+    bigDec = new BigDecimal(
+                        "8.090000000000000000000000000000000000000123456");
+    //                   1.23456789012345678901234567890123456789012345
+    //                             1         2         3         4
+    Assert.assertEquals("8.090000000000000000000000000000000000000123456", bigDec.toString());
+    //---------------------------------------------------
+    HiveDecimalV1 oldDec4 = HiveDecimalV1.create(bigDec, false);
+    Assert.assertTrue(oldDec4 == null);
+    oldDec4 = HiveDecimalV1.create(bigDec, true);
+    Assert.assertEquals("8.09", oldDec4.toString());
+    //---------------------------------------------------
+    // Without the round, this conversion fails.
+    dec = HiveDecimal.create(bigDec, false);
+    Assert.assertTrue(dec == null);
+    dec = HiveDecimal.create(bigDec, true);
+    Assert.assertEquals("8.09", dec.toString());
+
+    // MAX_DECIMAL 9's WITH NO ROUND (longer than 38 digits)
+    bigDec = new BigDecimal(
+                        "99999999.99999999999999999999999999999949999");
+    //                   12345678.901234567890123456789012345678
+    //                             1         2         3
+    Assert.assertEquals("99999999.99999999999999999999999999999949999", bigDec.toString());
+    //---------------------------------------------------
+    HiveDecimalV1 oldDec5 = HiveDecimalV1.create(bigDec, false);
+    Assert.assertTrue(oldDec5 == null);
+    oldDec5 = HiveDecimalV1.create(bigDec, true);
+    Assert.assertEquals("99999999.999999999999999999999999999999", oldDec5.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(bigDec, false);
+    Assert.assertTrue(dec == null);
+    dec = HiveDecimal.create(bigDec, true);
+    Assert.assertEquals("99999999.999999999999999999999999999999", dec.toString());
+
+    // MAX_DECIMAL 9's WITH ROUND.
+    bigDec = new BigDecimal(
+                        "99999999.99999999999999999999999999999979999");
+    //                   12346678.901234667890123466789012346678
+    //                             1         2         3
+    Assert.assertEquals("99999999.99999999999999999999999999999979999", bigDec.toString());
+    //---------------------------------------------------
+    HiveDecimalV1 oldDec6 = HiveDecimalV1.create(bigDec, false);
+    Assert.assertTrue(oldDec6 == null);
+    oldDec6 = HiveDecimalV1.create(bigDec, true);
+    Assert.assertEquals("100000000", oldDec6.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(bigDec, false);
+    Assert.assertTrue(dec == null);
+    dec = HiveDecimal.create(bigDec, true);
+    Assert.assertEquals("100000000", dec.toString());
+  }
+
+
+  @Test
+  public void testPrecisionScaleEnforcement() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimalV1 oldResultDec;
+
+    HiveDecimal dec;
+    HiveDecimal resultDec;
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("0.02538461538461538461538461538461538462");
+    Assert.assertEquals("0.02538461538461538461538",
+        HiveDecimalV1.enforcePrecisionScale(oldDec, 38, 23).toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create("0.02538461538461538461538461538461538462");
+    Assert.assertEquals("0.02538461538461538461538",
+        HiveDecimal.enforcePrecisionScale(dec, 38, 23).toString());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("005.34000");
+    Assert.assertEquals(oldDec.precision(), 3);  // 1 integer digit; 2 fraction digits.
+    Assert.assertEquals(oldDec.scale(), 2);      // Trailing zeroes are suppressed.
+    //---------------------------------------------------
+    dec = HiveDecimal.create("005.34000");
+    Assert.assertEquals(dec.precision(), 3);  // 1 integer digit; 2 fraction digits.
+    Assert.assertEquals(dec.scale(), 2);      // Trailing zeroes are suppressed.
+
+    dec = HiveDecimal.create("178613588865784752580332404014434337809799306448796128931113691624");
+    Assert.assertNull(dec);
+
+    // Rounding numbers that increase int digits
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("9.5");
+    Assert.assertEquals("10",
+        HiveDecimalV1.enforcePrecisionScale(oldDec, 2, 0).toString());
+    Assert.assertNull(
+        HiveDecimalV1.enforcePrecisionScale(oldDec, 1, 0));
+    oldDec = HiveDecimalV1.create("9.4");
+    Assert.assertEquals("9",
+        HiveDecimalV1.enforcePrecisionScale(oldDec, 1, 0).toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create("9.5");
+    Assert.assertEquals("10",
+        HiveDecimal.enforcePrecisionScale(dec, 2, 0).toString());
+    Assert.assertNull(
+        HiveDecimal.enforcePrecisionScale(dec, 1, 0));
+    dec = HiveDecimal.create("9.4");
+    Assert.assertEquals("9",
+        HiveDecimal.enforcePrecisionScale(dec, 1, 0).toString());
+  }
+
+  @Test
+  public void testPrecisionScaleEnforcementEdgeCond() {
+
+    // Since HiveDecimal now uses FastHiveDecimal which stores 16 decimal digits per long,
+    // lets test edge conditions here.
+
+    HiveDecimal fifteenFractionalNinesDec = HiveDecimal.create("0.999999999999999");
+    Assert.assertNotNull(fifteenFractionalNinesDec);
+    Assert.assertEquals("0.999999999999999",
+        HiveDecimal.enforcePrecisionScale(fifteenFractionalNinesDec, 15, 15).toString());
+
+    HiveDecimal sixteenFractionalNines = HiveDecimal.create("0.9999999999999999");
+    Assert.assertNotNull(sixteenFractionalNines);
+    Assert.assertEquals("0.9999999999999999",
+        HiveDecimal.enforcePrecisionScale(sixteenFractionalNines, 16, 16).toString());
+
+    HiveDecimal seventeenFractionalNines = HiveDecimal.create("0.99999999999999999");
+    Assert.assertNotNull(seventeenFractionalNines);
+    Assert.assertEquals("0.99999999999999999",
+        HiveDecimal.enforcePrecisionScale(seventeenFractionalNines, 17, 17).toString());
+
+  }
+
+  @Test
+  public void testTrailingZeroRemovalAfterEnforcement() {
+    String decStr = "8.090000000000000000000000000000000000000123456";
+    //                 123456789012345678901234567890123456789012345
+    //                          1         2         3         4
+    HiveDecimal dec = HiveDecimal.create(decStr);
+    Assert.assertEquals("8.09", dec.toString());
+  }
+
+  @Test
+  public void testMultiply() {
+
+    // This multiply produces more than 38 digits --> overflow.
+    //---------------------------------------------------
+    HiveDecimalV1 oldDec1 = HiveDecimalV1.create("0.00001786135888657847525803");
+    HiveDecimalV1 oldDec2 = HiveDecimalV1.create("3.0000123456789");
+    HiveDecimalV1 oldResult = oldDec1.multiply(oldDec2);
+    Assert.assertTrue(oldResult == null);
+    //---------------------------------------------------
+    HiveDecimal dec1 = HiveDecimal.create("0.00001786135888657847525803");
+    HiveDecimal dec2 = HiveDecimal.create("3.0000123456789");
+    HiveDecimal result = dec1.multiply(dec2);
+    Assert.assertTrue(result == null);
+
+    dec1 = HiveDecimal.create("178613588865784752580323232232323444.4");
+    dec2 = HiveDecimal.create("178613588865784752580302323232.3");
+    Assert.assertNull(dec1.multiply(dec2));   // i.e. Overflow.
+
+    dec1 = HiveDecimal.create("47.324");
+    dec2 = HiveDecimal.create("9232.309");
+    Assert.assertEquals("436909.791116", dec1.multiply(dec2).toString());
+
+    dec1 = HiveDecimal.create("3.140");
+    dec2 = HiveDecimal.create("1.00");
+    Assert.assertEquals("3.14", dec1.multiply(dec2).toString());
+
+    dec1 = HiveDecimal.create("43.010");
+    dec2 = HiveDecimal.create("2");
+    Assert.assertEquals("86.02", dec1.multiply(dec2).toString());
+  }
+
+  @Test
+  public void testMultiply2() {
+    // 0.09765625BD * 0.09765625BD * 0.0125BD * 578992BD
+    HiveDecimal dec1 = HiveDecimal.create("0.09765625");
+    HiveDecimal dec2 = HiveDecimal.create("0.09765625");
+    HiveDecimal dec3 = HiveDecimal.create("0.0125");
+    HiveDecimal dec4 = HiveDecimal.create("578992");
+    HiveDecimal result1 = dec1.multiply(dec2);
+    Assert.assertNotNull(result1);
+    HiveDecimal result2 = result1.multiply(dec3);
+    Assert.assertNotNull(result2);
+    HiveDecimal result = result2.multiply(dec4);
+    Assert.assertNotNull(result);
+    Assert.assertEquals("69.0212249755859375", result.toString());
+  }
+
+  @Test
+  public void testPow() {
+
+    HiveDecimal dec;
+
+    dec = HiveDecimal.create("3.00001415926");
+    HiveDecimal decPow2 = dec.pow(2);
+    HiveDecimal decMultiplyTwice = dec.multiply(dec);
+    Assert.assertEquals(decPow2, decMultiplyTwice);
+
+    dec = HiveDecimal.create("0.000017861358882");
+    dec = dec.pow(3);
+    Assert.assertNull(dec);
+
+    dec = HiveDecimal.create("3.140");
+    Assert.assertEquals("9.8596", dec.pow(2).toString());
+  }
+
+  @Test
+  public void testScaleByPowerOfTen() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimal dec;
+    HiveDecimalV1 oldResultDec;
+    HiveDecimal resultDec;
+
+    //**********************************************************************************************
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(
+        "1");
+    Assert.assertEquals(0, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(2);
+    Assert.assertEquals(
+        "100", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(
+        "1");
+    Assert.assertEquals(0, dec.scale());
+    // resultDec = dec.scaleByPowerOfTen(2);
+    // Assert.assertEquals(
+    //     "100", resultDec.toString());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(2);
+    Assert.assertEquals(
+        "0.000000000000000000000000000000000001", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, dec.scale());
+    resultDec = dec.scaleByPowerOfTen(2);
+    Assert.assertEquals(
+        "0.000000000000000000000000000000000001", resultDec.toString());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(38);
+    Assert.assertEquals(
+        "1", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, dec.scale());
+    resultDec = dec.scaleByPowerOfTen(38);
+    Assert.assertEquals(
+        "1", resultDec.toString());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(2 * 38 - 1);
+    Assert.assertEquals(
+        "10000000000000000000000000000000000000", oldResultDec.toString());
+    Assert.assertEquals(0, oldResultDec.scale());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, dec.scale());
+    resultDec = dec.scaleByPowerOfTen(2 * 38 - 1);
+    Assert.assertEquals(
+        "10000000000000000000000000000000000000", resultDec.toString());
+    Assert.assertEquals(0, resultDec.scale());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(2 * 38);
+    Assert.assertTrue(oldResultDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create(
+        "0.00000000000000000000000000000000000001");
+    Assert.assertEquals(38, dec.scale());
+    resultDec = dec.scaleByPowerOfTen(2 * 38);
+    Assert.assertTrue(resultDec == null);
+
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(
+        "0.00000000000000000000000000000000000022");
+    Assert.assertEquals(38, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(38);
+    Assert.assertEquals(
+        "22", oldResultDec.toString());
+    Assert.assertEquals(0, oldResultDec.scale());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(
+        "0.00000000000000000000000000000000000022");
+    Assert.assertEquals(38, dec.scale());
+    resultDec = dec.scaleByPowerOfTen(38);
+    Assert.assertEquals(
+        "22", resultDec.toString());
+    Assert.assertEquals(0, resultDec.scale());
+
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("3.00001415926");
+    Assert.assertEquals(11, oldDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(2);
+    Assert.assertEquals("300.001415926", oldResultDec.toString());
+    Assert.assertEquals(9, oldResultDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(5);
+    Assert.assertEquals("300001.415926", oldResultDec.toString());
+    Assert.assertEquals(6, oldResultDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(18);
+    Assert.assertEquals("3000014159260000000", oldResultDec.toString());
+    Assert.assertEquals(0, oldResultDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(35);
+    Assert.assertEquals("300001415926000000000000000000000000", oldResultDec.toString());
+    Assert.assertEquals(0, oldResultDec.scale());
+    oldResultDec = oldDec.scaleByPowerOfTen(37);
+    Assert.assertEquals("30000141592600000000000000000000000000", oldResultDec.toString());
+    Assert.assertEquals(0, oldResultDec.scale());
+    //---------------------------------------------------
+    dec = HiveDecimal.create("3.00001415926");
+    Assert.assertEquals(11, dec.scale());
+    Assert.assertEquals(1, dec.integerDigitCount());
+    resultDec = dec.scaleByPowerOfTen(2);
+    Assert.assertEquals("300.001415926", resultDec.toString());
+    Assert.assertEquals(9, resultDec.scale());
+    Assert.assertEquals(3, resultDec.integerDigitCount());
+    resultDec = dec.scaleByPowerOfTen(5);
+    Assert.assertEquals("300001.415926", resultDec.toString());
+    Assert.assertEquals(6, resultDec.scale());
+    Assert.assertEquals(6, resultDec.integerDigitCount());
+    resultDec = dec.scaleByPowerOfTen(18);
+    Assert.assertEquals("3000014159260000000", resultDec.toString());
+    Assert.assertEquals(0, resultDec.scale());
+    Assert.assertEquals(19, resultDec.integerDigitCount());
+    resultDec = dec.scaleByPowerOfTen(35);
+    Assert.assertEquals("300001415926000000000000000000000000", resultDec.toString());
+    Assert.assertEquals(0, resultDec.scale());
+    Assert.assertEquals(36, resultDec.integerDigitCount());
+    resultDec = dec.scaleByPowerOfTen(37);
+    Assert.assertEquals("30000141592600000000000000000000000000", resultDec.toString());
+    Assert.assertEquals(0, resultDec.scale());
+    Assert.assertEquals(38, resultDec.integerDigitCount());
+  }
+
+  @Test
+  public void testSingleWordDivision() {
+ 
+    HiveDecimalV1 oldDec1;
+    HiveDecimalV1 oldDec2;
+    HiveDecimalV1 oldResultDec;
+
+    HiveDecimal dec1;
+    HiveDecimal dec2;
+    HiveDecimal resultDec;
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("839293");
+    oldDec2 = HiveDecimalV1.create("8");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("104911.625", oldResultDec.toString());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("839293");
+    dec2 = HiveDecimal.create("8");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("104911.625", resultDec.toString());  // UNDONE
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("1");
+    oldDec2 = HiveDecimalV1.create("3");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("0.33333333333333333333333333333333333333", oldResultDec.toString());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("1");
+    dec2 = HiveDecimal.create("3");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("0.33333333333333333333333333333333333333", resultDec.toString());  // UNDONE
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("1");
+    oldDec2 = HiveDecimalV1.create("9");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("0.11111111111111111111111111111111111111", oldResultDec.toString());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("1");
+    dec2 = HiveDecimal.create("9");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("0.11111111111111111111111111111111111111", resultDec.toString());  // UNDONE
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("22");
+    oldDec2 = HiveDecimalV1.create("7");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("3.1428571428571428571428571428571428571", oldResultDec.toString());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("22");
+    dec2 = HiveDecimal.create("7");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("3.1428571428571428571428571428571428571", resultDec.toString());  // UNDONE
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("1");
+    oldDec2 = HiveDecimalV1.create("81");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("0.01234567901234567901234567901234567901", oldResultDec.toString());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("1");
+    dec2 = HiveDecimal.create("81");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("0.01234567901234567901234567901234567901", resultDec.toString());  // UNDONE
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("425");
+    oldDec2 = HiveDecimalV1.create("1000000000000000");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("0.000000000000425", oldResultDec.toString());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("425");
+    dec2 = HiveDecimal.create("1000000000000000");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("0.000000000000425", resultDec.toString());  // UNDONE
+
+    //---------------------------------------------------
+    oldDec1 = HiveDecimalV1.create("0.000000000088");
+    oldDec2 = HiveDecimalV1.create("1000000000000000");
+    oldResultDec = oldDec1.divide(oldDec2);
+    Assert.assertEquals("0.000000000000000000000000088", oldResultDec.toString());
+    Assert.assertEquals(27, oldResultDec.scale());
+    //---------------------------------------------------
+    dec1 = HiveDecimal.create("0.000000000088");
+    dec2 = HiveDecimal.create("1000000000000000");
+    resultDec = dec1.divide(dec2);
+    Assert.assertEquals("0.000000000000000000000000088", resultDec.toString());  // UNDONE
+    Assert.assertEquals(27, resultDec.scale());
+   }
+
+  @Test
+  public void testDivide() {
+    HiveDecimal dec1 = HiveDecimal.create("3.14");
+    HiveDecimal dec2 = HiveDecimal.create("3");
+    Assert.assertNotNull(dec1.divide(dec2));
+
+    dec1 = HiveDecimal.create("15");
+    dec2 = HiveDecimal.create("5");
+    Assert.assertEquals("3", dec1.divide(dec2).toString());
+
+    dec1 = HiveDecimal.create("3.140");
+    dec2 = HiveDecimal.create("1.00");
+    Assert.assertEquals("3.14", dec1.divide(dec2).toString());
+  }
+
+  @Test
+  public void testPlus() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimalV1 oldDec2;
+    HiveDecimalV1 oldResultDec;
+
+    HiveDecimal dec;
+    HiveDecimal dec1;
+    HiveDecimal dec2;
+    HiveDecimal resultDec;
+
+    String decStr;
+    String decStr2;
+
+    dec1 = HiveDecimal.create("3.140");
+    dec1.validate();
+    dec2 = HiveDecimal.create("1.00");
+    dec2.validate();
+    resultDec = dec1.add(dec2);
+    resultDec.validate();
+    Assert.assertEquals("4.14", resultDec.toString());
+
+    decStr = "3.140";
+    decStr2 = "1.00";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("4.14", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("4.14", resultDec.toString());
+    Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "3.140";
+    decStr2 = "1.00000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("4.14000008733", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("4.14000008733", resultDec.toString());
+    Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "3.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("4.14000000000000000008733", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("4.14000000000000000008733", resultDec.toString());
+    Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "30000000000.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("30000000001.14000000000000000008733", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("30000000001.14000000000000000008733", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "300000000000000.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("300000000000001.14000000000000000008733", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000000001.14000000000000000008733", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    // Edge case?
+    decStr = "3000000000000000.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("3000000000000001.1400000000000000000873", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("3000000000000001.1400000000000000000873", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "300000000000000000000000.14";
+    decStr2 = "0.0000055555555550008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("300000000000000000000000.14000555555556", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000000000000000000.14000555555556", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "300000000000000000000000.14";
+    decStr2 = "0.000005555555555000873355";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("300000000000000000000000.14000555555556", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000000000000000000.14000555555556", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+
+
+    // Example from HiveDecimal.add header comments.
+    decStr = "598575157855521918987423259.94094";
+    decStr2 = "0.0000000000006711991169422033";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("598575157855521918987423259.94094", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("598575157855521918987423259.94094", resultDec.toString());
+    Assert.assertEquals(27, resultDec.integerDigitCount());
+
+    decStr = "598575157855521918987423259.94094";
+    decStr2 = "0.5555555555556711991169422033";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("598575157855521918987423260.49649555556", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("598575157855521918987423260.49649555556", resultDec.toString());
+    Assert.assertEquals(27, resultDec.integerDigitCount());
+
+    decStr = "199999999.99995";
+    decStr2 = "100000000.00005";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("300000000", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000", resultDec.toString());
+    Assert.assertEquals(9, resultDec.integerDigitCount());
+
+    dec1 = HiveDecimal.create("99999999999999999999999999999999999999");
+    dec1.validate();
+    Assert.assertEquals(38, dec1.integerDigitCount());
+    dec2 = HiveDecimal.create("1");
+    dec2.validate();
+    Assert.assertNull(dec1.add(dec2));
+  }
+
+  @Test
+  public void testAdd() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimalV1 oldDec2;
+    HiveDecimalV1 oldResultDec;
+
+    HiveDecimal dec;
+    HiveDecimal dec2;
+    HiveDecimal resultDec;
+
+    // Use the example from HIVE-13423 where the integer digits of the result exceed the
+    // enforced precision/scale.
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("98765432109876543210.12345");
+    oldResultDec = oldDec.add(oldDec);
+    Assert.assertEquals("197530864219753086420.2469", oldResultDec.toString());
+    oldResultDec = HiveDecimalV1.enforcePrecisionScale(oldResultDec, 38, 18);
+    Assert.assertTrue(oldResultDec == null);
+    //---------------------------------------------------
+    dec = HiveDecimal.create("98765432109876543210.12345");
+    assertTrue(dec != null);
+    dec.validate();
+    resultDec = dec.add(dec);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("197530864219753086420.2469", resultDec.toString());
+    // Assert.assertEquals(21, resultDec.integerDigitCount());
+    resultDec = HiveDecimal.enforcePrecisionScale(resultDec, 38, 18);
+    Assert.assertTrue(resultDec == null);
+ 
+    // Make sure zero trimming doesn't extend into the integer digits.
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create("199999999.99995");
+    oldDec2 = HiveDecimalV1.create("100000000.00005");
+    oldResultDec = oldDec.add(oldDec2);
+    Assert.assertEquals("300000000", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create("199999999.99995");
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create("100000000.00005");
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.add(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000", resultDec.toString());
+    Assert.assertEquals(9, resultDec.integerDigitCount());
+   }
+
+  @Test
+  public void testMinus() {
+
+    HiveDecimalV1 oldDec;
+    HiveDecimalV1 oldDec2;
+    HiveDecimalV1 oldResultDec;
+
+    HiveDecimal dec;
+    HiveDecimal dec1;
+    HiveDecimal dec2;
+    HiveDecimal resultDec;
+
+    String decStr;
+    String decStr2;
+
+    dec1 = HiveDecimal.create("3.140");
+    dec1.validate();
+    dec2 = HiveDecimal.create("1.00");
+    dec2.validate();
+    resultDec = dec1.add(dec2);
+    resultDec.validate();
+    Assert.assertEquals("4.14", resultDec.toString());
+
+    decStr = "3.140";
+    decStr2 = "1.00";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("2.14", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("2.14", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "3.140";
+    decStr2 = "1.00000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("2.13999991267", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("2.13999991267", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "3.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("2.13999999999999999991267", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("2.13999999999999999991267", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "30000000000.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("29999999999.13999999999999999991267", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("29999999999.13999999999999999991267", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "300000000000000.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("299999999999999.13999999999999999991267", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("299999999999999.13999999999999999991267", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    // Edge case?
+    decStr = "3000000000000000.140";
+    decStr2 = "1.00000000000000000008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("2999999999999999.1399999999999999999127", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("2999999999999999.1399999999999999999127", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "300000000000000000000000.14";
+    decStr2 = "0.0000055555555550008733";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("300000000000000000000000.13999444444444", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000000000000000000.13999444444444", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "300000000000000000000000.14";
+    decStr2 = "0.000005555555555000873355";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("300000000000000000000000.13999444444444", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("300000000000000000000000.13999444444444", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    // Example from HiveDecimal.subtract header comments.
+    decStr = "598575157855521918987423259.94094";
+    decStr2 = "0.0000000000006711991169422033";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("598575157855521918987423259.94094", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("598575157855521918987423259.94094", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+
+    decStr = "598575157855521918987423259.94094";
+    decStr2 = "0.5555555555556711991169422033";
+    //---------------------------------------------------
+    oldDec = HiveDecimalV1.create(decStr);
+    oldDec2 = HiveDecimalV1.create(decStr2);
+    oldResultDec = oldDec.subtract(oldDec2);
+    Assert.assertEquals("598575157855521918987423259.38538444444", oldResultDec.toString());
+    //---------------------------------------------------
+    dec = HiveDecimal.create(decStr);
+    assertTrue(dec != null);
+    dec.validate();
+    dec2 = HiveDecimal.create(decStr2);
+    assertTrue(dec2 != null);
+    dec2.validate();
+    resultDec = dec.subtract(dec2);
+    assertTrue(resultDec != null);
+    resultDec.validate();
+    Assert.assertEquals("598575157855521918987423259.38538444444", resultDec.toString());
+    // Assert.assertEquals(1, resultDec.integerDigitCount());
+  }
+
+  @Test
+  public void testSubtract() {
+    HiveDecimal dec1 = HiveDecimal.create("3.140");
+    assertTrue(dec1 != null);
+    dec1.validate();
+    HiveDecimal dec2 = HiveDecimal.create("1.00");
+    assertTrue(dec2 != null);
+    dec2.validate();
+    HiveDecimal result = dec1.subtract(dec2);
+    assertTrue(result != null);
+    result.validate();
+    Assert.assertEquals("2.14", result.toString());
+
+    dec1 = HiveDecimal.create("0.00001786135888657847525803");
+    assertTrue(dec1 != null);
+    dec1.validate();
+    dec2 = HiveDecimal.create("3.0000123456789");
+    assertTrue(dec2 != null);
+    dec2.validate();
+    result = dec1.subtract(dec2);
+    assertTrue(result != null);
+    result.validate();
+    Assert.assertEquals("-2.99999448432001342152474197", result.toString());
+  }
+
+  @Test
+  public void testPosMod() {
+    HiveDecimal hd1 = HiveDecimal.create("-100.91");
+    assertTrue(hd1 != null);
+    hd1.validate();
+    HiveDecimal hd2 = HiveDecimal.create("9.8");
+    assertTrue(hd2 != null);
+    hd2.validate();
+    HiveDecimal dec = hd1.remainder(hd2).add(hd2).remainder(hd2);
+    assertTrue(dec != null);
+    dec.validate();
+    Assert.assertEquals("6.89", dec.toString());
+  }
+
+  @Test
+  public void testHashCode() {
+      Assert.assertEquals(HiveDecimal.create("9").hashCode(), HiveDecimal.create("9.00").hashCode());
+      Assert.assertEquals(HiveDecimal.create("0").hashCode(), HiveDecimal.create("0.00").hashCode());
+  }
+
+  @Test
+  public void testException() {
+    HiveDecimal dec = HiveDecimal.create("3.1415.926");
+    Assert.assertNull(dec);
+    dec = HiveDecimal.create("3abc43");
+    Assert.assertNull(dec);
+  }
+
+  @Test
+  public void testBinaryConversion() {
+    Random r = new Random(2399);
+    for (String decString : specialDecimalStrings) {
+      doTestBinaryConversion(decString, r);
+    }
+  }
+
+  private void doTestBinaryConversion(String num, Random r) {
+    int scale = r.nextInt(HiveDecimal.MAX_SCALE);
+    HiveDecimal dec = HiveDecimal.create(num);
+    if (dec == null) {
+      return;
+    }
+    byte[] d = dec.setScale(scale).unscaledValue().toByteArray();
+    HiveDecimal roundedDec = dec.setScale(scale, HiveDecimal.ROUND_HALF_UP);
+    Assert.assertEquals(roundedDec, HiveDecimal.create(new BigInteger(d), scale));
+  }
+
+//------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testDecimalsWithOneOne() {
+    doTestDecimalsWithPrecisionScale(decimal_1_1_txt, 1, 1);
+  }
+
+  @Test
+  public void testDecimalsWithKv7Keys() {
+    doTestDecimalsWithPrecisionScale(kv7_txt_keys, 38, 18);
+  }
+
+  public void doTestDecimalsWithPrecisionScale(String[] decStrings, int precision, int scale) {
+
+    HiveDecimalV1 oldSum = HiveDecimalV1.create(0);
+    HiveDecimalWritable sum = new HiveDecimalWritable(0);
+
+    for (int i = 0; i < decStrings.length; i++) {
+
+      String string = decStrings[i];
+
+      HiveDecimalV1 oldDec = HiveDecimalV1.create(string);
+
+      HiveDecimalV1 resultOldDec;
+      if (oldDec == null) {
+        resultOldDec = null;
+      } else {
+        resultOldDec = HiveDecimalV1.enforcePrecisionScale(oldDec, precision, scale);
+      }
+
+      HiveDecimal dec = HiveDecimal.create(string);
+
+      if (oldDec == null) {
+        Assert.assertTrue(dec == null);
+        continue;
+      }
+      HiveDecimal resultDec = HiveDecimal.enforcePrecisionScale(dec, precision, scale);
+      if (resultOldDec == null) {
+        Assert.assertTrue(resultDec == null);
+        continue;
+      }
+
+      Assert.assertEquals(resultOldDec.toString(), resultDec.toString());
+      Assert.assertEquals(resultOldDec.toFormatString(scale), resultDec.toFormatString(scale));
+
+      oldSum = oldSum.add(resultOldDec);
+      sum.mutateAdd(resultDec);
+    }
+
+    Assert.assertEquals(oldSum.toString(), sum.toString());
+  }
+
+//------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testDecimalsWithOneOneWritable() {
+    doTestDecimalsWithPrecisionScaleWritable(decimal_1_1_txt, 1, 1);
+  }
+
+  @Test
+  public void testDecimalsWithKv7KeysWritable() {
+    doTestDecimalsWithPrecisionScaleWritable(kv7_txt_keys, 38, 18);
+  }
+
+  public void doTestDecimalsWithPrecisionScaleWritable(String[] decStrings, int precision, int scale) {
+
+    HiveDecimalV1 oldSum = HiveDecimalV1.create(0);
+    HiveDecimalWritable sum = new HiveDecimalWritable(0);
+
+    for (int i = 0; i < decStrings.length; i++) {
+      String string = decStrings[i];
+
+      HiveDecimalV1 oldDec = HiveDecimalV1.create(string);
+      HiveDecimalV1 resultOldDec;
+      if (oldDec == null) {
+        resultOldDec = null;
+      } else {
+        resultOldDec = HiveDecimalV1.enforcePrecisionScale(oldDec, precision, scale);
+      }
+
+      HiveDecimalWritable decWritable = new HiveDecimalWritable(string);
+      if (oldDec == null) {
+        Assert.assertTrue(!decWritable.isSet());
+        continue;
+      }
+      decWritable.mutateEnforcePrecisionScale(precision, scale);;
+      if (resultOldDec == null) {
+        Assert.assertTrue(!decWritable.isSet());
+        continue;
+      }
+
+      Assert.assertEquals(resultOldDec.toString(), decWritable.toString());
+      Assert.assertEquals(resultOldDec.toFormatString(scale), decWritable.toFormatString(scale));
+
+      oldSum = oldSum.add(resultOldDec);
+      sum.mutateAdd(decWritable);
+    }
+
+    Assert.assertEquals(oldSum.toString(), sum.toString());
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testSort() {
+    doTestSort(decimal_1_1_txt);
+  }
+
+  @Test
+  public void testSortSpecial() {
+    doTestSort(specialDecimalStrings);
+  }
+
+  @Test
+  public void testSortRandom() {
+    Random r = new Random(14434);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestSortRandom(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestSortRandom(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  public void doTestSortRandom(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+    String[] randomStrings = new String[POUND_FACTOR];
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      randomStrings[i] = bigDecimal.toString();
+    }
+
+    doTestSort(randomStrings);
+  }
+
+  public void doTestSort(String[] decStrings) {
+
+    HiveDecimalV1[] oldDecSortArray = new HiveDecimalV1[decStrings.length];
+    HiveDecimal[] decSortArray = new HiveDecimal[decStrings.length];
+
+    int count = 0;
+    for (int i = 0; i < decStrings.length; i++) {
+      String string = decStrings[i];
+
+      HiveDecimalV1 oldDec = HiveDecimalV1.create(string);
+      if (oldDec == null) {
+        continue;
+      }
+      if (isTenPowerBug(oldDec.toString())) {
+        continue;
+      }
+      oldDecSortArray[count] = oldDec;
+
+      HiveDecimal dec = HiveDecimal.create(string);
+      if (dec == null) {
+        Assert.fail();
+      }
+      decSortArray[count] = dec;
+      count++;
+    }
+
+    oldDecSortArray = Arrays.copyOf(oldDecSortArray,  count);
+    decSortArray = Arrays.copyOf(decSortArray, count);
+
+    Arrays.sort(oldDecSortArray);
+    Arrays.sort(decSortArray);
+
+    for (int i = 0; i < count; i++) {
+      String oldDecString = oldDecSortArray[i].toString();
+      String decString = decSortArray[i].toString();
+
+      if (!oldDecString.equals(decString)) {
+        Assert.fail();
+      }
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromBigDecimal() {
+    Random r = new Random(14434);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomCreateFromBigDecimal(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomCreateFromBigDecimal(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomCreateFromBigDecimal(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestCreateFromBigDecimal(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testCreateFromBigDecimalSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromBigDecimal(bigDecimal);
+    }
+  }
+
+  private void doTestCreateFromBigDecimal(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromBigDecimalNoRound() {
+    Random r = new Random(14434);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomCreateFromBigDecimalNoRound(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomCreateFromBigDecimalNoRound(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomCreateFromBigDecimalNoRound(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestCreateFromBigDecimalNoRound(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testCreateFromBigDecimalNoRoundSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromBigDecimalNoRound(bigDecimal);
+    }
+  }
+
+  private void doTestCreateFromBigDecimalNoRound(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal, /* allowRounding */ false);
+    HiveDecimal dec = HiveDecimal.create(bigDecimal, /* allowRounding */ false);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    if (dec == null) {
+      Assert.fail();
+    }
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testCreateFromBigDecimalNegativeScaleSpecial() {
+    Random r = new Random(223965);
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      int negativeScale = -(0 + r.nextInt(38 + 1));
+      bigDecimal = bigDecimal.setScale(negativeScale, BigDecimal.ROUND_HALF_UP);
+      doTestCreateFromBigDecimalNegativeScale(bigDecimal);
+    }
+  }
+
+  private void doTestCreateFromBigDecimalNegativeScale(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromBigInteger() {
+    doTestRandomCreateFromBigInteger(standardAlphabet);
+  }
+
+  @Test
+  public void testRandomCreateFromBigIntegerSparse() {
+    for (String digitAlphabet : sparseAlphabets) {
+      doTestRandomCreateFromBigInteger(digitAlphabet);
+    }
+  }
+
+  private void doTestRandomCreateFromBigInteger(String digitAlphabet) {
+
+    Random r = new Random(11241);
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigInteger bigInteger = randHiveBigInteger(r, digitAlphabet);
+
+      doTestCreateFromBigInteger(bigInteger);
+    }
+  }
+
+  @Test
+  public void testCreateFromBigIntegerSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromBigInteger(bigDecimal.unscaledValue());
+    }
+  }
+
+  private void doTestCreateFromBigInteger(BigInteger bigInteger) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigInteger);
+    HiveDecimal dec = HiveDecimal.create(bigInteger);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromBigIntegerScale() {
+    doTestRandomCreateFromBigIntegerScale(standardAlphabet, false);
+  }
+
+  @Test
+  public void testRandomCreateFromBigIntegerScaleFractionsOnly() {
+    doTestRandomCreateFromBigIntegerScale(standardAlphabet, true);
+  }
+
+  @Test
+  public void testRandomCreateFromBigIntegerScaleSparse() {
+    for (String digitAlphabet : sparseAlphabets) {
+      doTestRandomCreateFromBigIntegerScale(digitAlphabet, false);
+    }
+  }
+
+  private void doTestRandomCreateFromBigIntegerScale(String digitAlphabet, boolean fractionsOnly) {
+
+    Random r = new Random(4448);
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigInteger bigInteger = randHiveBigInteger(r, digitAlphabet);
+
+      int scale;
+      if (fractionsOnly) {
+        scale = 1 + r.nextInt(38);
+      } else {
+        scale = 0 + r.nextInt(38 + 1);
+      }
+
+      doTestCreateFromBigIntegerScale(bigInteger, scale);
+    }
+  }
+
+  @Test
+  public void testCreateFromBigIntegerScaleSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromBigIntegerScale(bigDecimal.unscaledValue(), bigDecimal.scale());
+    }
+  }
+
+  private void doTestCreateFromBigIntegerScale(BigInteger bigInteger, int scale) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigInteger, scale);
+    HiveDecimal dec = HiveDecimal.create(bigInteger, scale);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomSetFromDouble() {
+    Random r = new Random(14434);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomSetFromDouble(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomSetFromDouble(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomSetFromDouble(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestSetFromDouble(bigDecimal.doubleValue());
+    }
+  }
+
+  private void doTestRandomSetFromDouble() {
+
+    Random r = new Random(94762);
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      double randomDouble = r.nextDouble();
+ 
+      doTestSetFromDouble(randomDouble);
+    }
+  }
+
+  @Test
+  public void testSetFromDoubleSpecial() {
+
+    for (String specialString : specialDecimalStrings) {
+      double specialDouble = Double.valueOf(specialString);
+      doTestSetFromDouble(specialDouble);
+    }
+  }
+
+  private void doTestSetFromDouble(double doubleValue) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(Double.toString(doubleValue));
+    if (oldDec == null) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(doubleValue);
+    if (dec == null) {
+      Assert.fail();
+    }
+    dec.validate();
+    if (!oldDec.toString().equals(dec.toString())) {
+      BigDecimal bigDecimal = new BigDecimal(dec.toString());
+      for (int i = 16; i < 18;i++) {
+        BigDecimal trial = bigDecimal.setScale(i, HiveDecimal.ROUND_HALF_UP);
+      }
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromString() {
+    Random r = new Random(1221);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomCreateFromString(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomCreateFromString(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomCreateFromString(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestCreateFromString(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testCreateFromStringSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromString(bigDecimal);
+    }
+  }
+
+  private void doTestCreateFromString(BigDecimal bigDecimal) {
+
+    String decString = bigDecimal.toPlainString();
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(decString);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(decString);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromStringPadded() {
+    Random r = new Random(9774);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomCreateFromStringPadded(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomCreateFromStringPadded(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomCreateFromStringPadded(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestCreateFromStringPadded(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testCreateFromStringPaddedSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromStringPadded(bigDecimal);
+    }
+  }
+
+  private void doTestCreateFromStringPadded(BigDecimal bigDecimal) {
+
+    String decString = bigDecimal.toPlainString();
+    String decString1 = " " + decString;
+    String decString2 = decString + " ";
+    String decString3 = " " + decString + " ";
+    String decString4 = "  " + decString;
+    String decString5 = decString + "  ";
+    String decString6 = "  " + decString + "  ";
+
+    HiveDecimalV1 oldDec;
+    HiveDecimal dec;
+
+    oldDec = HiveDecimalV1.create(decString);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+
+    dec = HiveDecimal.create(decString1, true);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+    } else {
+      assertTrue(dec != null);
+      dec.validate();
+
+      Assert.assertEquals(oldDec.toString(), dec.toString());
+    }
+
+    dec = HiveDecimal.create(decString2, true);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+    } else {
+      assertTrue(dec != null);
+      dec.validate();
+
+      Assert.assertEquals(oldDec.toString(), dec.toString());
+    }
+
+    dec = HiveDecimal.create(decString3, true);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+    } else {
+      assertTrue(dec != null);
+      dec.validate();
+
+      Assert.assertEquals(oldDec.toString(), dec.toString());
+    }
+
+    dec = HiveDecimal.create(decString4, true);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+    } else {
+      assertTrue(dec != null);
+      dec.validate();
+
+      Assert.assertEquals(oldDec.toString(), dec.toString());
+    }
+
+    dec = HiveDecimal.create(decString5, true);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+    } else {
+      assertTrue(dec != null);
+      dec.validate();
+
+      Assert.assertEquals(oldDec.toString(), dec.toString());
+    }
+
+    dec = HiveDecimal.create(decString6, true);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+    } else {
+      assertTrue(dec != null);
+      dec.validate();
+
+      Assert.assertEquals(oldDec.toString(), dec.toString());
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomCreateFromStringExponent() {
+    Random r = new Random(297111);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomCreateFromStringPadded(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomCreateFromStringPadded(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomCreateFromStringExponent(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestCreateFromStringExponent(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testCreateFromStringExponentSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestCreateFromStringExponent(bigDecimal);
+    }
+  }
+
+  private void doTestCreateFromStringExponent(BigDecimal bigDecimal) {
+
+    // Use toString which will have exponents instead of toPlainString.
+    String decString = bigDecimal.toString();
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(decString);
+    HiveDecimal dec = HiveDecimal.create(decString);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    Assert.assertEquals(oldDec.toString(), dec.toString());
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomLongValue() {
+    Random r = new Random(73293);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomLongValue(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomLongValue(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomLongValue(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestLongValue(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testLongValueSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestLongValue(bigDecimal);
+    }
+  }
+
+  private void doTestLongValue(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    BigDecimal bigDecimalOldDec = oldDec.bigDecimalValue();
+    BigDecimal bigDecimalDec = dec.bigDecimalValue();
+    Assert.assertEquals(bigDecimalOldDec, bigDecimalDec);
+
+    BigDecimal bigDecimalFloor = bigDecimalDec.setScale(0, BigDecimal.ROUND_DOWN);
+    long longValueBigDecimalFloor = bigDecimalFloor.longValue();
+    boolean isLongExpected =
+        bigDecimalFloor.equals(bigDecimalDec.valueOf(longValueBigDecimalFloor));
+
+    boolean decIsLong = dec.isLong();
+    long oldDecLong = oldDec.longValue();
+    long decLong = dec.longValue();
+    if (isLongExpected != decIsLong) {
+      Assert.fail();
+    }
+
+    if (decIsLong) {
+      if (oldDecLong != decLong) {
+        Assert.fail();
+      }
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomIntValue() {
+    Random r = new Random(98333);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomIntValue(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomIntValue(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomIntValue(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestIntValue(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testIntValueSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestIntValue(bigDecimal);
+    }
+  }
+
+  private void doTestIntValue(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    BigDecimal bigDecimalOldDec = oldDec.bigDecimalValue();
+    BigDecimal bigDecimalDec = dec.bigDecimalValue();
+    Assert.assertEquals(bigDecimalOldDec, bigDecimalDec);
+
+    BigDecimal bigDecimalFloor = bigDecimalDec.setScale(0, BigDecimal.ROUND_DOWN);
+    int intValueBigDecimalFloor = bigDecimalFloor.intValue();
+    boolean isIntExpected =
+        bigDecimalFloor.equals(bigDecimalDec.valueOf(intValueBigDecimalFloor));
+
+    boolean decIsInt = dec.isInt();
+    int oldDecInt = oldDec.intValue();
+    int decInt = dec.intValue();
+    if (isIntExpected != decIsInt) {
+      Assert.fail();
+    }
+
+    if (decIsInt) {
+      if (oldDecInt != decInt) {
+        Assert.fail();
+      }
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomShortValue() {
+    Random r = new Random(15);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomShortValue(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomShortValue(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomShortValue(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestShortValue(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testShortValueSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestShortValue(bigDecimal);
+    }
+  }
+
+  private void doTestShortValue(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    BigDecimal bigDecimalOldDec = oldDec.bigDecimalValue();
+    BigDecimal bigDecimalDec = dec.bigDecimalValue();
+    Assert.assertEquals(bigDecimalOldDec, bigDecimalDec);
+
+    BigDecimal bigDecimalFloor = bigDecimalDec.setScale(0, BigDecimal.ROUND_DOWN);
+    short shortValueBigDecimalFloor = bigDecimalFloor.shortValue();
+    boolean isShortExpected =
+        bigDecimalFloor.equals(bigDecimalDec.valueOf(shortValueBigDecimalFloor));
+
+    boolean decIsShort = dec.isShort();
+    short oldDecShort = oldDec.shortValue();
+    short decShort = dec.shortValue();
+    if (isShortExpected != decIsShort) {
+      Assert.fail();
+    }
+
+    if (decIsShort) {
+      if (oldDecShort != decShort) {
+        Assert.fail();
+      }
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomByteValue() {
+    Random r = new Random(9292);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomByteValue(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomByteValue(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomByteValue(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestByteValue(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testByteValueSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestByteValue(bigDecimal);
+    }
+  }
+
+  private void doTestByteValue(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+    dec.validate();
+
+    BigDecimal bigDecimalOldDec = oldDec.bigDecimalValue();
+    BigDecimal bigDecimalDec = dec.bigDecimalValue();
+    Assert.assertEquals(bigDecimalOldDec, bigDecimalDec);
+
+    BigDecimal bigDecimalFloor = bigDecimalDec.setScale(0, BigDecimal.ROUND_DOWN);
+    byte byteValueBigDecimalFloor = bigDecimalFloor.byteValue();
+    boolean isByteExpected =
+        bigDecimalFloor.equals(bigDecimalDec.valueOf(byteValueBigDecimalFloor));
+
+    boolean decIsByte = dec.isByte();
+    byte oldDecByte = oldDec.byteValue();
+    byte decByte = dec.byteValue();
+    if (isByteExpected != decIsByte) {
+      Assert.fail();
+    }
+
+    if (decIsByte) {
+      if (oldDecByte != decByte) {
+        Assert.fail();
+      }
+    }
+  }
+
+  //------------------------------------------------------------------------------------------------
+
+  @Test
+  public void testRandomTimestamp() {
+    Random r = new Random(5476);
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      doTestRandomTimestamp(r, standardAlphabet, bigDecimalFlavor);
+    }
+    for (BigDecimalFlavor bigDecimalFlavor : BigDecimalFlavor.values()) {
+      for (String sparseAlphabet : sparseAlphabets) {
+        doTestRandomTimestamp(r, sparseAlphabet, bigDecimalFlavor);
+      }
+    }
+  }
+
+  private void doTestRandomTimestamp(Random r, String digitAlphabet, BigDecimalFlavor bigDecimalFlavor) {
+    for (int i = 0; i < POUND_FACTOR; i++) {
+      BigDecimal bigDecimal = randHiveBigDecimal(r, digitAlphabet, bigDecimalFlavor);
+
+      doTestTimestamp(bigDecimal);
+    }
+  }
+
+  @Test
+  public void testTimestampSpecial() {
+    for (BigDecimal bigDecimal : specialBigDecimals) {
+      doTestTimestamp(bigDecimal);
+    }
+  }
+
+  private void doTestTimestamp(BigDecimal bigDecimal) {
+
+    HiveDecimalV1 oldDec = HiveDecimalV1.create(bigDecimal);
+    if (oldDec != null && isTenPowerBug(oldDec.toString())) {
+      return;
+    }
+    HiveDecimal dec = HiveDecimal.create(bigDecimal);
+    if (oldDec == null) {
+      assertTrue(dec == null);
+      return;
+    }
+    assertTrue(dec != null);
+   

<TRUNCATED>