/**
* 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.BigInteger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testcases for {@link UnsignedInt128}
*
* This code was based on code from Microsoft's PolyBase.
*/
public class TestUnsignedInt128 {
private UnsignedInt128 zero;
private UnsignedInt128 one;
private UnsignedInt128 two;
@Before
public void setUp() throws Exception {
zero = new UnsignedInt128(0);
one = new UnsignedInt128(1);
two = new UnsignedInt128(2);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testHashCode() {
assertNotEquals(one.hashCode(), two.hashCode());
assertNotEquals(zero.hashCode(), one.hashCode());
assertNotEquals(zero.hashCode(), two.hashCode());
assertEquals(zero.hashCode(), new UnsignedInt128(0).hashCode());
assertEquals(one.hashCode(), new UnsignedInt128(1).hashCode());
assertEquals(two.hashCode(), new UnsignedInt128(2).hashCode());
}
private void assertNotEquals(int a, int b) {
assertTrue(a != b);
}
private void assertNotEquals(long a, long b) {
assertTrue(a != b);
}
private void assertNotEquals(UnsignedInt128 a, UnsignedInt128 b) {
assertTrue(!a.equals(b));
}
@Test
public void testEquals() {
assertNotEquals(one, two);
assertNotEquals(zero, one);
assertNotEquals(zero, two);
assertEquals(zero, new UnsignedInt128(0));
assertEquals(one, new UnsignedInt128(1));
assertEquals(two, new UnsignedInt128(2));
}
@Test
public void testCompareTo() {
assertTrue(one.compareTo(two) < 0);
assertTrue(two.compareTo(one) > 0);
assertTrue(one.compareTo(zero) > 0);
assertTrue(zero.compareTo(two) < 0);
}
@Test
public void testCompareToScaleTen() {
assertTrue(zero.compareToScaleTen(new UnsignedInt128(0), (short) 3) == 0);
assertTrue(zero.compareToScaleTen(new UnsignedInt128(0), (short) -1) == 0);
assertTrue(zero.compareToScaleTen(new UnsignedInt128(0), (short) 12) == 0);
assertTrue(one.compareToScaleTen(zero, (short) 0) > 0);
assertTrue(one.compareToScaleTen(zero, (short) 3) > 0);
assertTrue(one.compareToScaleTen(zero, (short) -3) > 0);
assertTrue(zero.compareToScaleTen(one, (short) 3) < 0);
assertTrue(zero.compareToScaleTen(one, (short) 0) < 0);
assertTrue(zero.compareToScaleTen(one, (short) -1) == 0);
assertTrue(new UnsignedInt128(30).compareToScaleTen(new UnsignedInt128(3),
(short) 1) == 0);
assertTrue(new UnsignedInt128(30).compareToScaleTen(new UnsignedInt128(3),
(short) 2) < 0);
assertTrue(new UnsignedInt128(30).compareToScaleTen(new UnsignedInt128(3),
(short) 0) > 0);
assertTrue(new UnsignedInt128(680000000000L).compareToScaleTen(
new UnsignedInt128(68), (short) 10) == 0);
assertTrue(new UnsignedInt128(68).compareToScaleTen(new UnsignedInt128(
680000000000L), (short) -10) == 0);
assertTrue(new UnsignedInt128(680000000000L).compareToScaleTen(
new UnsignedInt128(0), (short) 60) > 0);
assertTrue(new UnsignedInt128(680000000000L).compareToScaleTen(
new UnsignedInt128(0), (short) 30) > 0);
assertTrue(new UnsignedInt128(680000000000L).compareToScaleTen(
new UnsignedInt128(0), (short) 10) > 0);
assertTrue(new UnsignedInt128(0).compareToScaleTen(new UnsignedInt128(
680000000000L), (short) -10) < 0);
assertTrue(new UnsignedInt128(0).compareToScaleTen(new UnsignedInt128(
680000000000L), (short) -11) < 0);
assertTrue(new UnsignedInt128(0).compareToScaleTen(new UnsignedInt128(
680000000000L), (short) -12) < 0);
assertTrue(new UnsignedInt128(0).compareToScaleTen(new UnsignedInt128(
680000000000L), (short) -13) == 0);
assertTrue(new UnsignedInt128(0).compareToScaleTen(new UnsignedInt128(
680000000000L), (short) -30) == 0);
assertTrue(new UnsignedInt128(680000000000L).compareToScaleTen(
new UnsignedInt128(680000000001L), (short) 0) < 1);
assertTrue(new UnsignedInt128(68000000000L).compareToScaleTen(
new UnsignedInt128(680000000001L), (short) -1) == 0);
assertTrue(new UnsignedInt128(68000000000L).compareToScaleTen(
new UnsignedInt128(680000000000L), (short) -1) == 0);
assertTrue(new UnsignedInt128(68000000000L).compareToScaleTen(
new UnsignedInt128(679999999999L), (short) -1) == 0);
assertTrue(new UnsignedInt128(0x10000000000000L).shiftLeftConstructive(32)
.compareToScaleTen(
new UnsignedInt128(0xA0000000000000L).shiftLeftConstructive(32),
(short) -1) == 0);
assertTrue(new UnsignedInt128(0x10000000000000L).shiftLeftConstructive(32)
.compareToScaleTen(
new UnsignedInt128(0xA0000000000000L).shiftLeftConstructive(32),
(short) 1) < 0);
assertTrue(new UnsignedInt128(0x10000000000000L).shiftLeftConstructive(32)
.compareToScaleTen(
new UnsignedInt128(0xA0000000000000L).shiftLeftConstructive(32),
(short) 0) < 0);
assertTrue(new UnsignedInt128(0x10000000000000L).shiftLeftConstructive(32)
.compareToScaleTen(
new UnsignedInt128(0xA0000000000000L).shiftLeftConstructive(32),
(short) -2) > 0);
}
@Test
public void testToFormalString() {
assertEquals("0", zero.toFormalString());
assertEquals("1", one.toFormalString());
assertEquals("30", new UnsignedInt128(30).toFormalString());
assertEquals("680000000000",
new UnsignedInt128(680000000000L).toFormalString());
assertEquals("6800000000000",
new UnsignedInt128(6800000000000L).toFormalString());
assertEquals("68", new UnsignedInt128(68).toFormalString());
assertEquals(zero, new UnsignedInt128("0"));
assertEquals(one, new UnsignedInt128("1"));
assertEquals(new UnsignedInt128(30), new UnsignedInt128("30"));
assertEquals(new UnsignedInt128(680000000000L), new UnsignedInt128(
"680000000000"));
assertEquals(new UnsignedInt128(6800000000000L), new UnsignedInt128(
"6800000000000"));
assertEquals(new UnsignedInt128(68), new UnsignedInt128("68"));
}
@Test
public void testUnsignedInt128() {
assertEquals(0L, new UnsignedInt128().asLong());
}
@Test
public void testUnsignedInt128UnsignedInt128() {
assertEquals(1L, new UnsignedInt128(one).asLong());
assertEquals(2L, new UnsignedInt128(two).asLong());
}
@Test
public void testUnsignedInt128IntIntIntInt() {
assertEquals(((long) 11) << 32L | 23L,
new UnsignedInt128(23, 11, 0, 0).asLong());
}
@Test
public void testZeroClear() {
assertFalse(one.isZero());
assertFalse(two.isZero());
assertNotEquals(0L, one.asLong());
assertNotEquals(0L, two.asLong());
two.zeroClear();
assertNotEquals(0L, one.asLong());
assertEquals(0L, two.asLong());
assertFalse(one.isZero());
assertTrue(two.isZero());
one.zeroClear();
assertEquals(0L, one.asLong());
assertEquals(0L, two.asLong());
assertTrue(one.isZero());
assertTrue(two.isZero());
}
@Test
public void testAddDestructive() {
one.addDestructive(two);
assertEquals(3L, one.asLong());
assertEquals(2L, two.asLong());
UnsignedInt128 big = new UnsignedInt128((1L << 62) + 3L);
UnsignedInt128 tmp = new UnsignedInt128(0L);
for (int i = 0; i < 54; ++i) {
tmp.addDestructive(big);
}
assertEquals(3 * 54, tmp.getV0());
assertEquals(0x80000000, tmp.getV1()); // (54 % 4) << 62
assertEquals(13, tmp.getV2()); // 54/4
assertEquals(0, tmp.getV3());
assertEquals((1L << 62) + 3L, big.asLong());
UnsignedInt128 huge = one.shiftLeftConstructive(127);
UnsignedInt128 huge2 = one.shiftLeftConstructive(127);
try {
huge2.addDestructive(huge);
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testSubtractDestructive() {
two.subtractDestructive(one);
assertEquals(1L, one.asLong());
assertEquals(1L, one.asLong());
try {
one.subtractDestructive(new UnsignedInt128(10L));
fail();
} catch (ArithmeticException ex) {
// ok
}
UnsignedInt128 big = new UnsignedInt128((1L << 62) + (3L << 34) + 3L);
big.shiftLeftDestructive(6);
UnsignedInt128 tmp = new UnsignedInt128((1L << 61) + 5L);
tmp.shiftLeftDestructive(6);
big.subtractDestructive(tmp);
big.subtractDestructive(tmp);
assertEquals((3 << 6) - 2 * (5 << 6), big.getV0());
assertEquals((3 << 8) - 1, big.getV1());
assertEquals(0, big.getV2());
assertEquals(0, big.getV3());
}
@Test
public void testMultiplyDestructiveInt() {
two.multiplyDestructive(1);
assertEquals(2L, two.asLong());
assertEquals(1L, one.asLong());
two.multiplyDestructive(2);
assertEquals(4L, two.asLong());
UnsignedInt128 five = new UnsignedInt128(5);
five.multiplyDestructive(6432346);
assertEquals(6432346 * 5, five.getV0());
assertEquals(0, five.getV1());
assertEquals(0, five.getV2());
assertEquals(0, five.getV3());
UnsignedInt128 big = new UnsignedInt128((1L << 62) + (3L << 34) + 3L);
big.multiplyDestructive(96);
assertEquals(3 * 96, big.getV0());
assertEquals(96 * (3 << 2), big.getV1());
assertEquals(96 / 4, big.getV2());
assertEquals(0, big.getV3());
UnsignedInt128 tmp = new UnsignedInt128(1);
tmp.shiftLeftDestructive(126);
tmp.multiplyDestructive(2);
try {
tmp.multiplyDestructive(2);
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testShiftDestructive() {
UnsignedInt128 big = new UnsignedInt128((1L << 62) + (23L << 32) + 89L);
big.shiftLeftDestructive(2);
assertEquals(89 * 4, big.getV0());
assertEquals(23 * 4, big.getV1());
assertEquals(1, big.getV2());
assertEquals(0, big.getV3());
big.shiftLeftDestructive(32);
assertEquals(0, big.getV0());
assertEquals(89 * 4, big.getV1());
assertEquals(23 * 4, big.getV2());
assertEquals(1, big.getV3());
big.shiftRightDestructive(2, true);
assertEquals(0, big.getV0());
assertEquals(89, big.getV1());
assertEquals(23 + (1 << 30), big.getV2());
assertEquals(0, big.getV3());
big.shiftRightDestructive(32, true);
assertEquals(89, big.getV0());
assertEquals(23 + (1 << 30), big.getV1());
assertEquals(0, big.getV2());
assertEquals(0, big.getV3());
// test rounding
UnsignedInt128 tmp = new UnsignedInt128(17);
assertEquals(17, tmp.getV0());
tmp.shiftRightDestructive(1, true);
assertEquals(9, tmp.getV0());
tmp.shiftRightDestructive(1, false);
assertEquals(4, tmp.getV0());
tmp.shiftRightDestructive(1, true);
assertEquals(2, tmp.getV0());
tmp.shiftRightDestructive(1, true);
assertEquals(1, tmp.getV0());
tmp.shiftRightDestructive(1, true);
assertEquals(1, tmp.getV0());
tmp.shiftRightDestructive(1, false);
assertEquals(0, tmp.getV0());
}
@Test
public void testMultiplyDestructiveUnsignedInt128() {
two.multiplyDestructive(one);
assertEquals(2L, two.asLong());
assertEquals(1L, one.asLong());
two.multiplyDestructive(two);
assertEquals(4L, two.asLong());
UnsignedInt128 five = new UnsignedInt128(5);
five.multiplyDestructive(new UnsignedInt128(6432346));
assertEquals(6432346 * 5, five.getV0());
assertEquals(0, five.getV1());
assertEquals(0, five.getV2());
assertEquals(0, five.getV3());
UnsignedInt128 big = new UnsignedInt128((1L << 62) + (3L << 34) + 3L);
big.multiplyDestructive(new UnsignedInt128(96));
assertEquals(3 * 96, big.getV0());
assertEquals(96 * (3 << 2), big.getV1());
assertEquals(96 / 4, big.getV2());
assertEquals(0, big.getV3());
UnsignedInt128 tmp = new UnsignedInt128(1);
tmp.shiftLeftDestructive(126);
tmp.multiplyDestructive(new UnsignedInt128(2));
try {
tmp.multiplyDestructive(new UnsignedInt128(2));
fail();
} catch (ArithmeticException ex) {
// ok
}
UnsignedInt128 complicated1 = new UnsignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0);
BigInteger bigInteger1 = complicated1.toBigIntegerSlow();
UnsignedInt128 complicated2 = new UnsignedInt128(54234234, 9, 0, 0);
BigInteger bigInteger2 = complicated2.toBigIntegerSlow();
complicated1.multiplyDestructive(complicated2);
BigInteger ans = bigInteger1.multiply(bigInteger2);
assertEquals(ans, complicated1.toBigIntegerSlow());
try {
UnsignedInt128 complicated3 = new UnsignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0);
complicated3
.multiplyDestructive(new UnsignedInt128(54234234, 9845, 0, 0));
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testMultiplyScaleDownTenDestructiveScaleTen() {
for (int scale = 0; scale < 38; ++scale) {
UnsignedInt128 right = new UnsignedInt128(1);
right.scaleUpTenDestructive((short) scale);
{
// 10000000....000
UnsignedInt128 leftJust = new UnsignedInt128(1);
leftJust.scaleUpTenDestructive((short) 15);
UnsignedInt128 leftInc = leftJust.incrementConstructive();
UnsignedInt128 leftDec = leftJust.decrementConstructive();
if (scale + 10 <= 38) {
leftJust.multiplyScaleDownTenDestructive(right, (short) (scale + 10));
assertEquals("scale=" + scale, 100000L, leftJust.asLong());
leftInc.multiplyScaleDownTenDestructive(right, (short) (scale + 10));
assertEquals("scale=" + scale, 100000L, leftInc.asLong());
leftDec.multiplyScaleDownTenDestructive(right, (short) (scale + 10));
assertEquals("scale=" + scale, 100000L, leftDec.asLong());
} else {
leftJust.multiplyScaleDownTenDestructive(right, (short) (scale + 10));
assertEquals("scale=" + scale, 0L, leftJust.asLong());
leftInc.multiplyScaleDownTenDestructive(right, (short) (scale + 10));
assertEquals("scale=" + scale, 0L, leftInc.asLong());
leftDec.multiplyScaleDownTenDestructive(right, (short) (scale + 10));
assertEquals("scale=" + scale, 0L, leftDec.asLong());
}
}
{
// 10000500....00
UnsignedInt128 leftHalfJust = new UnsignedInt128(1);
leftHalfJust.scaleUpTenDestructive((short) 6);
leftHalfJust.addDestructive(new UnsignedInt128(5));
leftHalfJust.scaleUpTenDestructive((short) 9);
UnsignedInt128 leftHalfInc = leftHalfJust.incrementConstructive();
UnsignedInt128 leftHalfDec = leftHalfJust.decrementConstructive();
if (scale + 10 <= 38) {
leftHalfJust.multiplyScaleDownTenDestructive(right,
(short) (scale + 10));
assertEquals("scale=" + scale, 100001L, leftHalfJust.asLong());
leftHalfInc.multiplyScaleDownTenDestructive(right,
(short) (scale + 10));
assertEquals("scale=" + scale, 100001L, leftHalfInc.asLong());
leftHalfDec.multiplyScaleDownTenDestructive(right,
(short) (scale + 10));
assertEquals("scale=" + scale, 100000L, leftHalfDec.asLong());
} else {
leftHalfJust.multiplyScaleDownTenDestructive(right,
(short) (scale + 10));
assertEquals("scale=" + scale, 0L, leftHalfJust.asLong());
leftHalfInc.multiplyScaleDownTenDestructive(right,
(short) (scale + 10));
assertEquals("scale=" + scale, 0L, leftHalfInc.asLong());
leftHalfDec.multiplyScaleDownTenDestructive(right,
(short) (scale + 10));
assertEquals("scale=" + scale, 0L, leftHalfDec.asLong());
}
}
}
}
@Test
public void testDivideDestructiveInt() {
two.divideDestructive(1);
assertEquals(1L, one.asLong());
assertEquals(2L, two.asLong());
one.divideDestructive(2);
assertEquals(0L, one.asLong());
assertEquals(2L, two.asLong());
UnsignedInt128 var1 = new UnsignedInt128(1234234662345L);
var1.divideDestructive(642337);
assertEquals(1234234662345L / 642337L, var1.asLong());
UnsignedInt128 complicated1 = new UnsignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0);
BigInteger bigInteger1 = complicated1.toBigIntegerSlow();
complicated1.divideDestructive(1534223465);
BigInteger bigInteger2 = BigInteger.valueOf(1534223465);
BigInteger ans = bigInteger1.divide(bigInteger2);
assertEquals(ans, complicated1.toBigIntegerSlow());
try {
complicated1.divideDestructive(0);
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testDivideDestructiveUnsignedInt128() {
UnsignedInt128 remainder = new UnsignedInt128();
two.divideDestructive(one, remainder);
assertEquals(1L, one.asLong());
assertEquals(2L, two.asLong());
assertEquals(zero, remainder);
one.divideDestructive(two, remainder);
assertEquals(0L, one.asLong());
assertEquals(2L, two.asLong());
assertEquals(new UnsignedInt128(1), remainder);
UnsignedInt128 var1 = new UnsignedInt128(1234234662345L);
var1.divideDestructive(new UnsignedInt128(642337), remainder);
assertEquals(1234234662345L / 642337L, var1.asLong());
assertEquals(1234234662345L % 642337L, remainder.asLong());
UnsignedInt128 complicated1 = new UnsignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0x42395ADC);
UnsignedInt128 complicated2 = new UnsignedInt128(0xF09DC19A, 0x00001234, 0,
0);
BigInteger bigInteger1 = complicated1.toBigIntegerSlow();
BigInteger bigInteger2 = complicated2.toBigIntegerSlow();
complicated1.divideDestructive(complicated2, remainder);
BigInteger ans = bigInteger1.divide(bigInteger2);
assertEquals(ans, complicated1.toBigIntegerSlow());
try {
complicated1.divideDestructive(zero, remainder);
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testDivideDestructiveUnsignedInt128Again() {
UnsignedInt128 complicated1 = new UnsignedInt128(0xF9892FCA, 0x59D109AD, 0,
0);
UnsignedInt128 complicated2 = new UnsignedInt128(0xF09DC19A, 3, 0, 0);
BigInteger bigInteger1 = complicated1.toBigIntegerSlow();
BigInteger bigInteger2 = complicated2.toBigIntegerSlow();
complicated1.divideDestructive(complicated2, new UnsignedInt128());
BigInteger ans = bigInteger1.divide(bigInteger2);
assertEquals(ans, complicated1.toBigIntegerSlow());
}
@Test
public void testBigIntConversion() {
BigInteger bigInteger = BigInteger.valueOf(0x1ABCDEF0123456L);
UnsignedInt128 uInt128 = new UnsignedInt128(bigInteger);
assertEquals(bigInteger, uInt128.toBigIntegerSlow());
}
}