/** * 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 static org.junit.Assert.*; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; import java.util.Random; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * This code was based on code from Microsoft's PolyBase. */ public class TestDecimal128 { private Decimal128 zero; private Decimal128 one; private Decimal128 two; @Before public void setUp() throws Exception { zero = new Decimal128(0); one = new Decimal128(1); two = new Decimal128(2); } @After public void tearDown() throws Exception { } @Test public void testCalculateTenThirtySeven() { // find 10^37 Decimal128 ten = new Decimal128(10, (short) 0); Decimal128 val = new Decimal128(1, (short) 0); for (int i = 0; i < 37; ++i) { val.multiplyDestructive(ten, (short) 0); } // verify it String s = val.toFormalString(); assertEquals("10000000000000000000000000000000000000", s); boolean overflow = false; } @Test public void testHashCode() { assertTrue(one.hashCode() != two.hashCode()); assertTrue(zero.hashCode() != one.hashCode()); assertTrue(zero.hashCode() != two.hashCode()); assertEquals(zero.hashCode(), new Decimal128(0).hashCode()); assertEquals(one.hashCode(), new Decimal128(1).hashCode()); assertEquals(two.hashCode(), new Decimal128(2).hashCode()); // scaled value might be not equal, but after scaling it should. Decimal128 oneScaled = new Decimal128(1L, (short) 3); oneScaled.changeScaleDestructive((short) 0); assertEquals(one.hashCode(), oneScaled.hashCode()); } @Test public void testEquals() { assertTrue(!one.equals(two)); assertTrue(!zero.equals(one)); assertTrue(!zero.equals(two)); assertEquals(zero, new Decimal128(0)); assertEquals(one, new Decimal128(1)); assertEquals(two, new Decimal128(2)); // scaled value might be not equal, but after scaling it should. Decimal128 oneScaled = new Decimal128(1L, (short) 3); oneScaled.changeScaleDestructive((short) 0); assertEquals(one, oneScaled); } @Test public void testCompareTo() { assertTrue(one.compareTo(two) < 0); assertTrue(two.compareTo(one) > 0); assertTrue(one.compareTo(zero) > 0); assertTrue(zero.compareTo(two) < 0); // compare to must compare with scaling up/down. Decimal128 oneScaled = new Decimal128(1L, (short) 3); assertTrue(one.compareTo(oneScaled) == 0); // exact numbers (power of 2) can do the same Decimal128 d1 = new Decimal128(2.0d, (short) 6); Decimal128 d2 = new Decimal128(2.0d, (short) 3); assertTrue(d1.compareTo(d2) == 0); // but, if the value is rounded by more scaling, // they will be different values. Decimal128 d3 = new Decimal128(2.0d / 3.0d, (short) 5); Decimal128 d4 = new Decimal128(2.0d / 3.0d, (short) 8); assertTrue(d3.compareTo(d4) != 0); Decimal128 d5 = new Decimal128(12, (short) 5); Decimal128 d6 = new Decimal128(15, (short) 7); assertTrue(d5.compareTo(d6) < 0); assertTrue(d6.compareTo(d5) > 0); Decimal128 d7 = new Decimal128(15, (short) 5); Decimal128 d8 = new Decimal128(12, (short) 7); assertTrue(d7.compareTo(d8) > 0); assertTrue(d8.compareTo(d7) < 0); } @Test public void testText() { assertEquals("1", one.toFormalString()); assertEquals(0, new Decimal128("1", (short) 0).compareTo(one)); assertEquals("2", two.toFormalString()); assertEquals(0, new Decimal128("2", (short) 0).compareTo(two)); assertEquals("0", zero.toFormalString()); assertEquals(0, new Decimal128("0", (short) 0).compareTo(zero)); assertEquals("1.000", new Decimal128(1L, (short) 3).toFormalString()); assertEquals(0, new Decimal128("1", (short) 3).compareTo(one)); assertEquals("2.000000", new Decimal128(2.0d, (short) 6).toFormalString()); assertEquals("2.000", new Decimal128(2.0d, (short) 3).toFormalString()); assertEquals(0, new Decimal128("2.0", (short) 6).compareTo(two)); assertEquals(0, new Decimal128("2.0", (short) 3).compareTo(two)); assertEquals("1.3330", new Decimal128("1.333", (short) 4).toFormalString()); assertEquals("1.333000", new Decimal128("1.333", (short) 6).toFormalString()); assertEquals("1.333", new Decimal128("1.333", (short) 3).toFormalString()); assertEquals("1.33", new Decimal128("1.333", (short) 2).toFormalString()); assertEquals("1.33", new Decimal128("1.333", (short) 2).toFormalString()); assertEquals("0.13330", new Decimal128("1333E-4", (short) 5).toFormalString()); assertEquals("0.01333", new Decimal128("1333E-5", (short) 5).toFormalString()); assertEquals("13330000.00", new Decimal128("1333E4", (short) 2).toFormalString()); assertEquals("123456789012345678901234.56789", new Decimal128( "123456789012345678901234567.8901234E-3", (short) 5).toFormalString()); } @Test public void testAdd() { Decimal128 result = new Decimal128(); Decimal128.add(one, two, result, (short) 2); assertEquals(0, new Decimal128(3L, (short) 0).compareTo(result)); Decimal128.add(two, two, result, (short) 1); assertEquals(0, new Decimal128(4L, (short) 0).compareTo(result)); long l1 = 123456789012345L; long l2 = 987654321097L; long sum = l1 + l2; Decimal128 left = new Decimal128(l1, (short) 3); Decimal128 right = new Decimal128(l2, (short) 5); Decimal128.add(left, right, result, (short) 2); assertEquals(0, new Decimal128(sum, (short) 0).compareTo(result)); Decimal128.add(right, left, result, (short) 2); assertEquals(0, new Decimal128(sum, (short) 0).compareTo(result)); } @Test public void testSubtract() { Decimal128 result = new Decimal128(); Decimal128.subtract(one, two, result, (short) 2); assertEquals(0, new Decimal128(-1L, (short) 0).compareTo(result)); Decimal128.subtract(two, one, result, (short) 2); assertEquals(0, new Decimal128(1L, (short) 0).compareTo(result)); Decimal128.subtract(two, two, result, (short) 1); assertEquals(0, zero.compareTo(result)); assertEquals(0, result.getSignum()); long l1 = 123456789012345L; long l2 = 987654321097L; long sub = l1 - l2; Decimal128 left = new Decimal128(l1, (short) 3); Decimal128 right = new Decimal128(l2, (short) 5); Decimal128.subtract(left, right, result, (short) 2); assertEquals(0, new Decimal128(sub, (short) 0).compareTo(result)); Decimal128.subtract(right, left, result, (short) 2); assertEquals(0, new Decimal128(-sub, (short) 0).compareTo(result)); Decimal128 val = new Decimal128("1.123", (short) 3); val.addDestructive(new Decimal128("4.321", (short) 3), (short) 3); assertEquals("5.444", val.toFormalString()); } @Test public void testMultiply() { Decimal128 result = new Decimal128(); Decimal128.multiply(one, two, result, (short) 2); assertEquals(0, two.compareTo(result)); Decimal128.multiply(two, two, result, (short) 2); assertEquals(0, new Decimal128(4L, (short) 0).compareTo(result)); long l1 = 123456789012345L; long l2 = 987654321097L; Decimal128 left = new Decimal128(l1, (short) 0); Decimal128 right = new Decimal128(l2, (short) 0); UnsignedInt128 unscaled = new UnsignedInt128(l1) .multiplyConstructive(new UnsignedInt128(l2)); Decimal128 ans = new Decimal128(unscaled, (short) 0, false); Decimal128.multiply(left, right, result, (short) 0); assertEquals(0, ans.compareTo(result)); Decimal128.multiply(right, left, result, (short) 0); assertEquals(0, ans.compareTo(result)); Decimal128.multiply(new Decimal128(1.123d, (short) 10), new Decimal128( 4.321d, (short) 10), result, (short) 10); assertEquals(1.123d * 4.321d, result.doubleValue(), 0.00001d); // because only 10 fractional digits, it's not this much accurate assertNotEquals(1.123d * 4.321d, result.doubleValue(), 0.00000000000000001d); Decimal128.multiply(new Decimal128(1.123d, (short) 2), new Decimal128( 4.321d, (short) 2), result, (short) 2); // this time even more inaccurate assertEquals(1.123d * 4.321d, result.doubleValue(), 1.0d); assertNotEquals(1.123d * 4.321d, result.doubleValue(), 0.000001d); Decimal128 val = new Decimal128("1.123", (short) 3); val.multiplyDestructive(new Decimal128("4.321", (short) 3), (short) 6); assertEquals("4.852483", val.toFormalString()); Decimal128 val1 = new Decimal128("1.0001", (short) 4); val1.multiplyDestructive(new Decimal128("1.0001", (short) 4), (short) 8); assertEquals("1.00020001", val1.toFormalString()); } // Assert that a and b are not the same, within epsilon tolerance. private void assertNotEquals(double a, double b, double epsilon) { assertTrue(Math.abs(a - b) > epsilon); } @Test public void testDivide() { Decimal128 quotient = new Decimal128(); Decimal128.divide(two, one, quotient, (short) 2); assertEquals(0, quotient.compareTo(two)); Decimal128.divide(two, two, quotient, (short) 2); assertEquals(0, quotient.compareTo(one)); Decimal128 three = new Decimal128(3); Decimal128 four = new Decimal128(4); Decimal128.divide(three, four, quotient, (short) 2); assertEquals("0.75", quotient.toFormalString()); Decimal128.divide(three, four, quotient, (short) 1); assertEquals("0.8", quotient.toFormalString()); Decimal128.divide(three, four, quotient, (short) 0); assertEquals("1", quotient.toFormalString()); Decimal128 two = new Decimal128(2); Decimal128.divide(two, three, quotient, (short) 4); assertEquals("0.6667", quotient.toFormalString()); } @Test public void testRandomMultiplyDivideInverse() { final int N = 100000; final long MASK56 = 0x00FFFFFFFFFFFFL; // 56 bit mask to generate positive 56 bit longs // from random signed longs int seed = 897089790; Random rand = new Random(seed); long l1, l2; for (int i = 1; i <= N; i++) { l1 = rand.nextLong() & MASK56; l2 = rand.nextLong() & MASK56; verifyMultiplyDivideInverse(l1, l2); } } /** * Verify that a * b / b == a * for decimal division for scale 0 with integer inputs. * * Not valid if abs(a * b) >= 10**38. */ private void verifyMultiplyDivideInverse(long a, long b) { final short scale = 0; // ignore zero-divide cases if (b == 0) { return; } Decimal128 decA = new Decimal128(a, scale); Decimal128 decB = new Decimal128(b, scale); decA.multiplyDestructive(decB, scale); decA.checkPrecisionOverflow(38); // caller must make sure product of inputs is not too big decA.divideDestructive(decB, scale); assertEquals("Error for a = " + Long.toString(a) + ", b = " + Long.toString(b), new Decimal128(a, scale), decA); } @Test public void testRandomAddSubtractInverse() { final int N = 1000000; int seed = 1427480960; Random rand = new Random(seed); long l1, l2; for (int i = 1; i <= N; i++) { l1 = rand.nextLong(); l2 = rand.nextLong(); verifyAddSubtractInverse(l1, l2); } } /** * Verify that (a + b) - b == a * for decimal add and subtract for scale 0 with long integer inputs. */ private void verifyAddSubtractInverse(long a, long b) { final short scale = 0; Decimal128 decA = new Decimal128(a, scale); Decimal128 decB = new Decimal128(b, scale); decA.addDestructive(decB, scale); decA.subtractDestructive(decB, scale); assertEquals("Error for a = " + Long.toString(a) + ", b = " + Long.toString(b), new Decimal128(a, scale), decA); } /** * During earlier code testing, if we found errors, test them here as regression tests. */ @Test public void testKnownPriorErrors() { // Regression test for defect reported in HIVE-6243 long a = 213474114411690L; long b = 5062120663L; verifyMultiplyDivideInverse(a, b); // Regression test for defect reported in HIVE-6399 String a2 = "-605044214913338382"; // 18 digits String b2 = "55269579109718297360"; // 20 digits // -33440539101030154945490585226577271520 is expected result verifyHighPrecisionMultiplySingle(a2, b2); } // Test a set of random adds at high precision. @Test public void testHighPrecisionDecimal128Add() { final int N = 10000; for (int i = 0; i < N; i++) { verifyHighPrecisionAddSingle(); } } // Test one random hi-precision decimal add. private void verifyHighPrecisionAddSingle() { Decimal128 a, b, r; String sA, sB; a = new Decimal128(); sA = makeNumericString(37); a.update(sA, (short) 0); b = new Decimal128(); sB = makeNumericString(37); b.update(sB, (short) 0); r = new Decimal128(); r.addDestructive(a, (short) 0); r.addDestructive(b, (short) 0); String res1 = r.toFormalString(); // Now do the add with Java BigDecimal BigDecimal bdA = new BigDecimal(sA); BigDecimal bdB = new BigDecimal(sB); BigDecimal bdR = bdA.add(bdB); String res2 = bdR.toPlainString(); // Compare the results String message = "For operation " + a.toFormalString() + " + " + b.toFormalString(); assertEquals(message, res2, res1); } // Test a set of random subtracts at high precision. @Test public void testHighPrecisionDecimal128Subtract() { final int N = 10000; for (int i = 0; i < N; i++) { verifyHighPrecisionSubtractSingle(); } } // Test one random high-precision subtract. private void verifyHighPrecisionSubtractSingle() { Decimal128 a, b, r; String sA, sB; a = new Decimal128(); sA = makeNumericString(37); a.update(sA, (short) 0); b = new Decimal128(); sB = makeNumericString(37); b.update(sB, (short) 0); r = new Decimal128(); r.addDestructive(a, (short) 0); r.subtractDestructive(b, (short) 0); String res1 = r.toFormalString(); // Now do the add with Java BigDecimal BigDecimal bdA = new BigDecimal(sA); BigDecimal bdB = new BigDecimal(sB); BigDecimal bdR = bdA.subtract(bdB); String res2 = bdR.toPlainString(); // Compare the results String message = "For operation " + a.toFormalString() + " - " + b.toFormalString(); assertEquals(message, res2, res1); } // Test a set of random multiplications at high precision. @Test public void testHighPrecisionDecimal128Multiply() { final int N = 10000; for (int i = 0; i < N; i++) { verifyHighPrecisionMultiplySingle(); } } // Test a single, high-precision multiply of random inputs. private void verifyHighPrecisionMultiplySingle() { Decimal128 a, b, r; String sA, sB; Random rand = new Random(); int aDigits = rand.nextInt(37) + 1; // number of digits in a (1..37) int bDigits = 38 - aDigits; // number of digits in b (1..37) assertTrue(aDigits + bDigits == 38 && aDigits > 0 && bDigits > 0); a = new Decimal128(); sA = makeNumericString(aDigits); a.update(sA, (short) 0); b = new Decimal128(); sB = makeNumericString(bDigits); b.update(sB, (short) 0); r = new Decimal128(); r.addDestructive(a, (short) 0); r.multiplyDestructive(b, (short) 0); String res1 = r.toFormalString(); // Now do the operation with Java BigDecimal BigDecimal bdA = new BigDecimal(sA); BigDecimal bdB = new BigDecimal(sB); BigDecimal bdR = bdA.multiply(bdB); String res2 = bdR.toPlainString(); // Compare the results String message = "For operation " + a.toFormalString() + " * " + b.toFormalString(); assertEquals(message, res2, res1); } // Test a single, high-precision multiply of random inputs. // Arguments must be integers with optional - sign, represented as strings. // Arguments must have 1 to 37 digits and the number of total digits // must be <= 38. private void verifyHighPrecisionMultiplySingle(String argA, String argB) { Decimal128 a, b, r; String sA, sB; // verify number of digits is <= 38 and each number has 1 or more digits int aDigits = argA.length(); aDigits -= argA.charAt(0) == '-' ? 1 : 0; int bDigits = argB.length(); bDigits -= argB.charAt(0) == '-' ? 1 : 0; assertTrue(aDigits + bDigits <= 38 && aDigits > 0 && bDigits > 0); a = new Decimal128(); sA = argA; a.update(sA, (short) 0); b = new Decimal128(); sB = argB; b.update(sB, (short) 0); r = new Decimal128(); r.addDestructive(a, (short) 0); r.multiplyDestructive(b, (short) 0); String res1 = r.toFormalString(); // Now do the operation with Java BigDecimal BigDecimal bdA = new BigDecimal(sA); BigDecimal bdB = new BigDecimal(sB); BigDecimal bdR = bdA.multiply(bdB); String res2 = bdR.toPlainString(); // Compare the results String message = "For operation " + a.toFormalString() + " * " + b.toFormalString(); assertEquals(message, res2, res1); } // Test a set of random divisions at high precision. @Test public void testHighPrecisionDecimal128Divide() { final int N = 10000; for (int i = 0; i < N; i++) { verifyHighPrecisionDivideSingle(); } } // Test a single, high-precision divide of random inputs. private void verifyHighPrecisionDivideSingle() { Decimal128 a, b, r; String sA, sB; Random rand = new Random(); int aDigits = rand.nextInt(37) + 1; // number of digits in a (1..37) int bDigits = 38 - aDigits; // number of digits in b (1..37) int temp; // make sure b will have less digits than A if (bDigits > aDigits) { temp = aDigits; aDigits = bDigits; bDigits = temp; } if (bDigits == aDigits) { return; } assertTrue(aDigits + bDigits == 38 && aDigits > 0 && bDigits > 0); a = new Decimal128(); sA = makeNumericString(aDigits); a.update(sA, (short) 0); b = new Decimal128(); sB = makeNumericString(bDigits); b.update(sB, (short) 0); if (b.isZero()) { // don't do zero-divide if one comes up at random return; } r = new Decimal128(); r.addDestructive(a, (short) 0); r.divideDestructive(b, (short) 0); String res1 = r.toFormalString(); // Now do the operation with Java BigDecimal BigDecimal bdA = new BigDecimal(sA); BigDecimal bdB = new BigDecimal(sB); BigDecimal bdR = bdA.divide(bdB, 0, RoundingMode.HALF_UP); String res2 = bdR.toPlainString(); // Compare the results String message = "For operation " + a.toFormalString() + " / " + b.toFormalString(); assertEquals(message, res2, res1); } /* Return a random number with length digits, as a string. Results may be * negative or positive. */ private String makeNumericString(int length) { Random r = new Random(); StringBuilder b = new StringBuilder(); for(int i = 0; i < length; i++) { b.append(r.nextInt(10)); } // choose a random sign String sign = r.nextInt(2) == 0 ? "-" : ""; return sign + b.toString(); } @Test public void testPiNewton() { // see http://en.wikipedia.org/wiki/Approximations_of_%CF%80 // Below is the simple Newton's equation final int LOOPS = 100; final short SCALE = 33; Decimal128 current = new Decimal128(1, SCALE); Decimal128 multiplier = new Decimal128(); Decimal128 dividor = new Decimal128(); Decimal128 one = new Decimal128(1); for (int i = LOOPS; i > 0; --i) { multiplier.update(i, SCALE); current.multiplyDestructive(multiplier, SCALE); dividor.update(1 + 2 * i, SCALE); current.divideDestructive(dividor, SCALE); current.addDestructive(one, SCALE); } current.multiplyDestructive(new Decimal128(2), SCALE); assertTrue(current.toFormalString().startsWith("3.141592653589793238")); } @Test public void testPiArcsine() { // This one uses the arcsin method. Involves more multiplications/divisions. // pi=Sum (3 * 2n!/(16^n * (2n+1) * n! * n!)) // =Sum (3 * ((n+1)(n+2)...2n)/n!*16^n/(2n+1)) // =Sum (3 / (2n+1) * (n+1)/16 * (n+2)/32... * 2n/16(n+1)) // (note that it is split so that each term is not overflown) final int LOOPS = 50; final short SCALE = 30; Decimal128 total = new Decimal128(0); Decimal128 multiplier = new Decimal128(); Decimal128 dividor = new Decimal128(); Decimal128 current = new Decimal128(); for (int i = 0; i < LOOPS; ++i) { current.update(3, SCALE); dividor.update(2 * i + 1, SCALE); current.divideDestructive(dividor, SCALE); for (int j = 1; j <= i; ++j) { multiplier.update(i + j, SCALE); dividor.update(16 * j, SCALE); current.multiplyDestructive(multiplier, SCALE); current.divideDestructive(dividor, SCALE); } total.addDestructive(current, SCALE); } assertTrue(total.toFormalString().startsWith("3.141592653589793238462")); } @Test public void testDoubleValue() { Decimal128 quotient = new Decimal128(); Decimal128 three = new Decimal128(3); Decimal128 four = new Decimal128(9); Decimal128.divide(three, four, quotient, (short) 38); assertEquals(0.33333333333333333333333333d, quotient.doubleValue(), 0.0000000000000000000000001d); Decimal128 minusThree = new Decimal128(-3); Decimal128.divide(minusThree, four, quotient, (short) 38); assertEquals(-0.33333333333333333333333333d, quotient.doubleValue(), 0.0000000000000000000000001d); } @Test public void testFloatValue() { Decimal128 quotient = new Decimal128(); Decimal128 three = new Decimal128(3); Decimal128 four = new Decimal128(9); Decimal128.divide(three, four, quotient, (short) 38); assertEquals(0.3333333333333333f, quotient.floatValue(), 0.00000000001f); Decimal128 minusThree = new Decimal128(-3); Decimal128.divide(minusThree, four, quotient, (short) 38); assertEquals(-0.333333333333333f, quotient.floatValue(), 0.00000000001f); } @Test public void testSqrtAsDouble() { Decimal128 val1 = new Decimal128("1.00435134913958923485982394892384", (short) 36); Decimal128 val2 = new Decimal128("1.00345982739817298323423423", (short) 36); assertEquals(1.00217331292526d, val1.sqrtAsDouble(), 0.000000000000001d); assertEquals(1.00172841998127d, val2.sqrtAsDouble(), 0.000000000000001d); } @Test public void testPowAsDouble() { Decimal128 val1 = new Decimal128("1.00435134913958923485982394892384", (short) 36); assertEquals(1.004366436877081d, val1.powAsDouble(1.00345982739817298323423423d), 0.000000000000001d); Decimal128 val2 = new Decimal128("1.001", (short) 36); assertEquals(1.0100451202102512d, val2.powAsDouble(10), 0.000000000000001d); } @Test public void testPrecisionOverflow() { new Decimal128("1.004", (short) 3).checkPrecisionOverflow(4); try { new Decimal128("1.004", (short) 3).checkPrecisionOverflow(3); fail(); } catch (ArithmeticException ex) { } try { new Decimal128("1.004", (short) 3).checkPrecisionOverflow(2); fail(); } catch (ArithmeticException ex) { } new Decimal128("1.004", (short) 3).checkPrecisionOverflow(38); new Decimal128("-3322", (short) 0).checkPrecisionOverflow(4); try { new Decimal128("-3322", (short) 0).checkPrecisionOverflow(3); fail(); } catch (ArithmeticException ex) { } new Decimal128("-3322", (short) 1).checkPrecisionOverflow(5); try { new Decimal128("-3322", (short) 1).checkPrecisionOverflow(4); fail(); } catch (ArithmeticException ex) { } // Try the extremes of precision and scale. // digit measuring stick: // 12345678901234567890123456789012345678 new Decimal128("0.99999999999999999999999999999999999999", (short) 38) .checkPrecisionOverflow(38); try { new Decimal128("0.99999999999999999999999999999999999999", (short) 38) .checkPrecisionOverflow(37); fail(); } catch (ArithmeticException ex) { } new Decimal128("99999999999999999999999999999999999999", (short) 0) .checkPrecisionOverflow(38); try { new Decimal128("99999999999999999999999999999999999999", (short) 0) .checkPrecisionOverflow(37); fail(); } catch (ArithmeticException ex) { } } @Test public void testToLong() { Decimal128 d = new Decimal128("1.25", (short) 2); assertEquals(1, d.longValue()); d.update("4294967295", (short) 0); // 2^32-1 assertEquals(4294967295L, d.longValue()); d.update("4294967296", (short) 0); // 2^32 -- needs 2 32 bit words assertEquals(4294967296L, d.longValue()); d.update("-4294967295", (short) 0); // -(2^32-1) assertEquals(-4294967295L, d.longValue()); d.update("-4294967296", (short) 0); // -(2^32) assertEquals(-4294967296L, d.longValue()); d.update("4294967295.01", (short) 2); // 2^32-1 + .01 assertEquals(4294967295L, d.longValue()); d.update("4294967296.01", (short) 2); // 2^32 + .01 assertEquals(4294967296L, d.longValue()); // Compare long value with HiveDecimal#longValue d.update(37.678, (short)5); HiveDecimal hd = HiveDecimal.create(BigDecimal.valueOf(37.678)); assertEquals(hd.longValue(), d.longValue()); } @Test public void testToHiveDecimalString() { Decimal128 d1 = new Decimal128("4134.923076923077", (short) 15); assertEquals("4134.923076923077", d1.getHiveDecimalString()); Decimal128 d2 = new Decimal128("0.00923076923", (short) 15); assertEquals("0.00923076923", d2.getHiveDecimalString()); Decimal128 d3 = new Decimal128("0.00923076000", (short) 15); assertEquals("0.00923076", d3.getHiveDecimalString()); Decimal128 d4 = new Decimal128("4294967296.01", (short) 15); assertEquals("4294967296.01", d4.getHiveDecimalString()); Decimal128 d5 = new Decimal128("4294967296.01", (short) 2); assertEquals("4294967296.01", d5.getHiveDecimalString()); Decimal128 d6 = new Decimal128(); HiveDecimal hd1 = HiveDecimal.create(new BigInteger("42949672")); d6.update(hd1.bigDecimalValue()); assertEquals(hd1.toString(), d6.getHiveDecimalString()); Decimal128 d7 = new Decimal128(); HiveDecimal hd2 = HiveDecimal.create(new BigDecimal("0.0")); d7.update(hd2.bigDecimalValue()); assertEquals(hd2.toString(), d7.getHiveDecimalString()); Decimal128 d8 = new Decimal128(); HiveDecimal hd3 = HiveDecimal.create(new BigDecimal("0.00023000")); d8.update(hd3.bigDecimalValue()); assertEquals(hd3.toString(), d8.getHiveDecimalString()); Decimal128 d9 = new Decimal128(); HiveDecimal hd4 = HiveDecimal.create(new BigDecimal("0.1")); d9.update(hd4.bigDecimalValue()); assertEquals(hd4.toString(), d9.getHiveDecimalString()); Decimal128 d10 = new Decimal128(); HiveDecimal hd5 = HiveDecimal.create(new BigDecimal("-00.100")); d10.update(hd5.bigDecimalValue()); assertEquals(hd5.toString(), d10.getHiveDecimalString()); Decimal128 d11 = new Decimal128(); HiveDecimal hd6 = HiveDecimal.create(new BigDecimal("00.1")); d11.update(hd6.bigDecimalValue()); assertEquals(hd6.toString(), d11.getHiveDecimalString()); Decimal128 d12 = new Decimal128(27.000, (short)3); HiveDecimal hd7 = HiveDecimal.create(new BigDecimal("27.000")); assertEquals(hd7.toString(), d12.getHiveDecimalString()); assertEquals("27", d12.getHiveDecimalString()); Decimal128 d13 = new Decimal128(1234123000, (short)3); HiveDecimal hd8 = HiveDecimal.create(new BigDecimal("1234123000")); assertEquals(hd8.toString(), d13.getHiveDecimalString()); assertEquals("1234123000", d13.getHiveDecimalString()); } @Test public void testUpdateWithScale() { Decimal128 d1 = new Decimal128(1234.123, (short)4); Decimal128 d2 = new Decimal128(0, (short)3); d2.update(d1, (short)3); assertEquals(0, d1.compareTo(d2)); } }