/**
* 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.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.math.BigInteger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testcases for {@link SignedInt128}
*
* This code was based on code from Microsoft PolyBase.
*/
public class TestSignedInt128 {
private SignedInt128 zero;
private SignedInt128 one;
private SignedInt128 two;
private SignedInt128 negativeOne;
private SignedInt128 negativeTwo;
@Before
public void setUp() throws Exception {
zero = new SignedInt128(0);
one = new SignedInt128(1);
two = new SignedInt128(2);
negativeOne = new SignedInt128(-1);
negativeTwo = new SignedInt128(-2);
}
@After
public void tearDown() throws Exception {
}
@Test
public void testHashCode() {
assertTrue(one.hashCode() != two.hashCode());
assertTrue(zero.hashCode() != one.hashCode());
assertTrue(zero.hashCode() != two.hashCode());
assertTrue(one.hashCode() != negativeOne.hashCode());
assertTrue(two.hashCode() != negativeTwo.hashCode());
assertEquals(zero.hashCode(), new SignedInt128(-0).hashCode());
assertEquals(zero.hashCode(), new SignedInt128(0).hashCode());
assertEquals(one.hashCode(), new SignedInt128(1).hashCode());
assertEquals(two.hashCode(), new SignedInt128(2).hashCode());
}
@Test
public void testEquals() {
assertTrue(!one.equals(two));
assertTrue(!zero.equals(one));
assertTrue(!zero.equals(two));
assertEquals(zero, new SignedInt128(0));
assertEquals(one, new SignedInt128(1));
assertEquals(two, new SignedInt128(2));
assertTrue(!one.equals(negativeOne));
assertTrue(!two.equals(negativeTwo));
assertEquals(zero, new SignedInt128(-0));
}
@Test
public void testCompareTo() {
assertTrue(one.compareTo(two) < 0);
assertTrue(two.compareTo(one) > 0);
assertTrue(one.compareTo(zero) > 0);
assertTrue(zero.compareTo(two) < 0);
assertTrue(zero.compareTo(negativeOne) > 0);
assertTrue(zero.compareTo(negativeTwo) > 0);
assertTrue(one.compareTo(negativeOne) > 0);
assertTrue(one.compareTo(negativeTwo) > 0);
assertTrue(two.compareTo(negativeOne) > 0);
assertTrue(two.compareTo(negativeTwo) > 0);
assertTrue(negativeOne.compareTo(negativeTwo) > 0);
assertTrue(negativeTwo.compareTo(negativeOne) < 0);
}
@Test
public void testToFormalString() {
assertEquals("0", zero.toFormalString());
assertEquals("1", one.toFormalString());
assertEquals("-1", negativeOne.toFormalString());
assertEquals("-2", negativeTwo.toFormalString());
assertEquals("30", new SignedInt128(30).toFormalString());
assertEquals("680000000000",
new SignedInt128(680000000000L).toFormalString());
assertEquals("6800000000000",
new SignedInt128(6800000000000L).toFormalString());
assertEquals("68", new SignedInt128(68).toFormalString());
assertEquals("-30", new SignedInt128(-30).toFormalString());
assertEquals("-680000000000",
new SignedInt128(-680000000000L).toFormalString());
assertEquals("-6800000000000",
new SignedInt128(-6800000000000L).toFormalString());
assertEquals("-68", new SignedInt128(-68).toFormalString());
assertEquals(zero, new SignedInt128("0"));
assertEquals(one, new SignedInt128("1"));
assertEquals(zero, new SignedInt128("-0"));
assertEquals(negativeOne, new SignedInt128("-1"));
assertEquals(negativeTwo, new SignedInt128("-2"));
assertEquals(new SignedInt128(30), new SignedInt128("30"));
assertEquals(new SignedInt128(680000000000L), new SignedInt128(
"680000000000"));
assertEquals(new SignedInt128(6800000000000L), new SignedInt128(
"6800000000000"));
assertEquals(new SignedInt128(68), new SignedInt128("68"));
assertEquals(new SignedInt128(-30), new SignedInt128("-30"));
assertEquals(new SignedInt128(-680000000000L), new SignedInt128(
"-680000000000"));
assertEquals(new SignedInt128(-6800000000000L), new SignedInt128(
"-6800000000000"));
assertEquals(new SignedInt128(-68), new SignedInt128("-68"));
}
@Test
public void testSignedInt128() {
assertEquals(0L, new SignedInt128().longValue());
}
@Test
public void testSignedInt128SignedInt128() {
assertEquals(1L, new SignedInt128(one).longValue());
assertEquals(2L, new SignedInt128(two).longValue());
}
@Test
public void testSignedInt128IntIntIntInt() {
assertEquals(((long) 11) << 32L | 23L,
new SignedInt128(23, 11, 0, 0).longValue());
}
@Test
public void testZeroClear() {
assertFalse(one.isZero());
assertFalse(two.isZero());
assertTrue(0L != one.longValue());
assertTrue(0L != two.longValue());
two.zeroClear();
assertTrue(0L != one.longValue());
assertEquals(0L, two.longValue());
assertFalse(one.isZero());
assertTrue(two.isZero());
one.zeroClear();
assertEquals(0L, one.longValue());
assertEquals(0L, two.longValue());
assertTrue(one.isZero());
assertTrue(two.isZero());
}
@Test
public void testAddDestructive() {
one.addDestructive(two);
assertEquals(3L, one.longValue());
assertEquals(2L, two.longValue());
SignedInt128 big = new SignedInt128((1L << 62) + 3L);
SignedInt128 tmp = new SignedInt128(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.longValue());
SignedInt128 huge = new SignedInt128(one);
huge.shiftLeftDestructive(125);
SignedInt128 huge2 = new SignedInt128(one);
huge2.shiftLeftDestructive(125);
try {
huge2.addDestructive(huge);
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testSubtractDestructive() {
two.subtractDestructive(one);
assertEquals(1L, one.longValue());
assertEquals(1L, one.longValue());
one.subtractDestructive(new SignedInt128(10L));
assertEquals(-9L, one.longValue());
SignedInt128 big = new SignedInt128((1L << 62) + (3L << 34) + 3L);
big.shiftLeftDestructive(6);
SignedInt128 tmp = new SignedInt128((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.longValue());
assertEquals(1L, one.longValue());
two.multiplyDestructive(2);
assertEquals(4L, two.longValue());
SignedInt128 five = new SignedInt128(5);
five.multiplyDestructive(6432346);
assertEquals(6432346 * 5, five.getV0());
assertEquals(0, five.getV1());
assertEquals(0, five.getV2());
assertEquals(0, five.getV3());
SignedInt128 big = new SignedInt128((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());
SignedInt128 tmp = new SignedInt128(1);
tmp.shiftLeftDestructive(126);
try {
tmp.multiplyDestructive(2);
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testShiftDestructive() {
SignedInt128 big = new SignedInt128((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
SignedInt128 tmp = new SignedInt128(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 testMultiplyDestructiveSignedInt128() {
two.multiplyDestructive(one);
assertEquals(2L, two.longValue());
assertEquals(1L, one.longValue());
two.multiplyDestructive(two);
assertEquals(4L, two.longValue());
SignedInt128 five = new SignedInt128(5);
five.multiplyDestructive(new SignedInt128(6432346));
assertEquals(6432346 * 5, five.getV0());
assertEquals(0, five.getV1());
assertEquals(0, five.getV2());
assertEquals(0, five.getV3());
SignedInt128 big = new SignedInt128((1L << 62) + (3L << 34) + 3L);
big.multiplyDestructive(new SignedInt128(96));
assertEquals(3 * 96, big.getV0());
assertEquals(96 * (3 << 2), big.getV1());
assertEquals(96 / 4, big.getV2());
assertEquals(0, big.getV3());
SignedInt128 tmp = new SignedInt128(1);
tmp.shiftLeftDestructive(126);
try {
tmp.multiplyDestructive(new SignedInt128(2));
fail();
} catch (ArithmeticException ex) {
// ok
}
SignedInt128 complicated1 = new SignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0);
BigInteger bigInteger1 = complicated1.toBigIntegerSlow();
SignedInt128 complicated2 = new SignedInt128(54234234, 9, 0, 0);
BigInteger bigInteger2 = complicated2.toBigIntegerSlow();
complicated1.multiplyDestructive(complicated2);
BigInteger ans = bigInteger1.multiply(bigInteger2);
assertEquals(ans, complicated1.toBigIntegerSlow());
try {
SignedInt128 complicated3 = new SignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0);
complicated3.multiplyDestructive(new SignedInt128(54234234, 9845, 0, 0));
fail();
} catch (ArithmeticException ex) {
// ok
}
}
@Test
public void testDivideDestructiveInt() {
two.divideDestructive(1);
assertEquals(1L, one.longValue());
assertEquals(2L, two.longValue());
one.divideDestructive(2);
assertEquals(0L, one.longValue());
assertEquals(2L, two.longValue());
SignedInt128 var1 = new SignedInt128(1234234662345L);
var1.divideDestructive(642337);
assertEquals(1234234662345L / 642337L, var1.longValue());
SignedInt128 complicated1 = new SignedInt128(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 testDivideDestructiveSignedInt128() {
SignedInt128 remainder = new SignedInt128();
two.divideDestructive(one, remainder);
assertEquals(1L, one.longValue());
assertEquals(2L, two.longValue());
assertEquals(zero, remainder);
one.divideDestructive(two, remainder);
assertEquals(0L, one.longValue());
assertEquals(2L, two.longValue());
assertEquals(new SignedInt128(1), remainder);
SignedInt128 var1 = new SignedInt128(1234234662345L);
var1.divideDestructive(new SignedInt128(642337), remainder);
assertEquals(1234234662345L / 642337L, var1.longValue());
assertEquals(1234234662345L % 642337L, remainder.longValue());
SignedInt128 complicated1 = new SignedInt128(0xF9892FCA, 0x59D109AD,
0x0534AB4C, 0x42395ADC);
SignedInt128 complicated2 = new SignedInt128(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 testDivideDestructiveSignedInt128Again() {
SignedInt128 complicated1 = new SignedInt128(0xF9892FCA, 0x59D109AD, 0, 0);
SignedInt128 complicated2 = new SignedInt128(0xF09DC19A, 3, 0, 0);
BigInteger bigInteger1 = complicated1.toBigIntegerSlow();
BigInteger bigInteger2 = complicated2.toBigIntegerSlow();
complicated1.divideDestructive(complicated2, new SignedInt128());
BigInteger ans = bigInteger1.divide(bigInteger2);
assertEquals(ans, complicated1.toBigIntegerSlow());
}
}