From 31733b1b34e058ca27a3aaeb96b4fccc1494312e Mon Sep 17 00:00:00 2001 From: jinhyukify Date: Wed, 11 Feb 2026 21:28:22 +0900 Subject: [PATCH 1/6] HBASE-29889 Add LittleEndianBytes utility for fast LE primitive access --- .../hadoop/hbase/util/LittleEndianBytes.java | 263 ++++++++++++++++++ .../hadoop/hbase/util/UnsafeAccess.java | 79 ++++++ .../hbase/util/TestLittleEndianBytes.java | 28 ++ .../hbase/util/TestLittleEndianBytesBase.java | 207 ++++++++++++++ .../util/TestLittleEndianBytesWoUnsafe.java | 40 +++ 5 files changed, 617 insertions(+) create mode 100644 hbase-common/src/main/java/org/apache/hadoop/hbase/util/LittleEndianBytes.java create mode 100644 hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytes.java create mode 100644 hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesBase.java create mode 100644 hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesWoUnsafe.java diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/LittleEndianBytes.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/LittleEndianBytes.java new file mode 100644 index 000000000000..f3f7500877fd --- /dev/null +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/LittleEndianBytes.java @@ -0,0 +1,263 @@ +/* + * 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.hbase.util; + +import java.nio.ByteBuffer; +import org.apache.hadoop.hbase.ByteBufferExtendedCell; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent; +import org.apache.yetus.audience.InterfaceAudience; + +/** + * Utility methods for reading and writing little-endian integers and longs from byte[] and + * ByteBuffer. Used by hashing components to perform fast, low-level LE conversions with optional + * Unsafe acceleration. + */ +@InterfaceAudience.Private +public final class LittleEndianBytes { + final static boolean UNSAFE_UNALIGNED = HBasePlatformDependent.unaligned(); + + static abstract class Converter { + abstract int toInt(byte[] bytes, int offset); + + abstract int toInt(ByteBuffer buffer, int offset); + + abstract int putInt(byte[] bytes, int offset, int val); + + abstract long toLong(byte[] bytes, int offset); + + abstract long toLong(ByteBuffer buffer, int offset); + + abstract int putLong(byte[] bytes, int offset, long val); + } + + static class ConverterHolder { + static final String UNSAFE_CONVERTER_NAME = + ConverterHolder.class.getName() + "$UnsafeConverter"; + static final Converter BEST_CONVERTER = getBestConverter(); + + static Converter getBestConverter() { + try { + Class theClass = + Class.forName(UNSAFE_CONVERTER_NAME).asSubclass(Converter.class); + return theClass.getConstructor().newInstance(); + } catch (Throwable t) { + return PureJavaConverter.INSTANCE; + } + } + + static final class PureJavaConverter extends Converter { + static final PureJavaConverter INSTANCE = new PureJavaConverter(); + + private PureJavaConverter() { + } + + @Override + int toInt(byte[] bytes, int offset) { + int n = 0; + for (int i = offset + 3; i >= offset; i--) { + n <<= 8; + n ^= (bytes[i] & 0xFF); + } + return n; + } + + @Override + int toInt(ByteBuffer buffer, int offset) { + return Integer.reverseBytes(buffer.getInt(offset)); + } + + @Override + int putInt(byte[] bytes, int offset, int val) { + for (int i = offset; i < offset + 3; i++) { + bytes[i] = (byte) val; + val >>>= 8; + } + bytes[offset + 3] = (byte) val; + return offset + Bytes.SIZEOF_INT; + } + + @Override + long toLong(byte[] bytes, int offset) { + long l = 0; + for (int i = offset + 7; i >= offset; i--) { + l <<= 8; + l ^= (bytes[i] & 0xFFL); + } + return l; + } + + @Override + long toLong(ByteBuffer buffer, int offset) { + return Long.reverseBytes(buffer.getLong(offset)); + } + + @Override + int putLong(byte[] bytes, int offset, long val) { + for (int i = offset; i < offset + 7; i++) { + bytes[i] = (byte) val; + val >>>= 8; + } + bytes[offset + 7] = (byte) val; + return offset + Bytes.SIZEOF_LONG; + } + } + + static final class UnsafeConverter extends Converter { + static final UnsafeConverter INSTANCE = new UnsafeConverter(); + + public UnsafeConverter() { + } + + static { + if (!UNSAFE_UNALIGNED) { + throw new Error(); + } + } + + @Override + int toInt(byte[] bytes, int offset) { + return UnsafeAccess.toIntLE(bytes, offset); + } + + @Override + int toInt(ByteBuffer buffer, int offset) { + return UnsafeAccess.toIntLE(buffer, offset); + } + + @Override + int putInt(byte[] bytes, int offset, int val) { + return UnsafeAccess.putIntLE(bytes, offset, val); + } + + @Override + long toLong(byte[] bytes, int offset) { + return UnsafeAccess.toLongLE(bytes, offset); + } + + @Override + long toLong(ByteBuffer buffer, int offset) { + return UnsafeAccess.toLongLE(buffer, offset); + } + + @Override + int putLong(byte[] bytes, int offset, long val) { + return UnsafeAccess.putLongLE(bytes, offset, val); + } + } + } + + /* + * Writes an int in little-endian order. Caller must ensure bounds; no checks are performed. + */ + public static void putInt(byte[] bytes, int offset, int val) { + assert offset >= 0 && bytes.length - offset >= Bytes.SIZEOF_INT; + ConverterHolder.BEST_CONVERTER.putInt(bytes, offset, val); + } + + /* + * Reads an int in little-endian order. Caller must ensure bounds; no checks are performed. + */ + public static int toInt(byte[] bytes, int offset) { + assert offset >= 0 && bytes.length - offset >= Bytes.SIZEOF_INT; + return ConverterHolder.BEST_CONVERTER.toInt(bytes, offset); + } + + /* + * Reads an int in little-endian order from ByteBuffer. Caller must ensure bounds; no checks are + * performed. + */ + public static int toInt(ByteBuffer buffer, int offset) { + assert offset >= 0 && buffer.capacity() - offset >= Bytes.SIZEOF_INT; + return ConverterHolder.BEST_CONVERTER.toInt(buffer, offset); + } + + /* + * Writes a long in little-endian order. Caller must ensure bounds; no checks are performed. + */ + public static void putLong(byte[] bytes, int offset, long val) { + assert offset >= 0 && bytes.length - offset >= Bytes.SIZEOF_LONG; + ConverterHolder.BEST_CONVERTER.putLong(bytes, offset, val); + } + + /* + * Reads a long in little-endian order. Caller must ensure bounds; no checks are performed. + */ + public static long toLong(byte[] bytes, int offset) { + assert offset >= 0 && bytes.length - offset >= Bytes.SIZEOF_LONG; + return ConverterHolder.BEST_CONVERTER.toLong(bytes, offset); + } + + /* + * Reads a long in little-endian order from ByteBuffer. Caller must ensure bounds; no checks are + * performed. + */ + public static long toLong(ByteBuffer buffer, int offset) { + assert offset >= 0 && buffer.capacity() - offset >= Bytes.SIZEOF_LONG; + return ConverterHolder.BEST_CONVERTER.toLong(buffer, offset); + } + + /* + * Reads an int in little-endian order from the row portion of the Cell, at the given offset. + */ + public static int getRowAsInt(Cell cell, int offset) { + if (cell instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell; + return toInt(bbCell.getRowByteBuffer(), bbCell.getRowPosition() + offset); + } + return toInt(cell.getRowArray(), cell.getRowOffset() + offset); + } + + /* + * Reads a long in little-endian order from the row portion of the Cell, at the given offset. + */ + public static long getRowAsLong(Cell cell, int offset) { + if (cell instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell; + return toLong(bbCell.getRowByteBuffer(), bbCell.getRowPosition() + offset); + } + return toLong(cell.getRowArray(), cell.getRowOffset() + offset); + } + + /* + * Reads an int in little-endian order from the qualifier portion of the Cell, at the given + * offset. + */ + public static int getQualifierAsInt(Cell cell, int offset) { + if (cell instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell; + return toInt(bbCell.getQualifierByteBuffer(), bbCell.getQualifierPosition() + offset); + } + return toInt(cell.getQualifierArray(), cell.getQualifierOffset() + offset); + } + + /* + * Reads a long in little-endian order from the qualifier portion of the Cell, at the given + * offset. + */ + public static long getQualifierAsLong(Cell cell, int offset) { + if (cell instanceof ByteBufferExtendedCell) { + ByteBufferExtendedCell bbCell = (ByteBufferExtendedCell) cell; + return toLong(bbCell.getQualifierByteBuffer(), bbCell.getQualifierPosition() + offset); + } + return toLong(cell.getQualifierArray(), cell.getQualifierOffset() + offset); + } + + private LittleEndianBytes() { + } +} diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java index 3aa8a6ec123f..ef42efc21a8a 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java @@ -81,6 +81,21 @@ public static int toInt(byte[] bytes, int offset) { } } + /** + * Converts a byte array to an int value considering it was written in little-endian format. + * @param bytes byte array + * @param offset offset into array + * @return the int value + */ + public static int toIntLE(byte[] bytes, int offset) { + if (LITTLE_ENDIAN) { + return HBasePlatformDependent.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET); + } else { + return Integer + .reverseBytes(HBasePlatformDependent.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET)); + } + } + /** * Converts a byte array to a long value considering it was written in big-endian format. * @param bytes byte array @@ -96,6 +111,21 @@ public static long toLong(byte[] bytes, int offset) { } } + /** + * Converts a byte array to a long value considering it was written in little-endian format. + * @param bytes byte array + * @param offset offset into array + * @return the long value + */ + public static long toLongLE(byte[] bytes, int offset) { + if (LITTLE_ENDIAN) { + return HBasePlatformDependent.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET); + } else { + return Long + .reverseBytes(HBasePlatformDependent.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET)); + } + } + // APIs to write primitive data to a byte[] using Unsafe way /** * Put a short value out to the specified byte array position in big-endian format. @@ -127,6 +157,21 @@ public static int putInt(byte[] bytes, int offset, int val) { return offset + Bytes.SIZEOF_INT; } + /** + * Put an int value out to the specified byte array position in little-endian format. + * @param bytes the byte array + * @param offset position in the array + * @param val int to write out + * @return incremented offset + */ + public static int putIntLE(byte[] bytes, int offset, int val) { + if (!LITTLE_ENDIAN) { + val = Integer.reverseBytes(val); + } + HBasePlatformDependent.putInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val); + return offset + Bytes.SIZEOF_INT; + } + /** * Put a long value out to the specified byte array position in big-endian format. * @param bytes the byte array @@ -142,6 +187,21 @@ public static int putLong(byte[] bytes, int offset, long val) { return offset + Bytes.SIZEOF_LONG; } + /** + * Put a long value out to the specified byte array position in little-endian format. + * @param bytes the byte array + * @param offset position in the array + * @param val long to write out + * @return incremented offset + */ + public static int putLongLE(byte[] bytes, int offset, long val) { + if (!LITTLE_ENDIAN) { + val = Long.reverseBytes(val); + } + HBasePlatformDependent.putLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val); + return offset + Bytes.SIZEOF_LONG; + } + // APIs to read primitive data from a ByteBuffer using Unsafe way /** * Reads a short value at the given buffer's offset considering it was written in big-endian @@ -191,6 +251,18 @@ public static int toInt(ByteBuffer buf, int offset) { return getAsInt(buf, offset); } + /** + * Reads an int value at the given buffer's offset considering it was written in little-endian + * format. + * @return int value at offset + */ + public static int toIntLE(ByteBuffer buf, int offset) { + if (LITTLE_ENDIAN) { + return getAsInt(buf, offset); + } + return Integer.reverseBytes(getAsInt(buf, offset)); + } + /** * Reads a int value at the given Object's offset considering it was written in big-endian format. * @return int value at offset @@ -226,6 +298,13 @@ public static long toLong(ByteBuffer buf, int offset) { return getAsLong(buf, offset); } + public static long toLongLE(ByteBuffer buf, int offset) { + if (LITTLE_ENDIAN) { + return getAsLong(buf, offset); + } + return Long.reverseBytes(getAsLong(buf, offset)); + } + /** * Reads a long value at the given Object's offset considering it was written in big-endian * format. diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytes.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytes.java new file mode 100644 index 000000000000..e1c9c4f5552b --- /dev/null +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytes.java @@ -0,0 +1,28 @@ +/* + * 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.hbase.util; + +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.jupiter.api.Tag; + +@Tag(MiscTests.TAG) +@Tag(SmallTests.TAG) +public class TestLittleEndianBytes extends TestLittleEndianBytesBase { + +} diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesBase.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesBase.java new file mode 100644 index 000000000000..68720878e5e8 --- /dev/null +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesBase.java @@ -0,0 +1,207 @@ +/* + * 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.hbase.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.ByteBuffer; +import org.apache.hadoop.hbase.ByteBufferExtendedCell; +import org.apache.hadoop.hbase.ByteBufferKeyValue; +import org.apache.hadoop.hbase.Cell; +import org.apache.hadoop.hbase.KeyValue; +import org.junit.jupiter.api.Test; + +public abstract class TestLittleEndianBytesBase { + + @Test + public void testToInt() { + byte[] b = generateByteArray(32); + + for (int i = 0; i <= b.length - Integer.BYTES; i++) { + long expected = readIntLE(b, i); + assertEquals(expected, LittleEndianBytes.toInt(b, i)); + } + } + + @Test + public void testByteBufferToInt() { + byte[] b = generateByteArray(32); + ByteBuffer buf = ByteBuffer.wrap(b); + + for (int i = 0; i <= b.length - Integer.BYTES; i++) { + long expected = readIntLE(b, i); + assertEquals(expected, LittleEndianBytes.toInt(buf, i)); + } + } + + @Test + public void testPutInt() { + byte[] b = new byte[16]; + + int offset = 5; + int value = 0x12345678; + LittleEndianBytes.putInt(b, offset, value); + int expected = readIntLE(b, offset); + assertEquals(value, expected); + + offset += Integer.BYTES; + value = 0x9ABCDEF0; + LittleEndianBytes.putInt(b, offset, value); + expected = readIntLE(b, offset); + assertEquals(value, expected); + } + + @Test + public void testGetLongLE() { + byte[] b = generateByteArray(40); + + for (int i = 0; i <= b.length - Long.BYTES; i++) { + long expected = readLongLE(b, i); + assertEquals(expected, LittleEndianBytes.toLong(b, i)); + } + } + + @Test + public void testByteBufferGetLongLE() { + byte[] b = generateByteArray(40); + ByteBuffer buf = ByteBuffer.wrap(b); + + for (int i = 0; i <= b.length - Long.BYTES; i++) { + long expected = readLongLE(b, i); + assertEquals(expected, LittleEndianBytes.toLong(buf, i)); + } + } + + @Test + public void testPutLong() { + byte[] b = new byte[24]; + + int offset = 4; + long value = 0x0123456789ABCDEFL; + LittleEndianBytes.putLong(b, offset, value); + long expected = readLongLE(b, offset); + assertEquals(value, expected); + + offset += Long.BYTES; + value = 0xFEDCBA9876543210L; + LittleEndianBytes.putLong(b, offset, value); + expected = readLongLE(b, offset); + assertEquals(value, expected); + } + + @Test + public void testGetRowAsIntFromByteBufferExtendedCell() { + Cell bbCell = createByteBufferExtendedCell(); + byte[] row = bbCell.getRowArray(); + + for (int i = bbCell.getRowOffset(); i <= bbCell.getRowLength() - Integer.BYTES; i++) { + int expected = readIntLE(row, i); + assertEquals(expected, LittleEndianBytes.getRowAsInt(bbCell, i)); + } + } + + @Test + public void testGetRowAsIntFromCell() { + KeyValue cell = createCell(); + byte[] row = cell.getRowArray(); + + for (int i = cell.getRowOffset(); i <= cell.getRowLength() - Integer.BYTES; i++) { + int expected = readIntLE(row, cell.getRowOffset() + i); + assertEquals(expected, LittleEndianBytes.getRowAsInt(cell, i)); + } + } + + @Test + public void testGetRowAsLongFromByteBufferExtendedCell() { + Cell bbCell = createByteBufferExtendedCell(); + byte[] row = bbCell.getRowArray(); + + for (int i = bbCell.getRowOffset(); i <= bbCell.getRowLength() - Long.BYTES; i++) { + long expected = readLongLE(row, i); + assertEquals(expected, LittleEndianBytes.getRowAsLong(bbCell, i)); + } + } + + @Test + public void testGetRowAsLongFromCell() { + KeyValue cell = createCell(); + byte[] row = cell.getRowArray(); + + for (int i = cell.getRowOffset(); i <= cell.getRowLength() - Long.BYTES; i++) { + long expected = readLongLE(row, cell.getRowOffset() + i); + assertEquals(expected, LittleEndianBytes.getRowAsLong(cell, i)); + } + } + + @Test + public void testGetQualifierAsIntFromByteBufferExtendedCell() { + Cell bbCell = createByteBufferExtendedCell(); + byte[] qual = bbCell.getQualifierArray(); + + for (int i = bbCell.getQualifierOffset(); i + <= bbCell.getQualifierLength() - Integer.BYTES; i++) { + int expected = readIntLE(qual, i); + assertEquals(expected, LittleEndianBytes.getQualifierAsInt(bbCell, i)); + } + } + + @Test + public void testGetQualifierAsIntFromCell() { + KeyValue cell = createCell(); + byte[] qual = cell.getQualifierArray(); + + for (int i = cell.getQualifierOffset(); i <= cell.getQualifierLength() - Integer.BYTES; i++) { + int expected = readIntLE(qual, cell.getQualifierOffset() + i); + assertEquals(expected, LittleEndianBytes.getQualifierAsInt(cell, i)); + } + } + + private static KeyValue createCell() { + byte[] row = Bytes.toBytes("row_key_for_test_12345"); + byte[] family = Bytes.toBytes("f"); + byte[] qualifier = Bytes.toBytes("qualifier_12345"); + byte[] value = Bytes.toBytes(123456789); + return new KeyValue(row, family, qualifier, value); + } + + private static ByteBufferExtendedCell createByteBufferExtendedCell() { + KeyValue kv = createCell(); + ByteBuffer buffer = ByteBuffer.wrap(kv.getBuffer()); + return new ByteBufferKeyValue(buffer, 0, buffer.remaining()); + } + + private static byte[] generateByteArray(int size) { + byte[] b = new byte[size]; + for (int i = 0; i < b.length; i++) { + b[i] = (byte) (i * 3 + 7); + } + return b; + } + + private static int readIntLE(byte[] b, int off) { + return (b[off] & 0xFF) | ((b[off + 1] & 0xFF) << 8) | ((b[off + 2] & 0xFF) << 16) + | ((b[off + 3] & 0xFF) << 24); + } + + private static long readLongLE(byte[] b, int off) { + return ((long) (b[off] & 0xFF)) | ((long) (b[off + 1] & 0xFF) << 8) + | ((long) (b[off + 2] & 0xFF) << 16) | ((long) (b[off + 3] & 0xFF) << 24) + | ((long) (b[off + 4] & 0xFF) << 32) | ((long) (b[off + 5] & 0xFF) << 40) + | ((long) (b[off + 6] & 0xFF) << 48) | ((long) (b[off + 7] & 0xFF) << 56); + } +} diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesWoUnsafe.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesWoUnsafe.java new file mode 100644 index 000000000000..dc82e4a40871 --- /dev/null +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestLittleEndianBytesWoUnsafe.java @@ -0,0 +1,40 @@ +/* + * 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.hbase.util; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.mockStatic; + +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.mockito.MockedStatic; + +@Tag(MiscTests.TAG) +@Tag(SmallTests.TAG) +public class TestLittleEndianBytesWoUnsafe extends TestLittleEndianBytesBase { + @BeforeAll + public static void disableUnsafe() { + try (MockedStatic mocked = mockStatic(HBasePlatformDependent.class)) { + mocked.when(HBasePlatformDependent::unaligned).thenReturn(false); + assertFalse(LittleEndianBytes.UNSAFE_UNALIGNED); + } + } +} From e6a302ee7efd507bc96b63febe6d6c789ca469b9 Mon Sep 17 00:00:00 2001 From: jinhyukify Date: Wed, 11 Feb 2026 22:06:44 +0900 Subject: [PATCH 2/6] HBASE-29889 Extend HashKey with bulk little-endian accessors for fast hashing --- .../hadoop/hbase/util/ByteArrayHashKey.java | 10 ++ .../org/apache/hadoop/hbase/util/HashKey.java | 16 ++ .../hadoop/hbase/util/RowBloomHashKey.java | 11 ++ .../hadoop/hbase/util/RowColBloomHashKey.java | 160 +++++++++++++++++- .../hbase/util/TestRowColBloomHashKey.java | 141 +++++++++++++++ 5 files changed, 330 insertions(+), 8 deletions(-) create mode 100644 hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowColBloomHashKey.java diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteArrayHashKey.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteArrayHashKey.java index 63ffabfa90f6..e34de557c934 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteArrayHashKey.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteArrayHashKey.java @@ -44,4 +44,14 @@ private int getAbsolutePos(int pos) { public int length() { return this.length; } + + @Override + public int getIntLE(int pos) { + return LittleEndianBytes.toInt(t, getAbsolutePos(pos)); + } + + @Override + public long getLongLE(int pos) { + return LittleEndianBytes.toLong(t, getAbsolutePos(pos)); + } } diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/HashKey.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/HashKey.java index 9f12acb0b674..2a23919acecd 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/HashKey.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/HashKey.java @@ -35,4 +35,20 @@ public HashKey(T t) { /** Returns The number of bytes in this HashKey */ public abstract int length(); + + /** + * Returns the little-endian 32-bit int value starting at the given position in this + * {@code HashKey}. + * @param pos the starting offset of the 4-byte little-endian int + * @return the 32-bit value decoded in little-endian order + */ + public abstract int getIntLE(int pos); + + /** + * Returns the little-endian 64-bit long value starting at the given position in this + * {@code HashKey}. + * @param pos the starting offset of the 8-byte little-endian long + * @return the 64-bit value decoded in little-endian order + */ + public abstract long getLongLE(int pos); } diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowBloomHashKey.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowBloomHashKey.java index 10b9dd8ac0ee..af3655b335bd 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowBloomHashKey.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowBloomHashKey.java @@ -37,4 +37,15 @@ public byte get(int offset) { public int length() { return this.t.getRowLength(); } + + @Override + public int getIntLE(int offset) { + return LittleEndianBytes.getRowAsInt(t, offset); + } + + @Override + public long getLongLE(int offset) { + return LittleEndianBytes.getRowAsLong(t, offset); + } + } diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowColBloomHashKey.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowColBloomHashKey.java index 68162f89e19f..31ab58ac1da4 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowColBloomHashKey.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/RowColBloomHashKey.java @@ -23,15 +23,18 @@ import org.apache.yetus.audience.InterfaceAudience; /** - * An hash key for ROWCOL bloom. This assumes the cells to be serialized in the Keyvalue + * A hash key for ROWCOL bloom. This assumes the cells to be serialized in the Keyvalue * serialization format with Empty column family. Note that the byte representing the family length * is considered to be 0 */ @InterfaceAudience.Private public class RowColBloomHashKey extends CellHashKey { - + // last 8 bytes (LATEST_TS[1..7] + MAX_TYPE) as LE long + private static final long LAST_8_BYTES = -1L; + private static final long LATEST_TS_LE = LittleEndianBytes.toLong(LATEST_TS, 0); private final int rowLength; private final int qualLength; + private final int totalLength; public RowColBloomHashKey(Cell cell) { super(cell); @@ -39,12 +42,16 @@ public RowColBloomHashKey(Cell cell) { // We don't consider the family length for ROWCOL bloom. So subtract the famLen from the // length calculation. Timestamp and type are of no relevance here qualLength = cell.getQualifierLength(); + // ROWCOL Bloom byte layout: + // <2B RK length> <1B CF length> <8B TS> <1B TYPE> + totalLength = KeyValue.ROW_LENGTH_SIZE + rowLength + KeyValue.FAMILY_LENGTH_SIZE + qualLength + + KeyValue.TIMESTAMP_TYPE_SIZE; } @Override public byte get(int offset) { - // For ROW_COL blooms we use bytes - // (2 bytes) , , 0 (one byte CF length), , (8 btes), ( 1 byte) + // ROWCOL Bloom byte layout: + // <2B RK length> <1B CF length> <8B TS> <1B TYPE> if (offset < Bytes.SIZEOF_SHORT) { // assign locally int rowlen = rowLength; @@ -80,9 +87,146 @@ public byte get(int offset) { @Override public int length() { - // For ROW_COL blooms we use bytes - // (2 bytes) , , 0 (one byte CF length), , (8 btes), ( 1 byte) - return KeyValue.ROW_LENGTH_SIZE + this.t.getRowLength() + KeyValue.FAMILY_LENGTH_SIZE - + this.t.getQualifierLength() + KeyValue.TIMESTAMP_TYPE_SIZE; + return totalLength; + } + + @Override + public int getIntLE(int offset) { + // Handle fast path that can return the row key as int directly + // Compute rowkey section range. + final int rowEnd = KeyValue.ROW_LENGTH_SIZE + rowLength; + if (offset >= KeyValue.ROW_LENGTH_SIZE && offset + Bytes.SIZEOF_INT <= rowEnd) { + return LittleEndianBytes.getRowAsInt(t, offset - KeyValue.ROW_LENGTH_SIZE); + } + + // Compute qualifier section range. + final int qualStart = rowEnd + KeyValue.FAMILY_LENGTH_SIZE; + final int qualEnd = qualStart + qualLength; + if (offset >= qualStart && offset + Bytes.SIZEOF_INT <= qualEnd) { + return LittleEndianBytes.getQualifierAsInt(t, offset - qualStart); + } + + // Compute timestamp section range. + final int tsEnd = qualEnd + KeyValue.TIMESTAMP_SIZE; + if (offset >= qualEnd && offset + Bytes.SIZEOF_INT <= tsEnd) { + return LittleEndianBytes.toInt(LATEST_TS, offset - qualEnd); + } + + return (int) assembleCrossingLE(offset, Bytes.SIZEOF_INT); + } + + @Override + public long getLongLE(int offset) { + // Handle fast path that can return the row key as long directly + // Compute rowkey section range. + final int rowEnd = KeyValue.ROW_LENGTH_SIZE + rowLength; + if (offset >= KeyValue.ROW_LENGTH_SIZE && offset + Bytes.SIZEOF_LONG <= rowEnd) { + return LittleEndianBytes.getRowAsLong(t, offset - KeyValue.ROW_LENGTH_SIZE); + } + + // Compute qualifier section range. + final int qualStart = rowEnd + KeyValue.FAMILY_LENGTH_SIZE; + final int qualEnd = qualStart + qualLength; + if (offset >= qualStart && offset + Bytes.SIZEOF_LONG <= qualEnd) { + return LittleEndianBytes.getQualifierAsLong(t, offset - qualStart); + } + + // Compute timestamp section range. + if (offset == qualEnd) { + return LATEST_TS_LE; + } + + // Optimization: when the offset points to the last 8 bytes, + // we can return the precomputed trailing long value directly. + if (offset + Bytes.SIZEOF_LONG == totalLength) { + return LAST_8_BYTES; + } + + return assembleCrossingLE(offset, Bytes.SIZEOF_LONG); + } + + private long assembleCrossingLE(int offset, int wordBytes) { + final int rowEnd = KeyValue.ROW_LENGTH_SIZE + rowLength; + final int qualStart = rowEnd + KeyValue.FAMILY_LENGTH_SIZE; + final int qualEnd = qualStart + qualLength; + final int tsEnd = qualEnd + KeyValue.TIMESTAMP_SIZE; + + long result = 0L; + int pos = offset; + int remaining = wordBytes; + + while (remaining > 0) { + // 1) row length field [0,2) + if (pos < KeyValue.ROW_LENGTH_SIZE) { + if (pos == 0) { + result |= (rowLength >>> 8) & 0xFF; + result |= (rowLength & 0xFF) << 8; + pos += 2; + remaining -= 2; + } else { + result |= rowLength & 0xFF; + pos += 1; + remaining -= 1; + } + continue; + } + + // 2) row bytes [2, rowEnd) + if (pos < rowEnd) { + final int take = Math.min(rowEnd - pos, remaining); + final int rOffset = pos - KeyValue.ROW_LENGTH_SIZE; + for (int i = 0; i < take; i++) { + final int shift = (wordBytes - remaining) * 8; + final byte b = PrivateCellUtil.getRowByte(t, rOffset + i); + result |= ((long) b & 0xFF) << shift; + remaining -= 1; + } + pos += take; + continue; + } + + // 3) family length byte (always 0) + if (pos == rowEnd) { + pos += 1; + remaining -= 1; + continue; + } + + // 4) qualifier bytes [qualStart, qualEnd) + if (pos < qualEnd) { + final int take = Math.min(qualEnd - pos, remaining); + final int qOffset = pos - qualStart; + for (int i = 0; i < take; i++) { + final int shift = (wordBytes - remaining) * 8; + final int b = PrivateCellUtil.getQualifierByte(t, qOffset + i) & 0xFF; + result |= ((long) b) << shift; + remaining -= 1; + } + pos += take; + continue; + } + + // 5) timestamp bytes [qualEnd, tsEnd) -> LATEST_TS + if (pos < tsEnd) { + final int take = Math.min(tsEnd - pos, remaining); + final int tsOff = pos - qualEnd; + for (int i = 0; i < take; i++) { + final int shift = (wordBytes - remaining) * 8; + final int b = LATEST_TS[tsOff + i] & 0xFF; + result |= ((long) b) << shift; + remaining -= 1; + } + pos += take; + continue; + } + + // 6) type byte at typePos -> MAX_TYPE + final int shift = (wordBytes - remaining) * 8; + result |= ((long) MAX_TYPE & 0xFF) << shift; + pos += 1; + remaining -= 1; + } + + return result; } } diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowColBloomHashKey.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowColBloomHashKey.java new file mode 100644 index 000000000000..94977627a144 --- /dev/null +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestRowColBloomHashKey.java @@ -0,0 +1,141 @@ +/* + * 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.hbase.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.PrivateCellUtil; +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.ClassRule; +import org.junit.experimental.categories.Category; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@Category({ MiscTests.class, SmallTests.class }) +public class TestRowColBloomHashKey { + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestRowColBloomHashKey.class); + + private KeyValue kv; + private RowColBloomHashKey hashKey; + + @BeforeEach + public void setup() { + byte[] row = Bytes.toBytes("row_key_test"); + byte[] family = Bytes.toBytes("family"); + byte[] qualifier = Bytes.toBytes("qualifier"); + byte[] value = Bytes.toBytes("1234567890"); + kv = new KeyValue(row, family, qualifier, value); + hashKey = new RowColBloomHashKey(kv); + } + + @Test + public void testGet() { + final int rowLen = kv.getRowLength(); + final int qualLen = kv.getQualifierLength(); + + // Expected virtual layout: + // [rowLen(2 bytes)][row bytes][famLen(1 byte, always 0)][qualifier bytes] + // [timestamp(8 bytes, HConstants.LATEST_TIMESTAMP)][type(1 byte, KeyValue.Type.Maximum)] + final int expectedLength = KeyValue.ROW_LENGTH_SIZE + rowLen + KeyValue.FAMILY_LENGTH_SIZE + + qualLen + KeyValue.TIMESTAMP_TYPE_SIZE; + assertEquals(expectedLength, hashKey.length()); + + int offset = 0; + + // 1) Row length field: MSB then LSB + int msb = hashKey.get(offset++) & 0xFF; + int lsb = hashKey.get(offset++) & 0xFF; + int decodedRowLen = (msb << 8) | lsb; + assertEquals(rowLen, decodedRowLen); + + // 2) Row bytes + for (int i = 0; i < rowLen; i++) { + int expected = PrivateCellUtil.getRowByte(kv, i) & 0xFF; + int actual = hashKey.get(offset++) & 0xFF; + assertEquals(expected, actual, "row byte mismatch at i=" + i); + } + + // 3) Family length byte + assertEquals(0, hashKey.get(offset++) & 0xFF); + + // 4) Qualifier bytes + for (int i = 0; i < qualLen; i++) { + int expected = PrivateCellUtil.getQualifierByte(kv, i) & 0xFF; + int actual = hashKey.get(offset++) & 0xFF; + assertEquals(expected, actual, "qualifier byte mismatch at i=" + i); + } + + // 5) Timestamp bytes: should match HConstants.LATEST_TIMESTAMP in big-endian + // RowColBloomHashKey uses LATEST_TS byte[] from CellHashKey which corresponds to latest + // timestamp. + long ts = HConstants.LATEST_TIMESTAMP; + for (int i = 0; i < KeyValue.TIMESTAMP_SIZE; i++) { + // KeyValue timestamp serialization is big-endian + int expected = (int) ((ts >>> (8 * (KeyValue.TIMESTAMP_SIZE - 1 - i))) & 0xFF); + int actual = hashKey.get(offset++) & 0xFF; + assertEquals(expected, actual, "timestamp byte mismatch at i=" + i); + } + + // 6) Type byte: should be Maximum + assertEquals(KeyValue.Type.Maximum.getCode(), hashKey.get(offset++)); + + // consumed exactly all bytes + assertEquals(hashKey.length(), offset); + } + + @Test + public void testGetIntLE() { + for (int i = 0; i <= hashKey.length() - Bytes.SIZEOF_INT; i++) { + int expected = expectedIntLEFromGet(i); + int actual = hashKey.getIntLE(i); + assertEquals(expected, actual, "sequential mismatch at offset=" + i); + } + } + + @Test + public void testGetLongLE() { + for (int i = 0; i <= hashKey.length() - Bytes.SIZEOF_LONG; i++) { + long expected = expectedLongLEFromGet(i); + long actual = hashKey.getLongLE(i); + assertEquals(expected, actual, "sequential mismatch at offset=" + i); + } + } + + private int expectedIntLEFromGet(int offset) { + int b0 = hashKey.get(offset) & 0xFF; + int b1 = hashKey.get(offset + 1) & 0xFF; + int b2 = hashKey.get(offset + 2) & 0xFF; + int b3 = hashKey.get(offset + 3) & 0xFF; + return (b0) | (b1 << 8) | (b2 << 16) | (b3 << 24); + } + + private long expectedLongLEFromGet(int offset) { + long result = 0L; + for (int i = 0; i < Bytes.SIZEOF_LONG; i++) { + long b = hashKey.get(offset + i) & 0xFFL; + result |= b << (8 * i); + } + return result; + } +} From fbdc25c19f9488c6f7d130fdf21d18201e36d1d9 Mon Sep 17 00:00:00 2001 From: jinhyukify Date: Wed, 11 Feb 2026 22:18:49 +0900 Subject: [PATCH 3/6] HBASE-29889 Implement XXH3 64bit hashing --- .../org/apache/hadoop/hbase/util/Hash64.java | 45 + .../org/apache/hadoop/hbase/util/XXH3.java | 557 +++++ .../apache/hadoop/hbase/util/TestXXH3.java | 92 + .../src/test/resources/xxh3/README.md | 65 + .../src/test/resources/xxh3/xxh3_vectors.csv | 2050 +++++++++++++++++ 5 files changed, 2809 insertions(+) create mode 100644 hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash64.java create mode 100644 hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java create mode 100644 hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java create mode 100644 hbase-common/src/test/resources/xxh3/README.md create mode 100644 hbase-common/src/test/resources/xxh3/xxh3_vectors.csv diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash64.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash64.java new file mode 100644 index 000000000000..83dc1e73bd58 --- /dev/null +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash64.java @@ -0,0 +1,45 @@ +/* + * 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.hbase.util; + +import org.apache.yetus.audience.InterfaceAudience; +import org.apache.yetus.audience.InterfaceStability; + +/** + * Interface for computing 64-bit hash values. + */ +@InterfaceAudience.Private +@InterfaceStability.Stable +public interface Hash64 { + /** + * Computes a 64-bit hash from the given {@code HashKey} using a seed of 0. + * @param hashKey the input key providing byte access + * @return the computed 64-bit hash value + */ + default long hash64(HashKey hashKey) { + return hash64(hashKey, 0L); + } + + /** + * Computes a 64-bit hash from the given {@code HashKey} and seed. + * @param hashKey the input key providing byte access + * @param seed the 64-bit seed value + * @return the computed 64-bit hash value + */ + long hash64(HashKey hashKey, long seed); +} diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java new file mode 100644 index 000000000000..51c029f016af --- /dev/null +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java @@ -0,0 +1,557 @@ +/* + * 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.hbase.util; + +import static java.lang.Integer.toUnsignedLong; + +import org.apache.yetus.audience.InterfaceAudience; +import org.apache.yetus.audience.InterfaceStability; + +/** + * XXH3 64-bit hash implementation. + *

+ * Optimized for modern CPU architectures, providing high throughput, strong dispersion, and minimal + * memory usage. Designed for low-latency, zero-allocation hashing in most cases. + *

+ * Note, however, that when the input exceeds 240 bytes and a non-default seed (anything other than + * {@code 0}) is used, a derived secret must be generated internally, which results in a temporary + * byte-array allocation. + * @see XXH3 + * Algorithm + */ +@InterfaceAudience.Private +@InterfaceStability.Unstable +public class XXH3 extends Hash implements Hash64 { + private static final XXH3 _instance = new XXH3(); + private static final long MASK32 = 0xFFFFFFFFL; + private static final long PRIME32_1 = 0x9E3779B1L; + private static final long PRIME32_2 = 0x85EBCA77L; + private static final long PRIME32_3 = 0xC2B2AE3DL; + private static final long PRIME64_1 = 0x9E3779B185EBCA87L; + private static final long PRIME64_2 = 0xC2B2AE3D27D4EB4FL; + private static final long PRIME64_3 = 0x165667B19E3779F9L; + private static final long PRIME64_4 = 0x85EBCA77C2B2AE63L; + private static final long PRIME64_5 = 0x27D4EB2F165667C5L; + private static final long PRIME_MX1 = 0x165667919E3779F9L; + private static final long PRIME_MX2 = 0x9FB21C651E98DF25L; + + private static final byte[] DEFAULT_SECRET = { (byte) 0xb8, (byte) 0xfe, (byte) 0x6c, (byte) 0x39, + (byte) 0x23, (byte) 0xa4, (byte) 0x4b, (byte) 0xbe, (byte) 0x7c, (byte) 0x01, (byte) 0x81, + (byte) 0x2c, (byte) 0xf7, (byte) 0x21, (byte) 0xad, (byte) 0x1c, (byte) 0xde, (byte) 0xd4, + (byte) 0x6d, (byte) 0xe9, (byte) 0x83, (byte) 0x90, (byte) 0x97, (byte) 0xdb, (byte) 0x72, + (byte) 0x40, (byte) 0xa4, (byte) 0xa4, (byte) 0xb7, (byte) 0xb3, (byte) 0x67, (byte) 0x1f, + (byte) 0xcb, (byte) 0x79, (byte) 0xe6, (byte) 0x4e, (byte) 0xcc, (byte) 0xc0, (byte) 0xe5, + (byte) 0x78, (byte) 0x82, (byte) 0x5a, (byte) 0xd0, (byte) 0x7d, (byte) 0xcc, (byte) 0xff, + (byte) 0x72, (byte) 0x21, (byte) 0xb8, (byte) 0x08, (byte) 0x46, (byte) 0x74, (byte) 0xf7, + (byte) 0x43, (byte) 0x24, (byte) 0x8e, (byte) 0xe0, (byte) 0x35, (byte) 0x90, (byte) 0xe6, + (byte) 0x81, (byte) 0x3a, (byte) 0x26, (byte) 0x4c, (byte) 0x3c, (byte) 0x28, (byte) 0x52, + (byte) 0xbb, (byte) 0x91, (byte) 0xc3, (byte) 0x00, (byte) 0xcb, (byte) 0x88, (byte) 0xd0, + (byte) 0x65, (byte) 0x8b, (byte) 0x1b, (byte) 0x53, (byte) 0x2e, (byte) 0xa3, (byte) 0x71, + (byte) 0x64, (byte) 0x48, (byte) 0x97, (byte) 0xa2, (byte) 0x0d, (byte) 0xf9, (byte) 0x4e, + (byte) 0x38, (byte) 0x19, (byte) 0xef, (byte) 0x46, (byte) 0xa9, (byte) 0xde, (byte) 0xac, + (byte) 0xd8, (byte) 0xa8, (byte) 0xfa, (byte) 0x76, (byte) 0x3f, (byte) 0xe3, (byte) 0x9c, + (byte) 0x34, (byte) 0x3f, (byte) 0xf9, (byte) 0xdc, (byte) 0xbb, (byte) 0xc7, (byte) 0xc7, + (byte) 0x0b, (byte) 0x4f, (byte) 0x1d, (byte) 0x8a, (byte) 0x51, (byte) 0xe0, (byte) 0x4b, + (byte) 0xcd, (byte) 0xb4, (byte) 0x59, (byte) 0x31, (byte) 0xc8, (byte) 0x9f, (byte) 0x7e, + (byte) 0xc9, (byte) 0xd9, (byte) 0x78, (byte) 0x73, (byte) 0x64, (byte) 0xea, (byte) 0xc5, + (byte) 0xac, (byte) 0x83, (byte) 0x34, (byte) 0xd3, (byte) 0xeb, (byte) 0xc3, (byte) 0xc5, + (byte) 0x81, (byte) 0xa0, (byte) 0xff, (byte) 0xfa, (byte) 0x13, (byte) 0x63, (byte) 0xeb, + (byte) 0x17, (byte) 0x0d, (byte) 0xdd, (byte) 0x51, (byte) 0xb7, (byte) 0xf0, (byte) 0xda, + (byte) 0x49, (byte) 0xd3, (byte) 0x16, (byte) 0x55, (byte) 0x26, (byte) 0x29, (byte) 0xd4, + (byte) 0x68, (byte) 0x9e, (byte) 0x2b, (byte) 0x16, (byte) 0xbe, (byte) 0x58, (byte) 0x7d, + (byte) 0x47, (byte) 0xa1, (byte) 0xfc, (byte) 0x8f, (byte) 0xf8, (byte) 0xb8, (byte) 0xd1, + (byte) 0x7a, (byte) 0xd0, (byte) 0x31, (byte) 0xce, (byte) 0x45, (byte) 0xcb, (byte) 0x3a, + (byte) 0x8f, (byte) 0x95, (byte) 0x16, (byte) 0x04, (byte) 0x28, (byte) 0xaf, (byte) 0xd7, + (byte) 0xfb, (byte) 0xca, (byte) 0xbb, (byte) 0x4b, (byte) 0x40, (byte) 0x7e, }; + + // Pre-converted longs from DefaultSecret to avoid reconstruction at runtime + private static final long DEFAULT_SECRET_LONG_0 = 0xBE4BA423396CFEB8L; + private static final long DEFAULT_SECRET_LONG_1 = 0x1CAD21F72C81017CL; + private static final long DEFAULT_SECRET_LONG_2 = 0xDB979083E96DD4DEL; + private static final long DEFAULT_SECRET_LONG_3 = 0x1F67B3B7A4A44072L; + private static final long DEFAULT_SECRET_LONG_4 = 0x78E5C0CC4EE679CBL; + private static final long DEFAULT_SECRET_LONG_5 = 0x2172FFCC7DD05A82L; + private static final long DEFAULT_SECRET_LONG_6 = 0x8E2443F7744608B8L; + private static final long DEFAULT_SECRET_LONG_7 = 0x4C263A81E69035E0L; + private static final long DEFAULT_SECRET_LONG_8 = 0xCB00C391BB52283CL; + private static final long DEFAULT_SECRET_LONG_9 = 0xA32E531B8B65D088L; + private static final long DEFAULT_SECRET_LONG_10 = 0x4EF90DA297486471L; + private static final long DEFAULT_SECRET_LONG_11 = 0xD8ACDEA946EF1938L; + private static final long DEFAULT_SECRET_LONG_12 = 0x3F349CE33F76FAA8L; + private static final long DEFAULT_SECRET_LONG_13 = 0x1D4F0BC7C7BBDCF9L; + private static final long DEFAULT_SECRET_LONG_14 = 0x3159B4CD4BE0518AL; + private static final long DEFAULT_SECRET_LONG_15 = 0x647378D9C97E9FC8L; + + // Pre-converted longs from DefaultSecret (3-byte offset) to avoid reconstruction at runtime. + private static final long DEFAULT_SECRET_3_LONG_0 = 0x81017CBE4BA42339L; + private static final long DEFAULT_SECRET_3_LONG_1 = 0x6DD4DE1CAD21F72CL; + private static final long DEFAULT_SECRET_3_LONG_2 = 0xA44072DB979083E9L; + private static final long DEFAULT_SECRET_3_LONG_3 = 0xE679CB1F67B3B7A4L; + private static final long DEFAULT_SECRET_3_LONG_4 = 0xD05A8278E5C0CC4EL; + private static final long DEFAULT_SECRET_3_LONG_5 = 0x4608B82172FFCC7DL; + private static final long DEFAULT_SECRET_3_LONG_6 = 0x9035E08E2443F774L; + private static final long DEFAULT_SECRET_3_LONG_7 = 0x52283C4C263A81E6L; + private static final long DEFAULT_SECRET_3_LONG_8 = 0x65D088CB00C391BBL; + private static final long DEFAULT_SECRET_3_LONG_9 = 0x486471A32E531B8BL; + private static final long DEFAULT_SECRET_3_LONG_10 = 0xEF19384EF90DA297L; + private static final long DEFAULT_SECRET_3_LONG_11 = 0x76FAA8D8ACDEA946L; + private static final long DEFAULT_SECRET_3_LONG_12 = 0xBBDCF93F349CE33FL; + private static final long DEFAULT_SECRET_3_LONG_13 = 0xE0518A1D4F0BC7C7L; + + private static final long DEFAULT_SECRET_LONG_119 = 0x7378D9C97E9FC831L; + private static final long DEFAULT_SECRET_LONG_127 = 0xEBD33483ACC5EA64L; + + private static final long DEFAULT_SECRET_BITFLIP_0 = + ((DEFAULT_SECRET_LONG_0 >>> 32) ^ (DEFAULT_SECRET_LONG_0 & MASK32)); + private static final long DEFAULT_SECRET_BITFLIP_1 = (DEFAULT_SECRET_LONG_1 ^ DEFAULT_SECRET_LONG_2); + private static final long DEFAULT_SECRET_BITFLIP_2 = (DEFAULT_SECRET_LONG_3 ^ DEFAULT_SECRET_LONG_4); + private static final long DEFAULT_SECRET_BITFLIP_3 = (DEFAULT_SECRET_LONG_5 ^ DEFAULT_SECRET_LONG_6); + private static final long DEFAULT_SECRET_BITFLIP_4 = (DEFAULT_SECRET_LONG_7 ^ DEFAULT_SECRET_LONG_8); + + public static Hash getInstance() { + return _instance; + } + + @Override + public long hash64(HashKey hashKey, long seed) { + int length = hashKey.length(); + long result64; + + if (length <= 16) { + result64 = hashSmall(hashKey, length, seed); + } else if (length <= 240) { + result64 = hashMedium(hashKey, length, seed); + } else { + result64 = hashLarge(hashKey, length, seed); + } + + return result64; + } + + @Override + public int hash(HashKey hashKey, int seed) { + long result64 = hash64(hashKey, (long) seed); + return toLow32Int(result64); + } + + private byte[] initSecret(long seed) { + if (seed == 0L) { + return DEFAULT_SECRET; + } else { + // For non-default seeds, derived secret generation requires a new byte array. + byte[] derivedSecret = new byte[192]; + for (int i = 0; i < 12; i++) { + putLong64LE(derivedSecret, i * 16, readLong64LE(DEFAULT_SECRET, i * 16) + seed); + putLong64LE(derivedSecret, i * 16 + 8, readLong64LE(DEFAULT_SECRET, i * 16 + 8) - seed); + } + return derivedSecret; + } + } + + private static int toLow32Int(long value) { + // Grab only the lower 32 bits. + return (int) value; + } + + private static long avalanche(long hash) { + hash ^= hash >>> 37; + hash *= PRIME_MX1; + hash ^= hash >>> 32; + return hash; + } + + private static long avalancheXXH64(long hash) { + hash ^= hash >>> 33; + hash *= PRIME64_2; + hash ^= hash >>> 29; + hash *= PRIME64_3; + hash ^= hash >>> 32; + return hash; + } + + private static long rrmxmx(long hash, int inputLength) { + hash ^= Long.rotateLeft(hash, 49) ^ Long.rotateLeft(hash, 24); + hash *= PRIME_MX2; + hash ^= (hash >>> 35) + inputLength; + hash *= PRIME_MX2; + hash ^= hash >>> 28; + return hash; + } + + private static long mul128AndFold64(long x, long y) { + long xLow = x & MASK32; + long xHigh = x >>> 32; + long yLow = y & MASK32; + long yHigh = y >>> 32; + + long lowLow = xLow * yLow; + long lowHigh = xLow * yHigh; + long highLow = xHigh * yLow; + long highHigh = xHigh * yHigh; + + long mid = lowHigh + (highLow & MASK32) + (lowLow >>> 32); + long hi = highHigh + (highLow >>> 32) + (mid >>> 32); + long lo = (mid << 32) | (lowLow & MASK32); + + return hi ^ lo; + } + + private static long mix16(HashKey key, int keyOffset, long secretLow, long secretHigh, + long seed) { + long inputLow = readLong64LE(key, keyOffset); + long inputHigh = readLong64LE(key, keyOffset + 8); + return mul128AndFold64(inputLow ^ (secretLow + seed), inputHigh ^ (secretHigh - seed)); + } + + private static int readInt32LE(HashKey key, int offset) { + return key.getIntLE(offset); + } + + private static long readLong64LE(HashKey key, int offset) { + return key.getLongLE(offset); + } + + private static long readLong64LE(byte[] input, int offset) { + return LittleEndianBytes.toLong(input, offset); + } + + private static void putLong64LE(byte[] input, int offset, long value) { + LittleEndianBytes.putLong(input, offset, value); + } + + private long hashEmpty(long seed) { + return avalancheXXH64(seed ^ DEFAULT_SECRET_BITFLIP_4); + } + + private long hashLength1To3(HashKey hashKey, int length, long seed) { + assert length >= 1 && length <= 3; + int middleOrLast = hashKey.get(length >> 1); + int first = hashKey.get(0); + int last = hashKey.get(length - 1); + long combined = toUnsignedLong((middleOrLast << 24) | (first << 16) | (length << 8) | last); + long bitflip = DEFAULT_SECRET_BITFLIP_0 + seed; + return avalancheXXH64(bitflip ^ combined); + } + + private long hashLength4To8(HashKey hashKey, int length, long seed) { + assert length >= 4 && length <= 8; + int inputFirst = readInt32LE(hashKey, 0); + int inputLast = readInt32LE(hashKey, length - 4); + long combined = toUnsignedLong(inputLast) | (toUnsignedLong(inputFirst) << 32); + long modifiedSeed = seed ^ (Long.reverseBytes(seed & MASK32)); + long bitflip = DEFAULT_SECRET_BITFLIP_1 - modifiedSeed; + long value = combined ^ bitflip; + return rrmxmx(value, length); + } + + private long hashLength9To16(HashKey hashKey, int length, long seed) { + assert length >= 9 && length <= 16; + long inputFirst = readLong64LE(hashKey, 0); + long inputLast = readLong64LE(hashKey, length - 8); + long low = (DEFAULT_SECRET_BITFLIP_2 + seed) ^ inputFirst; + long high = (DEFAULT_SECRET_BITFLIP_3 - seed) ^ inputLast; + long value = length + Long.reverseBytes(low) + high + mul128AndFold64(low, high); + return avalanche(value); + } + + private long hashSmall(HashKey hashKey, int length, long seed) { + if (length > 8) { + return hashLength9To16(hashKey, length, seed); + } else if (length > 3) { + return hashLength4To8(hashKey, length, seed); + } else if (length > 0) { + return hashLength1To3(hashKey, length, seed); + } + + return hashEmpty(seed); + } + + private long hashLength17To128(HashKey hashKey, int length, long seed) { + assert length >= 17 && length <= 128; + long acc = length * PRIME64_1; + switch ((length - 1) / 32) { + case 3: + acc += mix16(hashKey, 48, DEFAULT_SECRET_LONG_12, DEFAULT_SECRET_LONG_13, seed); + acc += mix16(hashKey, length - 64, DEFAULT_SECRET_LONG_14, DEFAULT_SECRET_LONG_15, seed); + case 2: + acc += mix16(hashKey, 32, DEFAULT_SECRET_LONG_8, DEFAULT_SECRET_LONG_9, seed); + acc += mix16(hashKey, length - 48, DEFAULT_SECRET_LONG_10, DEFAULT_SECRET_LONG_11, seed); + case 1: + acc += mix16(hashKey, 16, DEFAULT_SECRET_LONG_4, DEFAULT_SECRET_LONG_5, seed); + acc += mix16(hashKey, length - 32, DEFAULT_SECRET_LONG_6, DEFAULT_SECRET_LONG_7, seed); + case 0: + acc += mix16(hashKey, 0, DEFAULT_SECRET_LONG_0, DEFAULT_SECRET_LONG_1, seed); + acc += mix16(hashKey, length - 16, DEFAULT_SECRET_LONG_2, DEFAULT_SECRET_LONG_3, seed); + break; + } + + return avalanche(acc); + } + + private long hashLength129To240(HashKey hashKey, int length, long seed) { + assert length >= 129 && length <= 240; + long acc = length * PRIME64_1; + + acc += mix16(hashKey, 16 * 0, DEFAULT_SECRET_LONG_0, DEFAULT_SECRET_LONG_1, seed); + acc += mix16(hashKey, 16 * 1, DEFAULT_SECRET_LONG_2, DEFAULT_SECRET_LONG_3, seed); + acc += mix16(hashKey, 16 * 2, DEFAULT_SECRET_LONG_4, DEFAULT_SECRET_LONG_5, seed); + acc += mix16(hashKey, 16 * 3, DEFAULT_SECRET_LONG_6, DEFAULT_SECRET_LONG_7, seed); + acc += mix16(hashKey, 16 * 4, DEFAULT_SECRET_LONG_8, DEFAULT_SECRET_LONG_9, seed); + acc += mix16(hashKey, 16 * 5, DEFAULT_SECRET_LONG_10, DEFAULT_SECRET_LONG_11, seed); + acc += mix16(hashKey, 16 * 6, DEFAULT_SECRET_LONG_12, DEFAULT_SECRET_LONG_13, seed); + acc += mix16(hashKey, 16 * 7, DEFAULT_SECRET_LONG_14, DEFAULT_SECRET_LONG_15, seed); + + acc = avalanche(acc); + + switch ((length - 128) >> 4) { + case 7: + acc += mix16(hashKey, 16 * 14, DEFAULT_SECRET_3_LONG_12, DEFAULT_SECRET_3_LONG_13, seed); + case 6: + acc += mix16(hashKey, 16 * 13, DEFAULT_SECRET_3_LONG_10, DEFAULT_SECRET_3_LONG_11, seed); + case 5: + acc += mix16(hashKey, 16 * 12, DEFAULT_SECRET_3_LONG_8, DEFAULT_SECRET_3_LONG_9, seed); + case 4: + acc += mix16(hashKey, 16 * 11, DEFAULT_SECRET_3_LONG_6, DEFAULT_SECRET_3_LONG_7, seed); + case 3: + acc += mix16(hashKey, 16 * 10, DEFAULT_SECRET_3_LONG_4, DEFAULT_SECRET_3_LONG_5, seed); + case 2: + acc += mix16(hashKey, 16 * 9, DEFAULT_SECRET_3_LONG_2, DEFAULT_SECRET_3_LONG_3, seed); + case 1: + acc += mix16(hashKey, 16 * 8, DEFAULT_SECRET_3_LONG_0, DEFAULT_SECRET_3_LONG_1, seed); + case 0: + acc += mix16(hashKey, length - 16, DEFAULT_SECRET_LONG_119, DEFAULT_SECRET_LONG_127, seed); + break; + } + + return avalanche(acc); + } + + private long hashMedium(HashKey hashKey, int length, long seed) { + if (length > 128) { + return hashLength129To240(hashKey, length, seed); + } else { + return hashLength17To128(hashKey, length, seed); + } + } + + private long hashLarge(HashKey hashKey, int length, long seed) { + // Hot path for large inputs. + // This code is intentionally fully inlined to guarantee zero allocations and keep the inner + // loop JIT-friendly; no temporary arrays/objects. + long acc0 = PRIME32_3; + long acc1 = PRIME64_1; + long acc2 = PRIME64_2; + long acc3 = PRIME64_3; + long acc4 = PRIME64_4; + long acc5 = PRIME32_2; + long acc6 = PRIME64_5; + long acc7 = PRIME32_1; + + byte[] secret = initSecret(seed); + final int blockSize = 1024; + final int numberOfBlocks = (length - 1) / blockSize; + final int numberOfStripesPerBlock = (secret.length - 64) / 8; + for (int b = 0; b < numberOfBlocks; b++) { + // per block round accumulation + for (int s = 0; s < numberOfStripesPerBlock; s++) { + final int stripeOffset = (b * blockSize) + (s * 64); + final int secretOffset = s * 8; + + long lane0 = readLong64LE(hashKey, stripeOffset); + long secret0 = readLong64LE(secret, secretOffset); + long value0 = lane0 ^ secret0; + acc1 += lane0; + acc0 += (value0 & MASK32) * (value0 >>> 32); + + long lane1 = readLong64LE(hashKey, stripeOffset + 8); + long secret1 = readLong64LE(secret, secretOffset + 8); + long value1 = lane1 ^ secret1; + acc0 += lane1; + acc1 += (value1 & MASK32) * (value1 >>> 32); + + long lane2 = readLong64LE(hashKey, stripeOffset + 16); + long secret2 = readLong64LE(secret, secretOffset + 16); + long value2 = lane2 ^ secret2; + acc3 += lane2; + acc2 += (value2 & MASK32) * (value2 >>> 32); + + long lane3 = readLong64LE(hashKey, stripeOffset + 24); + long secret3 = readLong64LE(secret, secretOffset + 24); + long value3 = lane3 ^ secret3; + acc2 += lane3; + acc3 += (value3 & MASK32) * (value3 >>> 32); + + long lane4 = readLong64LE(hashKey, stripeOffset + 32); + long secret4 = readLong64LE(secret, secretOffset + 32); + long value4 = lane4 ^ secret4; + acc5 += lane4; + acc4 += (value4 & MASK32) * (value4 >>> 32); + + long lane5 = readLong64LE(hashKey, stripeOffset + 40); + long secret5 = readLong64LE(secret, secretOffset + 40); + long value5 = lane5 ^ secret5; + acc4 += lane5; + acc5 += (value5 & MASK32) * (value5 >>> 32); + + long lane6 = readLong64LE(hashKey, stripeOffset + 48); + long secret6 = readLong64LE(secret, secretOffset + 48); + long value6 = lane6 ^ secret6; + acc7 += lane6; + acc6 += (value6 & MASK32) * (value6 >>> 32); + + long lane7 = readLong64LE(hashKey, stripeOffset + 56); + long secret7 = readLong64LE(secret, secretOffset + 56); + long value7 = lane7 ^ secret7; + acc6 += lane7; + acc7 += (value7 & MASK32) * (value7 >>> 32); + } + + // per block scramble + acc0 = (acc0 ^ (acc0 >>> 47) ^ readLong64LE(secret, (secret.length - 64))) * PRIME32_1; + acc1 = (acc1 ^ (acc1 >>> 47) ^ readLong64LE(secret, (secret.length - 56))) * PRIME32_1; + acc2 = (acc2 ^ (acc2 >>> 47) ^ readLong64LE(secret, (secret.length - 48))) * PRIME32_1; + acc3 = (acc3 ^ (acc3 >>> 47) ^ readLong64LE(secret, (secret.length - 40))) * PRIME32_1; + acc4 = (acc4 ^ (acc4 >>> 47) ^ readLong64LE(secret, (secret.length - 32))) * PRIME32_1; + acc5 = (acc5 ^ (acc5 >>> 47) ^ readLong64LE(secret, (secret.length - 24))) * PRIME32_1; + acc6 = (acc6 ^ (acc6 >>> 47) ^ readLong64LE(secret, (secret.length - 16))) * PRIME32_1; + acc7 = (acc7 ^ (acc7 >>> 47) ^ readLong64LE(secret, (secret.length - 8))) * PRIME32_1; + } + + // Handle last partial block + final int lastBlockSize = length - (numberOfBlocks * blockSize); + final int lastBlockOffset = numberOfBlocks * blockSize; + final int numberOfFullStripes = (lastBlockSize - 1) / 64; + for (int s = 0; s < numberOfFullStripes; s++) { + final int stripeOffset = lastBlockOffset + (s * 64); + final int secretOffset = s * 8; + + long lane0 = readLong64LE(hashKey, stripeOffset); + long secret0 = readLong64LE(secret, secretOffset); + long value0 = lane0 ^ secret0; + acc1 += lane0; + acc0 += (value0 & MASK32) * (value0 >>> 32); + + long lane1 = readLong64LE(hashKey, stripeOffset + 8); + long secret1 = readLong64LE(secret, secretOffset + 8); + long value1 = lane1 ^ secret1; + acc0 += lane1; + acc1 += (value1 & MASK32) * (value1 >>> 32); + + long lane2 = readLong64LE(hashKey, stripeOffset + 16); + long secret2 = readLong64LE(secret, secretOffset + 16); + long value2 = lane2 ^ secret2; + acc3 += lane2; + acc2 += (value2 & MASK32) * (value2 >>> 32); + + long lane3 = readLong64LE(hashKey, stripeOffset + 24); + long secret3 = readLong64LE(secret, secretOffset + 24); + long value3 = lane3 ^ secret3; + acc2 += lane3; + acc3 += (value3 & MASK32) * (value3 >>> 32); + + long lane4 = readLong64LE(hashKey, stripeOffset + 32); + long secret4 = readLong64LE(secret, secretOffset + 32); + long value4 = lane4 ^ secret4; + acc5 += lane4; + acc4 += (value4 & MASK32) * (value4 >>> 32); + + long lane5 = readLong64LE(hashKey, stripeOffset + 40); + long secret5 = readLong64LE(secret, secretOffset + 40); + long value5 = lane5 ^ secret5; + acc4 += lane5; + acc5 += (value5 & MASK32) * (value5 >>> 32); + + long lane6 = readLong64LE(hashKey, stripeOffset + 48); + long secret6 = readLong64LE(secret, secretOffset + 48); + long value6 = lane6 ^ secret6; + acc7 += lane6; + acc6 += (value6 & MASK32) * (value6 >>> 32); + + long lane7 = readLong64LE(hashKey, stripeOffset + 56); + long secret7 = readLong64LE(secret, secretOffset + 56); + long value7 = lane7 ^ secret7; + acc6 += lane7; + acc7 += (value7 & MASK32) * (value7 >>> 32); + } + + // Handle last stripe + final int lastStripeOffset = length - 64; + final int lastSecretOffset = secret.length - 71; + + long lane0 = readLong64LE(hashKey, lastStripeOffset); + long secret0 = readLong64LE(secret, lastSecretOffset); + long value0 = lane0 ^ secret0; + acc1 += lane0; + acc0 += (value0 & MASK32) * (value0 >>> 32); + + long lane1 = readLong64LE(hashKey, lastStripeOffset + 8); + long secret1 = readLong64LE(secret, lastSecretOffset + 8); + long value1 = lane1 ^ secret1; + acc0 += lane1; + acc1 += (value1 & MASK32) * (value1 >>> 32); + + long lane2 = readLong64LE(hashKey, lastStripeOffset + 16); + long secret2 = readLong64LE(secret, lastSecretOffset + 16); + long value2 = lane2 ^ secret2; + acc3 += lane2; + acc2 += (value2 & MASK32) * (value2 >>> 32); + + long lane3 = readLong64LE(hashKey, lastStripeOffset + 24); + long secret3 = readLong64LE(secret, lastSecretOffset + 24); + long value3 = lane3 ^ secret3; + acc2 += lane3; + acc3 += (value3 & MASK32) * (value3 >>> 32); + + long lane4 = readLong64LE(hashKey, lastStripeOffset + 32); + long secret4 = readLong64LE(secret, lastSecretOffset + 32); + long value4 = lane4 ^ secret4; + acc5 += lane4; + acc4 += (value4 & MASK32) * (value4 >>> 32); + + long lane5 = readLong64LE(hashKey, lastStripeOffset + 40); + long secret5 = readLong64LE(secret, lastSecretOffset + 40); + long value5 = lane5 ^ secret5; + acc4 += lane5; + acc5 += (value5 & MASK32) * (value5 >>> 32); + + long lane6 = readLong64LE(hashKey, lastStripeOffset + 48); + long secret6 = readLong64LE(secret, lastSecretOffset + 48); + long value6 = lane6 ^ secret6; + acc7 += lane6; + acc6 += (value6 & MASK32) * (value6 >>> 32); + + long lane7 = readLong64LE(hashKey, lastStripeOffset + 56); + long secret7 = readLong64LE(secret, lastSecretOffset + 56); + long value7 = lane7 ^ secret7; + acc6 += lane7; + acc7 += (value7 & MASK32) * (value7 >>> 32); + + // do final merge + long result = length * PRIME64_1; + result += mul128AndFold64(acc0 ^ readLong64LE(secret, 11), acc1 ^ readLong64LE(secret, 11 + 8)); + result += mul128AndFold64(acc2 ^ readLong64LE(secret, 11 + 16), + acc3 ^ readLong64LE(secret, 11 + 16 + 8)); + result += mul128AndFold64(acc4 ^ readLong64LE(secret, 11 + 32), + acc5 ^ readLong64LE(secret, 11 + 32 + 8)); + result += mul128AndFold64(acc6 ^ readLong64LE(secret, 11 + 48), + acc7 ^ readLong64LE(secret, 11 + 48 + 8)); + + return avalanche(result); + } +} diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java new file mode 100644 index 000000000000..bab3ad35ae06 --- /dev/null +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java @@ -0,0 +1,92 @@ +/* + * 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.hbase.util; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.ClassRule; +import org.junit.experimental.categories.Category; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +@Category({ MiscTests.class, SmallTests.class }) +class TestXXH3 { + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestXXH3.class); + + private static final String RESOURCE = "xxh3/xxh3_vectors.csv"; + private static final XXH3 xxh3 = new XXH3(); + + static class Case { + final int len; + final long seed; + final long expected; + + Case(int len, long seed, long expected) { + this.len = len; + this.seed = seed; + this.expected = expected; + } + } + + static Stream vectors() throws Exception { + InputStream is = TestXXH3.class.getClassLoader().getResourceAsStream(RESOURCE); + if (is == null) { + throw new IllegalStateException(RESOURCE + " not found in resources"); + } + + try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + List out = new ArrayList<>(4096); + + br.lines().filter(s -> !s.isEmpty()).forEach(line -> { + String[] p = line.split(","); + int len = Integer.parseInt(p[0]); + + for (int i = 1; i + 1 < p.length; i += 2) { + long seed = Long.parseLong(p[i]); + long expected = Long.parseLong(p[i + 1]); + out.add(new Case(len, seed, expected)); + } + }); + + return out.stream(); + } + } + + @ParameterizedTest + @MethodSource("vectors") + void testXxh3(Case c) { + byte[] buf = new byte[c.len]; + for (int i = 0; i < c.len; i++) { + buf[i] = (byte) i; + } + + final ByteArrayHashKey key = new ByteArrayHashKey(buf, 0, buf.length); + long actual = xxh3.hash64(key, c.seed); + assertEquals(c.expected, actual, "len=" + c.len + " seed=" + c.seed); + } +} diff --git a/hbase-common/src/test/resources/xxh3/README.md b/hbase-common/src/test/resources/xxh3/README.md new file mode 100644 index 000000000000..c8266982c01e --- /dev/null +++ b/hbase-common/src/test/resources/xxh3/README.md @@ -0,0 +1,65 @@ +# Generating XXH3 Test Vectors + +This snippet shows how to generate test vectors for the XXH3 hash function using the upstream implementation. + +## Clone xxHash + +```shell +git clone https://github.com/Cyan4973/xxHash.git +cd xxHash +``` + +## Create the generator file + +```shell +cat > gen_xxh3_vectors.c << 'EOF' +#include "xxhash.c" +#include +#include +#include + +int main(int argc, char** argv) { + if (argc < 2) { + fprintf(stderr, "usage: %s [seed...]\n", argv[0]); + return 1; + } + + int maxLen = atoi(argv[1]); + int sc = argc - 2; + if (sc <= 0) sc = 1; + + unsigned char* buf = malloc((size_t)maxLen + 1); + if (!buf) return 2; + + for (int len = 0; len <= maxLen; len++) { + for (int i = 0; i < len; i++) buf[i] = (unsigned char)i; + + printf("%d", len); + + for (int i = 0; i < sc; i++) { + const char* seedStr = (argc >= 3) ? argv[2 + i] : "0"; + long long s64 = strtoll(seedStr, NULL, 10); + uint64_t seed = (uint64_t)s64; + uint64_t h = XXH3_64bits_withSeed(buf, (size_t)len, seed); + printf(",%lld,%lld", s64, (long long)(int64_t)h); + } + putchar('\n'); + } + + free(buf); + return 0; +} +EOF + +cc -O2 -std=c99 gen_xxh3_vectors.c -o gen_xxh3_vectors +``` + +## Generate CSV + +```shell +./gen_xxh3_vectors 2049 0 31 > xxh3_vectors.csv +``` + +- Lengths: 0 to 2049 (inclusive) +- Seeds: 0, 31 +- Output format: `length,seed,hash,seed,hash,...` diff --git a/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv b/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv new file mode 100644 index 000000000000..57fbdb1147ab --- /dev/null +++ b/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv @@ -0,0 +1,2050 @@ +0,0,3244421341483603138,31,-5533455083687115210 +1,0,-4302098779834749733,31,-8203419927524778795 +2,0,-2998166160713018281,31,507397404195618438 +3,0,6864218090047839419,31,1269775222705156552 +4,0,6979084321315492338,31,521489941546056718 +5,0,-5731546056562700354,31,-3299076980719297215 +6,0,-6460328875922888956,31,4171050709207095650 +7,0,923809989133364073,31,7227603522734853918 +8,0,4187271766389786872,31,-5301042565225696800 +9,0,-1629980255024596516,31,-7159932106675064752 +10,0,-6095164084758671497,31,-4175816663463701391 +11,0,2086176710598203789,31,-6761944409688831033 +12,0,6543284205211650379,31,-843893195591887467 +13,0,-5213522776729965383,31,3979572172563082339 +14,0,5545158833176453687,31,772770378971129644 +15,0,6191585008302141506,31,-963862311259126228 +16,0,-8983023575487778597,31,3587791604302124252 +17,0,-6993173599622040792,31,2076895542453216941 +18,0,-679721864292929835,31,-5722060720739791841 +19,0,6982591615625134866,31,-4050276830296497920 +20,0,2917394212576059053,31,-3692044872667611406 +21,0,-6639923505334063205,31,-5319432348632548497 +22,0,-2362153139612899683,31,-8278394164558857917 +23,0,4776590923197089330,31,1023194414703686173 +24,0,-1506670496010913414,31,-3493548877255053983 +25,0,-2647877581130602390,31,6829941672577876816 +26,0,-3024194937172852654,31,-8312320242463069739 +27,0,-6786232254807398843,31,8190797407263589738 +28,0,29867523197922776,31,1420728128656359891 +29,0,-4755612273762186448,31,-3326172205076148158 +30,0,7027486771791057426,31,5695133811618937061 +31,0,5707990981978323197,31,3430937539769978114 +32,0,3829001002278603781,31,-3516050178394170004 +33,0,-1833995589090992552,31,1234490865231556981 +34,0,-2859822223207566521,31,-8246745462174281034 +35,0,-822061951152501107,31,-3972680658239560161 +36,0,6172313773566651166,31,9099799971213725213 +37,0,3002688263104272481,31,-2439481326761072651 +38,0,2442729726468942826,31,-2677629057871296958 +39,0,838920225343106725,31,8685334723429632740 +40,0,-3625228911788322244,31,-8929359814079381236 +41,0,-3085758516746786139,31,-7249381377840056881 +42,0,-8838726273629984649,31,6629553942391476922 +43,0,147628805604629229,31,2957226643021721326 +44,0,-8609901492927370359,31,-3159008985670450102 +45,0,2523698187551014389,31,8660816325420302264 +46,0,6168573373090741088,31,4362527098520480288 +47,0,-1129058501854041166,31,5308210199199235000 +48,0,6287935907341083849,31,-6065030674739287856 +49,0,7111303459234964792,31,-4348329041357656428 +50,0,2178159668141251214,31,-3191824473769741969 +51,0,3355500812482858732,31,5169714125298257226 +52,0,7998592630692471773,31,8783852237677570344 +53,0,-3657590562873574961,31,2686403390216854685 +54,0,-6707964006400412490,31,2147651307852907235 +55,0,5984672195388902266,31,-8935506008537235038 +56,0,-4866191761727097338,31,-4568272811605315196 +57,0,-3867761180105420740,31,1216333196858591413 +58,0,5010507633288345206,31,4082468630158014617 +59,0,-6360606695257557456,31,-523156484833635201 +60,0,891304432194930768,31,6787826732669804075 +61,0,891409307892263904,31,-2815509615985742169 +62,0,-4666213895286452910,31,-4203121557044252393 +63,0,-6150244752716240152,31,1186100021552495578 +64,0,7027844749552840021,31,-4419293748349054223 +65,0,7577525643630617296,31,-173608823319790396 +66,0,-2909908046638187264,31,-4757971792075824669 +67,0,1269898915928975170,31,-621173009548193812 +68,0,-1296685705337969741,31,7404994870726875928 +69,0,6880380907958913107,31,8022122270635543887 +70,0,-5157697080261523794,31,2629163514091181382 +71,0,-2384830554205610823,31,8662769687281704827 +72,0,7117698599495882683,31,3100902708800348122 +73,0,8436634904183317409,31,-2345197095639661592 +74,0,-8685705461888375606,31,-5028961354236812148 +75,0,-2099116977851507310,31,6467568559082788415 +76,0,7784639995868301609,31,-6181031626737133261 +77,0,620173983152449558,31,-307753931722270063 +78,0,7875300522364621790,31,3556961439924909813 +79,0,-8571663595578279581,31,-8389621138591282179 +80,0,-6074103631611676465,31,-7058093681471494152 +81,0,4991809556790719000,31,2509384633526040184 +82,0,7182703058112323703,31,9078600886331345263 +83,0,6700847687881865453,31,-3185248691016141521 +84,0,2471686449789799931,31,8135820527136508774 +85,0,5615843466129961201,31,2456824697138809549 +86,0,108638713672822205,31,-1942751044109736007 +87,0,3583360813653880832,31,-8010928155740878266 +88,0,4747956906537059928,31,-8671870730527540922 +89,0,5998273219519720430,31,-897534387981388320 +90,0,-8227785307205256168,31,864583456454288154 +91,0,-7813674951517583442,31,-1248195100475098486 +92,0,-6588167816065898573,31,719183630179720943 +93,0,-6862603585040654361,31,1555838595791027876 +94,0,5081695234398607736,31,7552709336841076171 +95,0,1329474798079286264,31,-4069243984810946365 +96,0,2849157965221752315,31,-5106208346864798776 +97,0,-1791866940674927372,31,-3732487830019247944 +98,0,4332646258279960296,31,-2928171148850270852 +99,0,4180229147886927001,31,7678912738217399551 +100,0,22042537110060316,31,5409363480551986672 +101,0,-2696513067094881964,31,-5971563702850598760 +102,0,4479930798836342597,31,5785449582446552596 +103,0,7717940613376663979,31,-2203945947046924346 +104,0,6494116526350833911,31,-336860089673290363 +105,0,-197304122858742249,31,-6527701172290027600 +106,0,-4396092174831810083,31,-1851536429846076067 +107,0,289832483284799872,31,-5929445730322992565 +108,0,-1407793616753546142,31,2076655891675244312 +109,0,8107749310172792421,31,1340917029021559245 +110,0,-634728965402563086,31,6904746464938270882 +111,0,-5703942985817925313,31,-4619995933235809362 +112,0,1530829577509875692,31,-7757862201581103658 +113,0,725468970373613536,31,-5719399085102497553 +114,0,-8861952843133984162,31,6837973960375655504 +115,0,2677458900969433422,31,-4312727922829720227 +116,0,3204987178703259401,31,-8250413142131780822 +117,0,-5308372023803773091,31,7917414079932405821 +118,0,-4001659458034098463,31,973637336050174677 +119,0,-4307920379982142578,31,-4879734947035462979 +120,0,-7679947731286800682,31,9097810362063308459 +121,0,893843933290517983,31,686069017784569610 +122,0,4059405294108459720,31,2655105452030827443 +123,0,1831062127804751133,31,6664944383347160949 +124,0,-2762239301578822450,31,-8889017933972170779 +125,0,6439416643289274311,31,-7464030884111178223 +126,0,7794216615102176353,31,-7853800719666907996 +127,0,1300299527667998511,31,-6540016843180327863 +128,0,-8807326403944725397,31,6876211214193030912 +129,0,-1407864491810865574,31,-2042564055962608839 +130,0,5562548832393267847,31,-4850187058929557398 +131,0,-1909668463603883104,31,-5360367497045581700 +132,0,-3001908439859224423,31,2904774259335895753 +133,0,-8229811775093055754,31,-7970195707567457413 +134,0,-2185505997709248158,31,-5160000343253106413 +135,0,8747474804119761845,31,3134670813914134761 +136,0,3375976894941005122,31,8281310502831371154 +137,0,-8687541524345519584,31,1308677402244402431 +138,0,7475418969225723061,31,7460295924884998763 +139,0,1090519453973870407,31,-2769999378098164961 +140,0,-8039787237657230770,31,-4849342777802260049 +141,0,1464043301476531850,31,8868071824430640969 +142,0,4392840094176543368,31,-45447787983155602 +143,0,-9069431037609626595,31,-2301402593333068528 +144,0,184117852034042369,31,2328346896049066267 +145,0,3048613549567428513,31,7105677258835935981 +146,0,8360545369892314479,31,5286157887504594494 +147,0,4218067793502522363,31,3896922439356172032 +148,0,-1984361661054820977,31,-7140553193022403729 +149,0,3359102789277797744,31,-930176860020193784 +150,0,7846237042486223698,31,-614716293409684803 +151,0,8441054814755521322,31,5017100963356620851 +152,0,-6067811722142115057,31,649491300978220970 +153,0,-7157356563671886865,31,-1381520503295015133 +154,0,-2021770978571166827,31,-7687684833674481512 +155,0,2181025843643822270,31,2525974521248141657 +156,0,-544448869202488473,31,2225384869360400785 +157,0,7057264048203590026,31,-8119036832602043175 +158,0,4363323697043225181,31,-1452404933768973376 +159,0,288118730444504008,31,-6518874907136494540 +160,0,6623265038156431800,31,805213364312365158 +161,0,-1346676098681766085,31,-1318490257981400293 +162,0,6693111459824679536,31,-6363711430342853191 +163,0,-5826625922074103454,31,3239465684755385318 +164,0,-3486949479332473670,31,-8863514623547620354 +165,0,-5491430220943863042,31,3301205786622278565 +166,0,-7571085429759204806,31,-2212140383228631726 +167,0,-5040253774339356206,31,-6512981086629224205 +168,0,3305212073815689334,31,1397826483455722109 +169,0,-4916812550925428252,31,-2970873946516171281 +170,0,3791981966901325707,31,-3037165059916424514 +171,0,-122684436810232675,31,4599424679135611254 +172,0,-4859495698099370447,31,-1149701235925933844 +173,0,-7070496757192133073,31,7142476727336605629 +174,0,-868377069569577871,31,3882189116695581237 +175,0,8419145116270703784,31,-1440392650472852744 +176,0,6800486273015600197,31,-6909070134135887940 +177,0,4633342516797787668,31,4877631182960420346 +178,0,-1661577990952520136,31,-4572544820948815026 +179,0,-334342790235531239,31,8723900010970881407 +180,0,-8872817819424402897,31,-6039782948415697515 +181,0,-409486044664079154,31,-7998590360374066141 +182,0,6190926389261136345,31,4529981069562833786 +183,0,-1300830024987992860,31,-4879205665460137022 +184,0,-3395638269793024332,31,-3733211822820055735 +185,0,-8493538135787539363,31,-8974943656224539915 +186,0,-6621335634487712846,31,2215980815441172453 +187,0,1973828869629126484,31,-2321240999578931231 +188,0,-8925429074145354136,31,3990242318311591052 +189,0,-2678123694384376779,31,-8634171043776214257 +190,0,-4225602364907809934,31,6039624635318480150 +191,0,-7257068922279808299,31,5458232790884838654 +192,0,-7485343360991292969,31,-277815482298415911 +193,0,2406538583069093177,31,1546028040239032718 +194,0,926637182534700777,31,-4542603540899015865 +195,0,4630670481086444853,31,2615344700339322073 +196,0,7851742083103622018,31,8719772374926713882 +197,0,-98392444236074312,31,-5869604328638297734 +198,0,1142322156420818107,31,-3727131822107135837 +199,0,7462750549553202851,31,-7940791964616039404 +200,0,-852719212082297085,31,6935296748590661692 +201,0,1478659643974205762,31,755506487059477811 +202,0,-6521398709638030532,31,-8571689273963009157 +203,0,1345928530210989700,31,9020710895470625700 +204,0,-3363927467796334767,31,-3825567184378523265 +205,0,-4501085897120438635,31,3998740932521315596 +206,0,-1855175868195079840,31,6030783624765099713 +207,0,-8957269249266743558,31,606295539274106256 +208,0,-5499424421497234822,31,-4746980620180965994 +209,0,6823468430111213664,31,-60347655229194739 +210,0,-8349332096263306503,31,-9126487474271840477 +211,0,-796191064979922279,31,2819062081782572034 +212,0,3070550474559678794,31,6255054127336038744 +213,0,-7237539936935226606,31,-348373694251915425 +214,0,-1467576285689886091,31,4130260746067342064 +215,0,8020665312084081577,31,-2461846819094123337 +216,0,6549665319606165521,31,5273099833944124111 +217,0,8265205303228562057,31,7061864447106090983 +218,0,2959656348340404166,31,-6084673952687987835 +219,0,3479620626361283295,31,166314797731924553 +220,0,-1809040706699436602,31,-5532387697540001238 +221,0,-6118995013506825485,31,1688990120809381159 +222,0,-3703429629123416796,31,807309237521899840 +223,0,5314878427138221245,31,-3723928503412105706 +224,0,-3374786619071663812,31,-4562440664316472191 +225,0,-6020893708387338112,31,4161064831135389278 +226,0,-2099692294850961452,31,1403342389950518795 +227,0,5628155794800251850,31,-4936605747695463374 +228,0,-4036147416511180551,31,9133015269908668778 +229,0,-7941600054572002747,31,8102438367634111521 +230,0,-7483400491927447614,31,-7625910297640800178 +231,0,-720567278261368781,31,-7034978195415097245 +232,0,3314031855271606298,31,-1289819241429766070 +233,0,-5471631794645557473,31,-6211487451142230073 +234,0,8887891228392664673,31,-6260099938343564463 +235,0,-7960828123610685614,31,-6180781980242752942 +236,0,-766265380117391950,31,2709017917912742689 +237,0,-4017904512890559451,31,-446536438139604056 +238,0,3478074185490226921,31,-6300306438633383672 +239,0,-7553920981498126005,31,8146191505237547188 +240,0,3988562325861820517,31,-4180690146509669261 +241,0,209643423615708418,31,-6630060899166563120 +242,0,-2464819451665246158,31,5701802706578519272 +243,0,-8631718977760664612,31,-1451868833412072734 +244,0,-4893221336143393409,31,28791537156541922 +245,0,2390264798730683615,31,1753899946993634685 +246,0,-8300749389255144164,31,-5770246008681600292 +247,0,-3549775289570958064,31,-6569792330272974563 +248,0,6514441262456966668,31,-2312183481153619810 +249,0,-7301663820335638615,31,-4474372557344010176 +250,0,4181559756778549411,31,-288664188543776993 +251,0,6215253578855337690,31,4157292030956060512 +252,0,-7323335092456459405,31,4339366647602131385 +253,0,-1860577032441476467,31,-8129223681346577956 +254,0,3644299936077808538,31,1827707375470566350 +255,0,-5161174126835724701,31,4741936162609739398 +256,0,-7779787747613135503,31,659849081488463204 +257,0,-3446338450597548406,31,-4674089452231623685 +258,0,-2662609220502962318,31,-471339711087374603 +259,0,208946340318274486,31,858879612229589753 +260,0,922869894074454969,31,4823900065599038052 +261,0,-8428909140908329623,31,-3186112797755767156 +262,0,-6875524699939418906,31,-7033823250704091392 +263,0,5154230294972327697,31,1793318047884091248 +264,0,-5868880138852165350,31,9042137922943752581 +265,0,-2697155020815738737,31,-5543723392764713874 +266,0,6278899766774254324,31,305518120012103009 +267,0,-6124877505863871039,31,-6984875796740866955 +268,0,6113186870348198684,31,2893813083082068970 +269,0,1328797232741421065,31,5777462930888060288 +270,0,8936960355443139766,31,-172166716142196137 +271,0,9069883653377839816,31,8947397080288277716 +272,0,-6698244186639407697,31,5315396488602438687 +273,0,6633988379507542818,31,5171364984832591024 +274,0,4243888593320380368,31,-5708793133033249357 +275,0,1299920470993756698,31,-3080180092837850693 +276,0,2315187937474071861,31,-5770231742149855240 +277,0,806120923801759332,31,8631414337626806664 +278,0,-8537792935927015380,31,-6005983427738005837 +279,0,-751623313460664870,31,-3312486898052481598 +280,0,2455098182130434513,31,240107566166488173 +281,0,-3041072155357054618,31,-5106213676116682572 +282,0,-5209258140949481980,31,-4669607120945866099 +283,0,-7784651030341623624,31,-3350343569599416746 +284,0,-8624281235662545565,31,8210079972479885552 +285,0,-5185374153462168974,31,5202468168578868297 +286,0,-8728622305551122108,31,2255714269623975580 +287,0,3633316488676598179,31,6019173254708496960 +288,0,2341850275669250720,31,-4533960333243154029 +289,0,8998800880957295269,31,3248225868458550898 +290,0,-2791108801739767859,31,6298101125646037253 +291,0,4207716787796156879,31,-5271870580745433388 +292,0,-4083554261407892809,31,2544058002418457630 +293,0,2977762250156739855,31,-1132687177413904555 +294,0,-6066243213313847782,31,-4675724604453303528 +295,0,-3134677742513834402,31,6883393155162284905 +296,0,-5231660756514911289,31,6019308974044084931 +297,0,-7916346081138370244,31,-6775742645940432433 +298,0,9105509708951212631,31,-8023852616513616736 +299,0,-3071680532260795719,31,-5801691201944870647 +300,0,-3152428524199455707,31,-6687339325423137821 +301,0,-5276930195233923125,31,4008544757736713036 +302,0,1981446637702558747,31,-4423651580038079645 +303,0,-8822786060285469479,31,5350780306827231126 +304,0,-3086453182842996354,31,4849599622427744016 +305,0,-7521798164704108718,31,5780470260112942571 +306,0,-7460429880600038351,31,8324992171521699647 +307,0,-5031515429775225415,31,-3683281598645275706 +308,0,5662627828449328757,31,6708077785307686927 +309,0,2804157867790593789,31,2074469194687769402 +310,0,-6183934836359652529,31,7402814355296646057 +311,0,2425310972806241292,31,3239411911495370728 +312,0,-7877162957672040682,31,-2776394963240803743 +313,0,-4575453773921540745,31,7693103463076295958 +314,0,-6152892230011262930,31,-4070014557606459932 +315,0,-1554429781063399588,31,-1374817506481049787 +316,0,6395550633581619922,31,-2267963186283828175 +317,0,948199150697514149,31,5559057279217848998 +318,0,4123518706442132507,31,3101415343514899481 +319,0,-8620024481834864148,31,-4433121313509072498 +320,0,-4627311960537433998,31,517439659500632978 +321,0,-1517263476517287336,31,-6491565857317339567 +322,0,3087156144310177979,31,5715607033075643105 +323,0,802387854806242344,31,-3225788534423856976 +324,0,-8223164854162179626,31,-1037002493552637863 +325,0,-8876883825341271093,31,8154902907479918190 +326,0,6189924694943538938,31,-6193469594792766267 +327,0,-558048344469199000,31,-1851948476887841851 +328,0,-6388815497071843014,31,-2250515670046861913 +329,0,7970082794223216108,31,-7788270616703110317 +330,0,8943146030443257086,31,7285987639624185226 +331,0,1919558538884824162,31,-5209493496595938331 +332,0,-5413821296846136841,31,922111738342633701 +333,0,8482255996292420949,31,-20080433893715352 +334,0,-2059351044571046226,31,-1819351668237479549 +335,0,8122315934009425936,31,2515316881718676721 +336,0,-6002133579485340781,31,-5892091485638114400 +337,0,6439465961707132723,31,8623072985837685369 +338,0,2763117897158909339,31,-8597988554777179271 +339,0,4241846593057682886,31,-8694141641226629381 +340,0,-3156374353704014890,31,-8045593149371615435 +341,0,3611310604513156987,31,7914734216431138327 +342,0,2539868227324188707,31,-2774234374369581189 +343,0,-3160603853021599046,31,-9111138413434820446 +344,0,-6694565052629228305,31,-2005569495485903556 +345,0,-2829087677596299075,31,8579269599548458262 +346,0,-3855421753196086451,31,8203540394153576917 +347,0,8353874633819013271,31,-4148211639534829810 +348,0,-2485914493713180581,31,-532827645219215410 +349,0,2924901647540244351,31,-6021006842144370040 +350,0,140830235769158231,31,-2400657722589790306 +351,0,8924525771772034372,31,5026588309495674683 +352,0,1991645829771754924,31,1123139069474960330 +353,0,-6409133430531739321,31,96195016936805772 +354,0,-2477349252564343349,31,-7165593464286467935 +355,0,7592298137540200578,31,2551937620311073339 +356,0,-8706120837264950112,31,-5410291386671070917 +357,0,2330049856518978017,31,48628557510442688 +358,0,-1333715564956417750,31,-273796261995820486 +359,0,5321303278236129003,31,-6209019196781344256 +360,0,1316603583801631000,31,-948980824969743617 +361,0,-2052093890021786856,31,712954873209509757 +362,0,-2212919092132307727,31,-3601451985598435977 +363,0,-1138248150179747101,31,4248885629056062772 +364,0,-7297574785915472699,31,-7392526091572022522 +365,0,3159392081609537393,31,-3922955551538541546 +366,0,5438969032594710113,31,5981915887707058814 +367,0,-1117946266762888661,31,-4334129985302488638 +368,0,-3513962250060316650,31,-6097796249812915489 +369,0,-95470470775096400,31,155523270410792049 +370,0,-928547845419412355,31,-4139020688702242746 +371,0,3064209748165139149,31,4124716127369098509 +372,0,5570740544374382296,31,8106153642629024388 +373,0,-4848606292970499536,31,3137204277056582572 +374,0,1249733847255258336,31,7933277786128302144 +375,0,-9081876379081045111,31,-3908453161017593360 +376,0,-3178350430540128617,31,6392681530041927308 +377,0,4580722282117591455,31,6278102992300382789 +378,0,4910338723691444614,31,-8683164093455711308 +379,0,-3861107435455294057,31,2996323143637941464 +380,0,2455351552393139588,31,-3787976329703411258 +381,0,-3098045343671378301,31,-5264078604238422868 +382,0,1276702104227748441,31,-3055625120914711722 +383,0,-8725606894849543465,31,-7845869971152576526 +384,0,-7043526197674754455,31,-8403173606096126916 +385,0,2543751490914779898,31,-3461755608988395016 +386,0,1111188191726666289,31,-6064530627277518927 +387,0,3299681536744686092,31,-7669585585178028158 +388,0,-4968407975804173061,31,6626264254699346423 +389,0,-8443232222924958642,31,5579786204933264505 +390,0,2692856020311995538,31,7123123681332590327 +391,0,-7295992543900831720,31,3920160947618201625 +392,0,-835426980056055153,31,-9018654113195804750 +393,0,-7189216512060259212,31,-5233231186080297929 +394,0,1546667140862204220,31,1514017214552004646 +395,0,-5157738526808785307,31,3284473228690089349 +396,0,-8400112152363165211,31,185466868331298469 +397,0,-2562446629278342489,31,-5743191757689673501 +398,0,-3984312152746163924,31,4052666217658668117 +399,0,263973571859894620,31,-7447333179307179356 +400,0,5863738959863392730,31,-5665516982294012514 +401,0,-3750469576779228200,31,-5058737198419256056 +402,0,2859093520615066384,31,723291883271503873 +403,0,239574671716835044,31,8763036368773881264 +404,0,1758244848125395099,31,8112855082354342961 +405,0,4692926060224877180,31,-5747837508451518317 +406,0,2328985435627410056,31,-5467461460192012566 +407,0,-712944964417726519,31,-5473532943404445513 +408,0,7575628018175957835,31,-4740188144615380716 +409,0,-6461647485226712981,31,8261455183700464506 +410,0,-9175844658802936237,31,-3537869168345143484 +411,0,-1791894645853433273,31,-1136172264923808410 +412,0,-3209291319104719345,31,4457952568913887766 +413,0,8435774909159574457,31,4718554572147412417 +414,0,3068904622159492539,31,2072301105206975642 +415,0,6405574310234631665,31,5421523368426574999 +416,0,-7236310029621050895,31,4289035122198650062 +417,0,1939741827857698370,31,-181223286162322245 +418,0,-2711876483320863546,31,4172725799759953558 +419,0,-5191337944005182792,31,7170771980419642636 +420,0,851301927202074099,31,5930270300351755850 +421,0,7817558216393575797,31,95596503464339104 +422,0,-924173671401578135,31,2285760792899038571 +423,0,-8870424728276452684,31,7420373124417904568 +424,0,-5612135981154918473,31,3158516732653198415 +425,0,5352840780989627332,31,-6068991971774450932 +426,0,3115501649750915797,31,-6708503790450831440 +427,0,-7282764488136203731,31,6533293543509437462 +428,0,-4410122159075968274,31,-6334815267988844414 +429,0,-5112841868993719465,31,4777181169596726 +430,0,1606611627835962209,31,7749134781338749151 +431,0,-2564625118517656156,31,2353082092656708691 +432,0,-7347999176364584697,31,-1293807815914928397 +433,0,-7520586016175454443,31,89550026706270865 +434,0,-3582872246453049220,31,-4674612563068915780 +435,0,-7208670274224679141,31,1423087795654451035 +436,0,1407185043226639926,31,7842714321030400466 +437,0,5548472899324259498,31,9081185597309034470 +438,0,-3424704481698318306,31,-6731284234870559431 +439,0,-8898045228081312865,31,-5740440599147555360 +440,0,-5032961205984329240,31,2928223460257055445 +441,0,2319704565344125424,31,-4573210339714330827 +442,0,-1858090959206557106,31,-1277759614770492259 +443,0,-1847512527385111193,31,-8759478398143393529 +444,0,-218817722784924760,31,8935997385782664222 +445,0,-4644538017574761086,31,-320958622128485654 +446,0,527762499588866419,31,29891086076798005 +447,0,7682925460546142196,31,-5149940832874622923 +448,0,2618673582975102782,31,6434999602916810035 +449,0,-8339358073633623035,31,9041009245957302157 +450,0,4632344075623474881,31,-6112973450582946282 +451,0,-2634725682046056737,31,-1637930574215261658 +452,0,3264353773883015103,31,4388632294695556199 +453,0,3450256920483368564,31,3898221322270193025 +454,0,-8453373497678191816,31,851697481826376177 +455,0,4324811352547234228,31,277341313735917491 +456,0,5231611966727557421,31,2633476166140752744 +457,0,3935063678731059941,31,-8617532786207807041 +458,0,6338309551930394802,31,8017773574705634479 +459,0,6622686033142507173,31,4909830274457464693 +460,0,-5278373537512798709,31,-2791433303098363080 +461,0,-9063940204441257539,31,-4945859737524610944 +462,0,-6333833756325058415,31,2025843912481509435 +463,0,3799491381076234981,31,-1483043896957683255 +464,0,5050905817684546674,31,2537650526541797986 +465,0,-796624655126841621,31,5624764882795280871 +466,0,8334872366472578300,31,-3997025771846541914 +467,0,-5288752267258476166,31,7644921161382415630 +468,0,4335956913966038392,31,-8243259903711952009 +469,0,-2247074774901543705,31,-8285592092433100497 +470,0,8474035569080943503,31,-9123206849355802204 +471,0,-3170167932314701995,31,-8391371140886831976 +472,0,6999756768956410897,31,2601182322169988973 +473,0,-4451078577344071588,31,6731587110290059761 +474,0,-8433054951584831409,31,-310083986210506918 +475,0,-2640652121643463448,31,-7663265376044393354 +476,0,-7045594934288710931,31,-3540606019121825610 +477,0,-4036935141669708886,31,4633371185196070637 +478,0,-7734407512972194081,31,-3626004247719480800 +479,0,2053541054148333962,31,2718393641867442801 +480,0,-566653752431971002,31,9130412631138122915 +481,0,1898804146829115409,31,-1320164234689695137 +482,0,8507984725723339263,31,-868564257842760668 +483,0,-3742788731083462619,31,-1026075019287350605 +484,0,-614166854038590657,31,-3992494720724620357 +485,0,8147682807535759575,31,1869343973443874489 +486,0,2813322236228401990,31,4841064740360285018 +487,0,-7697111451322995338,31,-6379231448333518386 +488,0,8023578719528819358,31,6745503877598037648 +489,0,-1666048881205334172,31,-5256246541444134630 +490,0,2861705383918865808,31,-6096421255289505098 +491,0,-2067264870309406817,31,1081657611234086601 +492,0,1544932780962992751,31,-507619730665765774 +493,0,5752963315823730718,31,-591201474865907404 +494,0,5563418456763501584,31,4354726250317963066 +495,0,-956763705026909993,31,961821220093665230 +496,0,-6723021793890249884,31,-588968225227245527 +497,0,8199491799885937348,31,5473869347877072977 +498,0,8254326245904567972,31,4887628237292388865 +499,0,696534455436688862,31,-6632466211595998459 +500,0,-4526166123204455007,31,-2158781430527542758 +501,0,-1244479971115743946,31,1470692072796260725 +502,0,-4712028527008594695,31,-5880972975620601089 +503,0,3845317619056596538,31,-8977270330924335718 +504,0,1397508695414938292,31,5369189888528787177 +505,0,5199778266100306999,31,1395045740269106965 +506,0,7649610185133409821,31,-6626038639423519246 +507,0,-7736979936936405855,31,7248478658655595748 +508,0,-1871499676764587199,31,-7583770806479473862 +509,0,4089210433244498057,31,5560753314727485355 +510,0,-5319342193649020117,31,-6786052382262917719 +511,0,6510328602034064204,31,6734185512492271438 +512,0,1177990759783856649,31,4867234317275339635 +513,0,-6211536889696831922,31,5588493526303969783 +514,0,-2806444732697667079,31,3385240408828417595 +515,0,-5534324430749159010,31,-8248239965109122940 +516,0,-6189402282341917673,31,7992994296340619329 +517,0,6327177260956086170,31,-6604510753943290447 +518,0,-8199327532062722025,31,-4953705018661094285 +519,0,1757637089703623521,31,4226419900260225770 +520,0,-1083020196125888231,31,-1461440847604073327 +521,0,-4027554827881183115,31,1113252302192415291 +522,0,2536452110533397141,31,6327324158304334778 +523,0,-5283309880767903892,31,-9100358157866131671 +524,0,-8726185014741079280,31,-3730398572853717826 +525,0,5870565960746070417,31,2452185736584987221 +526,0,-5981985584772708231,31,8593579823893106821 +527,0,-1932877698882443840,31,3627022586357508512 +528,0,-1002343255004640521,31,1691115630615953203 +529,0,4369245457815499473,31,-2704650708478260494 +530,0,574307157338267836,31,267736055877217543 +531,0,-9022123090729501652,31,-7074578763681993584 +532,0,289683520338718123,31,8024791884142845258 +533,0,-5791631171477648402,31,-3366362538803282577 +534,0,-7088072188409060385,31,-7870960328028909705 +535,0,-4659987534525277948,31,-4674974712598879558 +536,0,-6573587402478059370,31,4399474469003104034 +537,0,-9147189283662432041,31,2058864807899134103 +538,0,-4621406226758810332,31,2889894455781585349 +539,0,3827992897413425855,31,7489443102791058792 +540,0,8237187128340177815,31,6503491198040788271 +541,0,-2575127860924571660,31,-8939934198472954375 +542,0,-5807831166865245102,31,8450900971245869022 +543,0,-5362714198312494492,31,689927801702729240 +544,0,4800564949032048849,31,7101644839874884365 +545,0,6232971559544384156,31,8423596116537464748 +546,0,5346264270546834545,31,4714781792280690158 +547,0,4418021854956695145,31,4062353976771359690 +548,0,-2503709442294180811,31,-772384937613336008 +549,0,-6705525727229877941,31,-1062335677339366613 +550,0,2807916716409994404,31,499846210406889339 +551,0,-140901784876025870,31,-1413369757116780058 +552,0,8341454749980902529,31,-3204423776573875122 +553,0,-1877846120130857988,31,3137378379258502568 +554,0,-5151008775080326365,31,-4233767706071281637 +555,0,4141948371168606708,31,-7067077945950405115 +556,0,-2991396496641036974,31,-9018372652475149438 +557,0,-8231846204849830109,31,-2195920631996819514 +558,0,8817247101288954387,31,-8363775066342741534 +559,0,8987037987198023072,31,4272172218859102843 +560,0,-3653961272252403667,31,2312280819506635210 +561,0,-5540876112254432380,31,-2872263810614578316 +562,0,6630760576601451124,31,8494181677612570171 +563,0,3952853764187760519,31,2721287669408405552 +564,0,-2752207231177565438,31,-2411739265332339617 +565,0,-8990910782429153994,31,-4439039606918846593 +566,0,275029084438740989,31,-344516756026755639 +567,0,4377008995333363792,31,6605003074466558993 +568,0,7821963094129670639,31,6361729924240900759 +569,0,5910345261804604591,31,-3360905706066488613 +570,0,-4676534586425310858,31,-3844193724875374902 +571,0,-893427896035022872,31,7693093957216519232 +572,0,-5107326322974521170,31,-3650813192138079157 +573,0,5928147272454832468,31,4211102623224287282 +574,0,-6838714257802993131,31,5245464678556168612 +575,0,3828181535474040080,31,-5767711028535640487 +576,0,108432455104664877,31,3792771207311601057 +577,0,6134860905554719891,31,-3670383854569635973 +578,0,-9006906057728028416,31,-4079021968473785061 +579,0,-8785087250130628623,31,-6017900966427842596 +580,0,5107258923997586783,31,8983826538332698061 +581,0,-4184502077870950738,31,-4860355966945867312 +582,0,-4196994343382319067,31,5368983906266526541 +583,0,-3602525630290645804,31,7900579519151208806 +584,0,-721602986806918388,31,4827592009155509216 +585,0,-685749048932716724,31,8234201947875022833 +586,0,-2226124441764103982,31,5251192020729884318 +587,0,-8444470437189672337,31,-5482747959748058913 +588,0,5967905323104782609,31,-4327471041820647242 +589,0,-774529365691330376,31,4790133046864863459 +590,0,5317411683068394421,31,7190937723842443634 +591,0,8753729036148149823,31,2296709299698668279 +592,0,-2600284926580864832,31,760729606203150875 +593,0,1501264369203023713,31,-6843207807744510583 +594,0,-5589106565383836539,31,7397428727978062977 +595,0,2671769607792597675,31,-7658367888460014319 +596,0,-571916257780128106,31,-6916934903720355206 +597,0,-466398102722097434,31,-177526284959880475 +598,0,-8668321984643614166,31,162578756884980834 +599,0,7631202114905008803,31,-5237269352333783437 +600,0,-8647922451448787023,31,-7380353753081271375 +601,0,8025381490498356948,31,4908827198072522217 +602,0,6049280950696679244,31,4534476971796610133 +603,0,-7696482417187458362,31,-6116514322720974887 +604,0,7140438358861456746,31,-6127632829076058168 +605,0,-4921885565559803566,31,-3352339589344262455 +606,0,-7027307783313071980,31,909980735562222073 +607,0,4879598629629415952,31,-4741787610664876709 +608,0,-7342155744245645378,31,7135001494663066561 +609,0,-2263378697656156016,31,7717511775816782642 +610,0,3707257119850556629,31,-533496375853155501 +611,0,2267112971575522392,31,4739985595418369176 +612,0,4213162373130191016,31,-721891521335144011 +613,0,8934898250536865564,31,-8915885795574444760 +614,0,-2149765792894599153,31,6491531051981059094 +615,0,-5375160376931751557,31,-6474458471369515946 +616,0,2196544121130659101,31,-2102186857259317304 +617,0,1698916734136113996,31,3191397003786932497 +618,0,3433172695894846834,31,1868172568944785858 +619,0,-2849259564218003615,31,2536981603701846335 +620,0,3254138956861413927,31,-2176931262925080332 +621,0,1285929622626453198,31,-789348407345628852 +622,0,-2349127797610817522,31,-1834334320173105364 +623,0,-1191286947825336074,31,6139851265778586731 +624,0,-9055971338481310193,31,-1742567209936713783 +625,0,-3525928115330914396,31,619568578224077671 +626,0,-3227633136719463166,31,-9202068314002964892 +627,0,-133501853014392460,31,2838929404808587798 +628,0,1099153576792978915,31,4215769867896413613 +629,0,-648473507797745243,31,-4923889798069829437 +630,0,-8947946509829984393,31,2801827781325068376 +631,0,-183277647411867477,31,-7325943137447885015 +632,0,-8972836557830117056,31,-733235480662214110 +633,0,7599024178448012477,31,-2176026002847345932 +634,0,-4558685557381095142,31,-4883882808933946877 +635,0,4767843848744584145,31,1252698248302364335 +636,0,-1522308275842184404,31,-6680610680071233200 +637,0,-8584574042672861403,31,-2238316672250712269 +638,0,-1734332735592240813,31,-8669035079915286630 +639,0,-5832090116698921823,31,-3927512435379658765 +640,0,-8717779938268738600,31,-3856099312908886193 +641,0,-1881355893097809021,31,3625835721912199557 +642,0,7715529933819950784,31,5727752944981454042 +643,0,-2289162375063823266,31,-3597266369183424286 +644,0,5628801095532857454,31,-1214817661599162401 +645,0,4961594313236250573,31,-1087136692153496161 +646,0,4618832900030681591,31,-3525402740276291700 +647,0,-2860026598356511432,31,-3455533093901741410 +648,0,1961029532371905567,31,-7361723750588002876 +649,0,-7427116119564073711,31,-1827505840155963915 +650,0,-7663272674507523073,31,-8045716843806203631 +651,0,-1432342159197328837,31,-3072008746538135968 +652,0,-6656742466964663442,31,-3597767361721334594 +653,0,1884610673731472834,31,8707351858126404146 +654,0,-3810094228658892044,31,7845377612704049361 +655,0,-6616291605664442115,31,-5468263490302906858 +656,0,-6089433736056798518,31,7670258041749713517 +657,0,-7473225570871869756,31,3126941406091656110 +658,0,-2962461410122376636,31,-4724154794394598573 +659,0,-7732736326487208707,31,-5966244421511703898 +660,0,-4443012182604465346,31,-2289586784965462105 +661,0,-6157220788020380465,31,5340066001730013657 +662,0,4600227015044805999,31,-2389390686206075541 +663,0,4469639125734518912,31,-2274885390374612385 +664,0,-7792518910888390519,31,3658037123203222397 +665,0,1994555386333163764,31,-1289029557200166081 +666,0,4369373061497876631,31,-1734692833643974821 +667,0,-4738249058452865067,31,6628928410189741847 +668,0,-5995135073617675417,31,-5268233306733196623 +669,0,8575145712582277328,31,7233958521060208486 +670,0,-3326852669647946366,31,3158263057140253099 +671,0,-2007891227481667403,31,8048091231885825613 +672,0,7761466597038557448,31,-9141095127672150117 +673,0,-7224144129768088459,31,-1515144578207119710 +674,0,-6066361559768252258,31,6154476292135896897 +675,0,-4068105427650671702,31,-8161346520065804688 +676,0,-5560889521429203904,31,2436183198670024333 +677,0,-4762527649365520713,31,-5301257709575933017 +678,0,2694767757294725688,31,6307149899268802390 +679,0,-98412761475871782,31,2674617490882665119 +680,0,-1686751510820366009,31,4523222379407211862 +681,0,-8638747288926132295,31,8543193335140594814 +682,0,-3606421426295459375,31,-3352476826306841581 +683,0,703911580424568845,31,3756684942085849634 +684,0,3806874684410471199,31,-1896083802123955649 +685,0,-5118211203482914183,31,-7491110214805776810 +686,0,3783835693585708905,31,-9179347615507445225 +687,0,-4147496567901501893,31,-8956586685911416967 +688,0,4328139758484363106,31,-6098262698836987698 +689,0,3028068134370267202,31,3140182098325454699 +690,0,-5966389813687232408,31,7552078852600793931 +691,0,2195469898148267913,31,2156878055366859281 +692,0,-3080166474377317430,31,3360972131466746238 +693,0,6412533502918649688,31,-2809425401964999029 +694,0,-4801061500654703956,31,-1703214441352786830 +695,0,-554194900129906123,31,8403510435372475664 +696,0,1486000469436139740,31,-9140445052996452349 +697,0,-6971589411333019409,31,649956163089346485 +698,0,2647463349908157318,31,-961680615397158052 +699,0,-6754094203714628854,31,-3537644177622593114 +700,0,2314399046579224435,31,3595826630510184694 +701,0,-6177383374280917075,31,-250960113345455325 +702,0,-5619632493646738964,31,-7611364126409268643 +703,0,-7301831206207675015,31,-3994065631758830822 +704,0,-5527516975398904813,31,7889570084988767803 +705,0,-7206298956882517419,31,-4455174009381679936 +706,0,-1535337994919517848,31,3431565382723421880 +707,0,725107219148423471,31,-2676844644434251354 +708,0,1938195538047669437,31,-8036877000036558576 +709,0,1028829726878266547,31,5948763491492046877 +710,0,3981352596771855719,31,-6412302299728604826 +711,0,4637441575637536278,31,4091543707108512735 +712,0,-567364300216533096,31,-424888970457666562 +713,0,4215820779392244698,31,-775341554992733187 +714,0,5791138156269639416,31,4202135502812675428 +715,0,527001488112788484,31,-310309839249908517 +716,0,-4390338125863921979,31,2395595708926579743 +717,0,5557055272452535368,31,-4145819974190545347 +718,0,-205316410586789577,31,-6064372937843756170 +719,0,6952133288635206796,31,2288062064402174385 +720,0,-7457518070084443694,31,1455415991817577798 +721,0,2002018537802900078,31,-6886504427135626139 +722,0,1561023860546606398,31,-8641516814337776651 +723,0,3006183850758749007,31,-5333685348707189945 +724,0,-1361037422909233361,31,5089797214803521044 +725,0,-4203933835330884180,31,2118846105116955484 +726,0,7500988945823273736,31,-6030791920928942766 +727,0,-3010872765453549672,31,-895350837644601051 +728,0,-3781827987408697259,31,-8555400277222601251 +729,0,7460277383018710734,31,-3859365297608817085 +730,0,5250710645655626569,31,3964167510807900068 +731,0,1109553850343924028,31,-66110948226606998 +732,0,-6498085059809326090,31,8224583195011294327 +733,0,-5879222670885240061,31,-5073393894807639927 +734,0,6210613100795379620,31,4896582440985512942 +735,0,-5759675374559290972,31,2833305183677290270 +736,0,2824738880545011656,31,8899053738701393399 +737,0,3213468672819532759,31,-3688971267577439358 +738,0,514328750496380347,31,-5295958024936044038 +739,0,4470285007717204101,31,6565904636068768883 +740,0,2269240343629252129,31,-1941271840664439450 +741,0,8714859525098129755,31,-7423427504399954018 +742,0,-6932578361476642118,31,-3420384832120161015 +743,0,3219949239213817308,31,8561552405036982957 +744,0,-974585298959970878,31,-3093831236298237571 +745,0,6482527911604968876,31,-3132234695333765983 +746,0,889153561428168470,31,4232221327517072659 +747,0,-8207616222981108363,31,-6527684347153200097 +748,0,2386860797138412452,31,5729425614259392138 +749,0,-6749686321997906685,31,1311996795539597801 +750,0,-1105424552884318985,31,-2469083191424331542 +751,0,-3137963539903752699,31,7342413364893138914 +752,0,-5296550634024189868,31,-9048094556514976834 +753,0,2919221292190747486,31,-8386087031942172274 +754,0,-3991521756182858814,31,-518995324886271971 +755,0,3802413126716557908,31,-402314233012974265 +756,0,4556158013211621930,31,-2939676369660500973 +757,0,-1956520472596138305,31,2835732916803925978 +758,0,-1667618395239727751,31,-2270929196964072279 +759,0,-4948155010712448139,31,2726743797660617646 +760,0,-2667546434479018044,31,-5564226003270834118 +761,0,-5192951416537530780,31,-3807188288204402395 +762,0,4474564860866849514,31,-582444666045744556 +763,0,6795504197096101870,31,-2291686899101840046 +764,0,348555520492747776,31,-7956157182374000211 +765,0,-9152654684800879935,31,-8101480221143743278 +766,0,-139520144005307559,31,-2190765246330659421 +767,0,8655115078308054377,31,-6911004608154436374 +768,0,4640578432082008138,31,468733779829389133 +769,0,8526214307008571064,31,7262922641802820501 +770,0,-7079091919397494753,31,-778917758771509989 +771,0,-4852301075482608956,31,-4124462486053911465 +772,0,-6726381834527599283,31,-5993460797326519933 +773,0,-467175742480032731,31,-856369839081680215 +774,0,5092513639393893997,31,7303185603640871814 +775,0,-916781769295487406,31,4530826094386641964 +776,0,-3306005301217276910,31,8539363786544310723 +777,0,5711239369216246603,31,6722595935708959027 +778,0,7411369067342514714,31,184238637656098552 +779,0,-137089609471843551,31,-4035502579108601733 +780,0,2197853544547148264,31,2450645162535157134 +781,0,6994895994975015585,31,7011268932372780582 +782,0,-3993584670641567357,31,8903350539126690941 +783,0,7324113989979846776,31,-3111058306071968112 +784,0,4848201612974985071,31,-534830764061929340 +785,0,-2319141888027790806,31,594631992895413372 +786,0,-7727572350242351429,31,-2846371309241060379 +787,0,3611228677421118756,31,-470913032330306120 +788,0,3254031939911056022,31,-4823628212648635425 +789,0,1315862663037871882,31,-6267005765984706956 +790,0,2762719496333050774,31,259152660320498902 +791,0,2441476684596910583,31,8257396568680067698 +792,0,-1751985778109806355,31,-8592208455417313232 +793,0,3156518557955714028,31,8964137245153690621 +794,0,-7474525109128332157,31,6065778298533352476 +795,0,-402634945481420093,31,2024465509977480707 +796,0,3711042493776857096,31,-8367793676028455828 +797,0,-526618219268616930,31,-4804240488155025153 +798,0,-8956423818433397438,31,5008880979452871479 +799,0,3318951429850234648,31,8573302284896377218 +800,0,-4065748355754556535,31,-65384473517974962 +801,0,-2974465318794034149,31,-3462799275588800778 +802,0,9156201933336414671,31,-6966694879318916218 +803,0,-1224004278953882958,31,-8045692128698710136 +804,0,-5567810197150710613,31,-1207380474866255891 +805,0,7645667176564158039,31,-7906411557756745808 +806,0,7437954892140634061,31,80889103239840424 +807,0,8595047667824297631,31,-8597711749342191173 +808,0,-4227841629446459104,31,-4575775586328108150 +809,0,-4073313779073810355,31,-316563575979278474 +810,0,764623093768368301,31,-3132045223722383431 +811,0,4502563456929761688,31,2187718346368394428 +812,0,1027370723462817766,31,2381256311788207489 +813,0,7668869338814612684,31,7928117590498404008 +814,0,-4780350365503382825,31,-5159704665692864327 +815,0,-6389061999435806787,31,9048060284369073027 +816,0,-2133237830821026919,31,-349058486193318579 +817,0,-618977682776693149,31,-3431989804262478479 +818,0,467656057704319257,31,-7740443208125609989 +819,0,-6754479852919060751,31,1797645757313505102 +820,0,-121796624546305099,31,8958092859473404932 +821,0,-6164861615484187016,31,-6643235250090200979 +822,0,-8568598162483564153,31,549706993043844227 +823,0,-8182644091745100549,31,4901824862476801010 +824,0,-3989631051916738549,31,-8100533073502498765 +825,0,-3812515520109109155,31,-1298984003898158708 +826,0,5458479505950940580,31,-6048625806832997511 +827,0,-4068063356781230185,31,-9119915523323993594 +828,0,-2830766632873229698,31,4459397615404347803 +829,0,-7592354330098913572,31,-4909437909508748542 +830,0,5323147076973602219,31,4919397963797335225 +831,0,462800867816435413,31,-5975527719643942059 +832,0,4002154584204048905,31,-4407033405659710749 +833,0,-803837213195276249,31,-7178440868711067132 +834,0,270846859760410932,31,-50670456992774841 +835,0,339186719055655409,31,6317599652673076910 +836,0,-1681073433226249949,31,-8583393410371016431 +837,0,-3172364168133842187,31,58345887483905125 +838,0,4471576722877991666,31,-6364894895964314108 +839,0,5796602822306813285,31,556294380130548532 +840,0,-7918394505018135767,31,-3778541858117972313 +841,0,-8099706435104488972,31,-7945336403745013268 +842,0,3225305587851029418,31,6631468425755659374 +843,0,-4366886220054887809,31,2572975570110837761 +844,0,7732358946751522729,31,4925230621434492091 +845,0,-228816160482375387,31,-7531687796450770915 +846,0,-6429545033940023762,31,401979517178258648 +847,0,-4874531170284168803,31,-6815183807912405713 +848,0,-7919754354938613725,31,5857051289455258724 +849,0,4818550076091948962,31,-6863264564396788066 +850,0,3907701057522316102,31,-165206991583379078 +851,0,-2162109673539899314,31,-8197004974667352540 +852,0,-6296577330837677905,31,4259707277805789564 +853,0,-5038523314786213767,31,6886715378844825401 +854,0,-4182256071671167089,31,-4321349813819824659 +855,0,2347804671767305901,31,-6316799377488363677 +856,0,8781747195783722684,31,6385422203678615860 +857,0,5464112250608435856,31,7481197518903749079 +858,0,270499223000052613,31,-3552901802171712300 +859,0,5387476652934255975,31,-2687266518605571648 +860,0,-2665753069813354951,31,2291502179088251556 +861,0,-6640316903187366435,31,-4307827578942702253 +862,0,5182130073111288069,31,-4976300209201100462 +863,0,3324630100168604545,31,8507538303864334011 +864,0,6092224834024861844,31,-6282732092789453635 +865,0,-7314979478990434840,31,-5079068772006646592 +866,0,2475323565628074124,31,-6267865896023378376 +867,0,3744881942029260381,31,-4713787033580918922 +868,0,-4468245448047387416,31,-7013732629761055639 +869,0,-2514532843437356755,31,3920327548466943214 +870,0,-8460931029051770120,31,-8173476098702646660 +871,0,6058982121000846509,31,1705476080088938640 +872,0,-5771467892492359246,31,-8836303807829881954 +873,0,4284427580292476574,31,891105533594491800 +874,0,-4502826197302040607,31,-6489978660682625586 +875,0,-8909965133023702444,31,2474318734336012736 +876,0,-5152825667036557377,31,6341824132370198826 +877,0,-9001319942906464381,31,7098583396698746318 +878,0,8783326653870239059,31,-7130318207488700284 +879,0,7169538748654303504,31,8958636857947569253 +880,0,-7206711339673245443,31,6615213928803137015 +881,0,-959892259265562431,31,553208085362759182 +882,0,-1673323329893911437,31,-91434838388933868 +883,0,-5827914418805049723,31,4159906415104460753 +884,0,-820830695253715046,31,-3047986477497506760 +885,0,-5782181341435499931,31,7244611226388001554 +886,0,2663734005752892035,31,6535965224905857160 +887,0,6987511185271585413,31,8619188796658080916 +888,0,1292089443730939651,31,1849493830859390059 +889,0,5587170596809636807,31,541893901025933909 +890,0,8237809229146017083,31,6993890077302282948 +891,0,-2235781308356196513,31,5032842915893541728 +892,0,5423273201690025713,31,5301556812154555002 +893,0,-827014178432784464,31,6198846503704264175 +894,0,4410575469603649344,31,-2717957435296483557 +895,0,-4472642034035214939,31,-1846413683302963427 +896,0,5360193252716249224,31,1541065546450007988 +897,0,-4572235983836835323,31,7627406535637422433 +898,0,-5433653902594010857,31,8688653962585513200 +899,0,4134790485921001466,31,-2279789089859885546 +900,0,4485288889906709425,31,3693984740267638729 +901,0,1685824402735587758,31,3307052409720155314 +902,0,6091818520229922279,31,5632857322252214070 +903,0,-212523426857309616,31,-1095700011694709600 +904,0,8873690209863775893,31,-6855267415195781839 +905,0,-8812432523459654235,31,125994440120922706 +906,0,8103047819338531286,31,-8537834667232717986 +907,0,4614534509558570387,31,-5991743487399037439 +908,0,4229082172984667846,31,1838245642562354941 +909,0,5484460792243331111,31,-4582703496683427972 +910,0,-2385763800014084246,31,-2559135925496972699 +911,0,7030455160712580607,31,3049228046937389916 +912,0,-4237997225503760625,31,-2810084410975757599 +913,0,-8124291737715145061,31,-7639653331306102662 +914,0,6327782024255912635,31,8302468588794394460 +915,0,-1059957986215325879,31,-4906371567568624092 +916,0,-4603394046555224246,31,-2748394192089372195 +917,0,-412280426794415941,31,4912319239840743716 +918,0,-3912022758691365061,31,2960875061456332825 +919,0,8274283857906326279,31,4236003832685267381 +920,0,-6679687570538459747,31,-2291936739241778707 +921,0,-6155809572519276859,31,7971655038464202395 +922,0,-341344339192464824,31,1892448381984082699 +923,0,4137861550441588415,31,-1650280442436931970 +924,0,-6618940267671493988,31,-4815196415908707956 +925,0,-7291675023689911653,31,8287777086955180539 +926,0,-7953871974818004574,31,8490371740640015410 +927,0,-397153165830243551,31,3085462683838400523 +928,0,4399741193484513820,31,6197357588372183848 +929,0,-7321827371527026850,31,1140626495881479526 +930,0,1338155597001139997,31,-685297953011469041 +931,0,-7945100475342274903,31,8202662370685309675 +932,0,4522579580699730675,31,-2700066499305519229 +933,0,-1777997817650119183,31,-4879934737224192714 +934,0,-5064101783437092203,31,1070970288463817753 +935,0,1113553310062801693,31,-7908782979990185158 +936,0,-5709720543205442481,31,1112784443256682344 +937,0,772882345518435045,31,-5592767587073410287 +938,0,8903336589907078605,31,5204736283117939634 +939,0,-8789465120959251318,31,8902524586883241592 +940,0,-7834044567177051539,31,1647068676942038390 +941,0,1770279151425541006,31,1324576436775908097 +942,0,-4941283968572768930,31,-8710262043509104512 +943,0,-8127231558741248281,31,1379956660804330728 +944,0,737747628416269099,31,4967523328260836623 +945,0,1574449851957266285,31,-3735276130542548771 +946,0,-471282776174276539,31,2249779664829486072 +947,0,6739952936193376447,31,-5553964111219639877 +948,0,-2424982200476312714,31,4322159740412245593 +949,0,176022186483763915,31,3253129107613528731 +950,0,347356729555692814,31,-6064911160477577289 +951,0,7550980861784622262,31,2813189134497328433 +952,0,-6474882761637742162,31,-8992328992999091641 +953,0,6769254801287215843,31,-8921059120539276466 +954,0,-7346044586598503820,31,3449678967156123155 +955,0,1815045574884249754,31,-1316687914608243894 +956,0,-4240219227462571370,31,5274038587361881316 +957,0,-649819224919779208,31,-2850644551591911512 +958,0,-3697860834931443057,31,313580859199758764 +959,0,4209607762757612835,31,2721136691941302363 +960,0,5512379227441488333,31,6899814102030924137 +961,0,2554702396243693813,31,-4262379033637215099 +962,0,-33063197416101018,31,7226455038649897293 +963,0,6204387436027047110,31,1333602243129974971 +964,0,1121696558750946811,31,-7057526783213450977 +965,0,-67713675745955613,31,-6765806327098241786 +966,0,2900236341998750711,31,-2087014665315653959 +967,0,4072627124871947361,31,1627400262381859873 +968,0,3411250942283240973,31,-6916832408947844728 +969,0,3459019187218245290,31,3561260847678568913 +970,0,-4931935198846519054,31,1400201469883793416 +971,0,8420402881327935528,31,-2942662524032535728 +972,0,-2700073972687127894,31,1652279787136382690 +973,0,4135622085465759778,31,3359997409337373596 +974,0,3115364578959809417,31,7691928846577945699 +975,0,7905907040079822152,31,6974333129516273013 +976,0,3117202331600018366,31,-666372451355801442 +977,0,-6912405766950946927,31,-1494169212034077471 +978,0,-4526890208931001416,31,-4052706116197995762 +979,0,-8362196017109360491,31,7089177105804728741 +980,0,7990163642449120866,31,-5136539369592935549 +981,0,8921333090931858791,31,8377687437445744380 +982,0,-7835160532401884454,31,3992106647829779781 +983,0,2597345228860385242,31,-3793352602435856873 +984,0,-2019901582135813985,31,-7945560152368860408 +985,0,-734731610197007345,31,2394085492392656168 +986,0,-4478738615320414333,31,3501612013075406461 +987,0,-7971363857175568029,31,8678927507551454256 +988,0,-4550695664824391599,31,4854126022746109031 +989,0,7004896942426055925,31,-4137613734412068139 +990,0,3243444764663891458,31,3501194119389597385 +991,0,8221182849925835178,31,8671460489014922288 +992,0,8413639868002181795,31,7729995920067257899 +993,0,-7599742913553767497,31,4203613812539348767 +994,0,-4861871033227348667,31,-2223991466644364493 +995,0,7180813616057727196,31,-409819264089019600 +996,0,4110358466985293134,31,4976956191213072360 +997,0,-9163301540202343656,31,5008061666532470612 +998,0,7407431836530456233,31,5429302847456273436 +999,0,7168833492994704184,31,5391886050670694682 +1000,0,-3225184215180636592,31,6238711774226800984 +1001,0,8550286352383434501,31,-7033179752395490818 +1002,0,-4037242040051553894,31,-6189050500568700846 +1003,0,-7019860459089371337,31,-4898903992053015197 +1004,0,6499568859919656194,31,4560735087665543080 +1005,0,-6517870390876058597,31,-5878896329736180161 +1006,0,-8816903563531564452,31,-6559898135946017059 +1007,0,-5488567103311833696,31,-5489635361011455616 +1008,0,7162975208461021799,31,281909088428919898 +1009,0,3231150263108104601,31,-6095476675182966156 +1010,0,-6472825090155306196,31,-1689653320479897602 +1011,0,-7112727281349161724,31,-7327604998132218310 +1012,0,-8908480908774446053,31,-228829010333903790 +1013,0,-162138742916032914,31,-2445329385268550830 +1014,0,-4934765719133081654,31,2773183873260101791 +1015,0,-5383597847234182085,31,563358633060495016 +1016,0,-1457750799424768103,31,381306221872201475 +1017,0,2062788467226997042,31,5031127726998511612 +1018,0,5195212083662151172,31,6639307224571377323 +1019,0,-7086725269988157115,31,2891666349750308170 +1020,0,3216790230270684188,31,-4548711714070865234 +1021,0,-6772983200597124262,31,3945287090389353279 +1022,0,2139536380152189149,31,-8937867503618472392 +1023,0,2783400616608816134,31,-9164734078142312043 +1024,0,-6309269121238725342,31,4354711622420435254 +1025,0,8703327852945446994,31,5442018140312952074 +1026,0,5986578967392046329,31,-3960256517306462354 +1027,0,-8686234791137218952,31,1947772254480049609 +1028,0,7147175926193618258,31,7610773631557342737 +1029,0,2812520130705527307,31,3229797751087780306 +1030,0,1012516456501023939,31,1070398585875606800 +1031,0,7796658848573086967,31,4781805553991597435 +1032,0,2642184550087192362,31,7158571104493559700 +1033,0,2521303561751617614,31,-3745383909346703166 +1034,0,-2372355039844318123,31,661706017585711438 +1035,0,-7982908463432899233,31,183939329936927986 +1036,0,-4773586301827797121,31,-8220023980643983993 +1037,0,4040904044293393487,31,2851804732207747457 +1038,0,-142670900232845920,31,-6856401183405056119 +1039,0,-10691804562559377,31,4601363436560089745 +1040,0,8453630879397574208,31,7468823501423475597 +1041,0,5612078661433375152,31,-3938200256038909036 +1042,0,-3592401183831123809,31,-6700724590232858233 +1043,0,-1194636486876965628,31,-748326708138615899 +1044,0,7144612844993582305,31,6303214931239235041 +1045,0,5952025594559102453,31,947842656111318803 +1046,0,7768859735998504182,31,-7479166762514972211 +1047,0,-9046596974248194873,31,4537602797705097950 +1048,0,-6171084369920910835,31,1659427236554607631 +1049,0,1781418400960307869,31,9034497206656892364 +1050,0,5081999630281512875,31,1247096232313123478 +1051,0,-5147831879244994539,31,7737692044940344349 +1052,0,-6245492622672631422,31,-6504193015403983174 +1053,0,-8665204890652827995,31,1019223700748945338 +1054,0,-1175718303513980672,31,-2321614853859921742 +1055,0,8885449897820005156,31,-4966143327912914755 +1056,0,-328163209321586593,31,-2800664313596682356 +1057,0,-1445525508305375763,31,1749886263141031128 +1058,0,-2100999238041350502,31,-6181852862063166353 +1059,0,7410786050561217868,31,1382134040134743530 +1060,0,-7914164711220348362,31,-4957161605381028734 +1061,0,-2906200250494490361,31,4987368781092281513 +1062,0,-867790952312765711,31,-3036129939775251146 +1063,0,5887767909251264450,31,5023023863951197589 +1064,0,-5789450489200739242,31,459575774408016516 +1065,0,1662159886119924244,31,2580903764950510554 +1066,0,5012361370472355454,31,5184667654522130183 +1067,0,3429745384914079292,31,-352821239740305547 +1068,0,-4445208736020219814,31,-5117172113599333866 +1069,0,-5413763295704138557,31,250164660546825169 +1070,0,839374495111075513,31,-766118384267143369 +1071,0,-7648977736915073173,31,-4329751808096495121 +1072,0,-3664832624688924839,31,2474438887816739461 +1073,0,7158412277573249226,31,1011249325364311278 +1074,0,7779305491962558566,31,-1968712817183116247 +1075,0,8039313349173431072,31,6139424537170216034 +1076,0,-4220847824862505833,31,-2151665361404572525 +1077,0,-1939839155925934724,31,-2754651264080328912 +1078,0,-8034010027834756500,31,5798350360244220188 +1079,0,8475758752811450501,31,4693765529447583156 +1080,0,1099214246266343746,31,1929244904383993575 +1081,0,9186354033975902114,31,1727413515341283376 +1082,0,2335697942068596836,31,-3805910952490999875 +1083,0,5125601667360226370,31,-1948961990045347343 +1084,0,6606318187238773479,31,6555733018114098125 +1085,0,-1182364933194642155,31,4546493924641412668 +1086,0,-1282696136769309305,31,3223379425966786077 +1087,0,1154559731683162717,31,-554470938888379315 +1088,0,2886049233756462774,31,-6701080950684947405 +1089,0,4825677492212933300,31,2441378598304816570 +1090,0,-9121350732551109877,31,735163064735787855 +1091,0,-877752678277742358,31,-1143805278330222519 +1092,0,-3266764465431864389,31,-9142970822786918097 +1093,0,-1914199636241277795,31,-4432720495241210302 +1094,0,-4687907120417383299,31,-1438632070804150077 +1095,0,-474253911596715394,31,8243725180214631403 +1096,0,-7075290400477487025,31,-2011101577828633348 +1097,0,8134957124130148548,31,-849824540384978442 +1098,0,-2992238854808660187,31,-2047593776263337298 +1099,0,5996516183600836003,31,-7071397527407483233 +1100,0,-371549095799671162,31,749882371238471020 +1101,0,3902975175457565825,31,4337409275444921786 +1102,0,6605036583318392521,31,4116424725796020314 +1103,0,1891100275270423451,31,-7253122679156767454 +1104,0,2119245665259072674,31,5629828633231633579 +1105,0,-834774890825819923,31,-4383084959152783913 +1106,0,-231771124221128734,31,-5155193086714023720 +1107,0,3133196876747178672,31,-2373259479026519915 +1108,0,7298692169226203885,31,-7818215197774843535 +1109,0,7126455091552696586,31,5925293837667639541 +1110,0,-2143648506542037333,31,-3510495143095778244 +1111,0,2865309216991778464,31,-119225895633457361 +1112,0,-582169278536046195,31,3635590242204487527 +1113,0,8080177625773872889,31,4587974855194592417 +1114,0,-2641866597771089394,31,-6709978784897220010 +1115,0,-4210759777426999986,31,-3616920416503714983 +1116,0,8940623302154716559,31,-603973036260972461 +1117,0,8753678355208533280,31,8502868427192263963 +1118,0,-6281297936039038456,31,-4701562571313643734 +1119,0,-4466014453281785565,31,-1853254659587754427 +1120,0,6273362062923197148,31,638202299401670308 +1121,0,2333217083667471091,31,-4127480652418968457 +1122,0,-2134695293413683177,31,7481102533917325704 +1123,0,1638282373040657672,31,4315563942107051815 +1124,0,3200622258378038793,31,-6431493028350020891 +1125,0,-8777912174432066160,31,-6125380500904211150 +1126,0,4509402067996738269,31,-1175424890970443457 +1127,0,-5444623700171973227,31,3473017400138563091 +1128,0,-4861257960719874399,31,-4293757893879787839 +1129,0,-2931845644152220868,31,8160788278104892773 +1130,0,-2415035074251453041,31,5872850515613149514 +1131,0,-3415608992526650142,31,-5374042931879036384 +1132,0,-1100060277548286709,31,-6683256837741040680 +1133,0,-7950756431533405941,31,2688409882729282116 +1134,0,2529778543681983619,31,7281550413955055152 +1135,0,-2509511542105356611,31,-5597789545133864217 +1136,0,25235701976844069,31,-9100148192240672197 +1137,0,3512243450460933893,31,-3815054694652941277 +1138,0,5497081699936367558,31,-1944426576341816210 +1139,0,8834833749235004269,31,4110577598696549911 +1140,0,-8786955172657476976,31,5973123866520066340 +1141,0,-2806229680204644453,31,7719847717746669329 +1142,0,-5310949673572257587,31,-7738400875354384813 +1143,0,7180989110601385791,31,7655985755874562338 +1144,0,4574812998786692932,31,-4422434002967042126 +1145,0,-7191136183375597108,31,8385476496812996502 +1146,0,7817612065160053901,31,-9169486455574486594 +1147,0,4092147258927215079,31,-3536998069107770923 +1148,0,-916694886327147203,31,7386036540154058211 +1149,0,-8155481011317235899,31,-2461748404253781808 +1150,0,-6577214469178899288,31,6629004787091023543 +1151,0,-4704682976594284594,31,-1046232746239765593 +1152,0,-970000750564611255,31,-8087327022654778321 +1153,0,6392037803435901919,31,-2833250548933164447 +1154,0,4653466442162924160,31,-1526149227933180961 +1155,0,-4217569099833350175,31,6741087764976503227 +1156,0,-7494295064988163591,31,-5414286467582367480 +1157,0,268071204677339466,31,-2351903832177740850 +1158,0,-3128139626778549626,31,9090297006393798932 +1159,0,-8490295735340959824,31,-8723823578008743569 +1160,0,-5162368829222403127,31,5828509530413400225 +1161,0,-4379157681365371219,31,7484185622284045511 +1162,0,-4505869932044746193,31,-5624993716176790589 +1163,0,-7725004848904746158,31,-4902927524521696646 +1164,0,-1077347489733049759,31,-1884333194900702972 +1165,0,4372692724364737369,31,2034257300053016911 +1166,0,-6095523387109702205,31,6112715489488477093 +1167,0,866555760732064401,31,-5785479078375577823 +1168,0,-6043383891507219565,31,9070568109583299646 +1169,0,-5064298145687783678,31,-3511138338699360915 +1170,0,-8284554766413268444,31,463039522329168898 +1171,0,4358509246174021158,31,-7697486516647479059 +1172,0,-314402459279271878,31,1544771087818730181 +1173,0,4534052702364464050,31,6830610090913253939 +1174,0,-5069975264209271430,31,1161592649080623928 +1175,0,7618881160105474363,31,1915270481215459006 +1176,0,4167592104901771551,31,-339896811858234565 +1177,0,2277499839812963141,31,7304674457302427809 +1178,0,-5797737740917833733,31,-1788935973462080004 +1179,0,5386843611229288306,31,6640280275177134407 +1180,0,322032948055534721,31,-7117217727885136711 +1181,0,8623908495470433985,31,336044405129858379 +1182,0,1464656873108399270,31,1468006944558775510 +1183,0,-143110847782655873,31,7522289179160789276 +1184,0,-3683505493125515417,31,-4018934852501355137 +1185,0,5263884653798534228,31,-7469562831506956435 +1186,0,-5596816932431872850,31,-296305079638866453 +1187,0,449263668055475580,31,-5863074793454900995 +1188,0,-8209880385374160761,31,-5073430568215616159 +1189,0,-6160876842633556933,31,1445218666972486280 +1190,0,-2822510119276015598,31,3895193056163975024 +1191,0,-1867833971803598158,31,-4087637794332683382 +1192,0,-2743011208375680513,31,-8521054590569787031 +1193,0,-562758870972224424,31,-6043895865180623173 +1194,0,5241707884356795802,31,2832404952503794844 +1195,0,3044382044884310303,31,3430546036153929594 +1196,0,4240643424518839454,31,-8243067158207263475 +1197,0,-7202731734581844883,31,5243901865576444685 +1198,0,-8098501199143125283,31,665866922920616239 +1199,0,-2550459180607677020,31,1102963014311839746 +1200,0,-1776717083783659251,31,-2552789205416214466 +1201,0,-2343369089757631624,31,-875100392565970036 +1202,0,-6293279254462751659,31,-2742232049665283833 +1203,0,-9100627021059872276,31,3346204770439191657 +1204,0,-1298100985130924363,31,3617178253112727172 +1205,0,3390116780901102550,31,-7038914848507758540 +1206,0,-4663999614093100429,31,-1348633231417818679 +1207,0,6916372370306791572,31,-7451686098357835220 +1208,0,1488349423055656442,31,8171346835840554535 +1209,0,6773020852755024150,31,-401202259793390466 +1210,0,-7005014351468554871,31,6522655462184670847 +1211,0,-4753926923183579314,31,2412270107978838271 +1212,0,5415870192658316069,31,-4831183853930634305 +1213,0,-2670881940811475410,31,4786721410372709542 +1214,0,-7225213211793183097,31,1745957932090855999 +1215,0,-5703028807893997804,31,8648873209534113191 +1216,0,6561444537664669662,31,3890848852620957985 +1217,0,8939981796276591301,31,-6689399819542424422 +1218,0,6017910964940092953,31,2695939565462612852 +1219,0,4500890776998912544,31,-3576311568654229412 +1220,0,-1835018042586347444,31,-3231502388948936223 +1221,0,-4191687948466793374,31,8224274411255449639 +1222,0,4106435482907441086,31,1304822073471845643 +1223,0,-6130167349217050086,31,-8702454446826110013 +1224,0,620129892796426300,31,-2200210370534167134 +1225,0,-6144158488464216798,31,4908501241386952134 +1226,0,-625006850515938527,31,-4519128563573851055 +1227,0,-6682172611475406987,31,8013492964919143488 +1228,0,1220842624016183584,31,-4044360707952897158 +1229,0,-7098540157067814615,31,691128998094416275 +1230,0,-4378743347226734130,31,5458707118700515224 +1231,0,-6508042393772984279,31,8363561475106876229 +1232,0,5289282493574993598,31,-6051400999624110791 +1233,0,-6781000719696595982,31,-4956870383565124222 +1234,0,3322666381578332368,31,2568855053447673314 +1235,0,-8173363279507413324,31,6590127290656044681 +1236,0,-3603049973704190207,31,8946858741346005115 +1237,0,-4316988796658196446,31,861061192098376640 +1238,0,914989291445423876,31,-3156418472126141324 +1239,0,-305370752767861151,31,-2432386916892609644 +1240,0,-6987550192802158001,31,-33226580931025371 +1241,0,-942676483343861967,31,2996564639525699491 +1242,0,539036846465448158,31,-6148247234338671110 +1243,0,1605373100913987077,31,1121035817317574475 +1244,0,7713068526230669637,31,-5005969316266322298 +1245,0,7241900405827926293,31,-7270024421498375252 +1246,0,186408038263119881,31,2621101632884020861 +1247,0,-2429472274603752977,31,-5930033659748457627 +1248,0,-5720789098334319209,31,-499731473504668948 +1249,0,-6674769505767916301,31,1834354603403798322 +1250,0,-581393540490176967,31,-161770551161716671 +1251,0,3124744789645879825,31,-5822330226877828590 +1252,0,-5602915602343937931,31,-3348184775512108201 +1253,0,3263507419526132695,31,4729535135380637106 +1254,0,6937077332985554718,31,1075975578503529597 +1255,0,-7919624999578199393,31,8132285429578087273 +1256,0,6556190618267765484,31,5349358871084184058 +1257,0,5682381095734864238,31,5802742526552812624 +1258,0,7614251273120089370,31,-7527530898329861990 +1259,0,3395157685499349978,31,2173726469197589642 +1260,0,-6398328093992251036,31,-4653161382842209755 +1261,0,-2651093395236575804,31,7482111014601532045 +1262,0,-2097470820892650054,31,2951155031919664369 +1263,0,-7267148748500151232,31,4226863709628908432 +1264,0,5507274834982481157,31,6161275195705861335 +1265,0,-2194323672581532616,31,-465769205819839014 +1266,0,2269493654210886217,31,-7705933868240888672 +1267,0,-4216275761811372636,31,9200199179002781548 +1268,0,7228709978053803804,31,-8376502023954053038 +1269,0,1544682503099095700,31,-9168364301200737872 +1270,0,-8135200911288478327,31,4575698614109268267 +1271,0,7339704802803690870,31,2891101607550403759 +1272,0,-9063598666954112733,31,-1492292817891341680 +1273,0,4249185982522288588,31,-159441991646161544 +1274,0,-4695745996091883154,31,8749066787566949432 +1275,0,2627137268581003083,31,-700365358660365856 +1276,0,-2578238879441406084,31,1010723655700711418 +1277,0,2429552460105156204,31,8400419788065802705 +1278,0,-5016405662860787559,31,-3303932320216752257 +1279,0,1213685060600888916,31,-7435907851752391737 +1280,0,5207480625629771054,31,8864432643667460942 +1281,0,-9039842400434871721,31,-4295548076369557621 +1282,0,9199909831090107055,31,-5687878214893720026 +1283,0,-3171515520826634527,31,-8545357130345932295 +1284,0,-1366973376209295366,31,-8290135444773380119 +1285,0,-6750324026060931870,31,579662423345930816 +1286,0,8743899778045759827,31,1865348949472845442 +1287,0,-8621966377322960273,31,-1544913042264798329 +1288,0,4838450322903886505,31,6302269571714819438 +1289,0,1788019071908015560,31,9202465688872715216 +1290,0,4913822197134872906,31,-7081944846597977799 +1291,0,8309346613152344445,31,3545673798081707602 +1292,0,7951951012499331460,31,-3361508514499898016 +1293,0,-4689530477253691656,31,-6508489256787258294 +1294,0,-375319494882093024,31,-3684156751704226007 +1295,0,-1845044534505086395,31,652366486229814575 +1296,0,-8796776862070375491,31,-5885230082425172375 +1297,0,5018318155817526800,31,-253323472965276132 +1298,0,2586522091503534478,31,-7374639746054656305 +1299,0,-4968582762284083199,31,6957675925906633765 +1300,0,-4927465852300428021,31,-6498751842238085053 +1301,0,-2580812699959118622,31,-7044751506517371074 +1302,0,-4904418483836862133,31,2137597604864327204 +1303,0,4578001388519224564,31,5940948261415220206 +1304,0,-145427029490022812,31,4541538191788093614 +1305,0,5605281842155781953,31,5009435503057047599 +1306,0,-8269674765102782771,31,-6566736843383418858 +1307,0,4873099922414055552,31,6762981939716129612 +1308,0,2170749688227700120,31,755601562448277586 +1309,0,4825942009324106796,31,4408785109908629860 +1310,0,1792050877115378285,31,-3721112962377631040 +1311,0,-6605853503524394834,31,3608129937746839580 +1312,0,-3916692778840952841,31,395345438581398489 +1313,0,-1986097963548896269,31,-5899911832362003114 +1314,0,7892537689540433594,31,6552095371137037488 +1315,0,-714136291891260346,31,-2504825269847773292 +1316,0,-1648197774385026330,31,3615492526755541540 +1317,0,3795404391823901459,31,-6331771505447850368 +1318,0,-1987978550021718355,31,5684957840507294844 +1319,0,8998001289418857599,31,3255716220107484337 +1320,0,-3968668700060172110,31,-8442472332863634201 +1321,0,-5244271268838414883,31,-8635592130359201609 +1322,0,1096876802937588911,31,-2570547058322927361 +1323,0,4954206823378648244,31,-7017799837454690826 +1324,0,5569423710280172585,31,2122466090921827396 +1325,0,179070914051875895,31,4458398649517814026 +1326,0,-1379762138674772955,31,692682873396075689 +1327,0,-6297783890085466379,31,-8273009781767211092 +1328,0,8673286033209200164,31,1690691951291434423 +1329,0,-209771371089403783,31,6254034993657850375 +1330,0,-8371158182924445911,31,4491484636510913167 +1331,0,-7703744831611511871,31,5553218472265184053 +1332,0,1612557317982335369,31,1649029168485065007 +1333,0,1602832695339190345,31,-6254244712396140682 +1334,0,-5248812496760442693,31,-3377318196393986341 +1335,0,-555465681086935620,31,-1401697021409079754 +1336,0,2520493230458560658,31,-5159087756230008208 +1337,0,-6666085761216925275,31,-6896897009024695727 +1338,0,7883921169936066300,31,-8424648108485787365 +1339,0,3038683421696596159,31,788876017766453777 +1340,0,5845618097380867812,31,2774218368275159146 +1341,0,-6239014819988016480,31,6828688921392281425 +1342,0,-8753088746243740226,31,-924622569372152472 +1343,0,-2330652362011359445,31,-1809063437546062273 +1344,0,840642889332131730,31,-2181996112200007936 +1345,0,4416624017275726341,31,-641509037387812661 +1346,0,4690979542527364119,31,51839008476586846 +1347,0,5378555482069527564,31,935854194737555799 +1348,0,1969844668631546234,31,6019484609010634870 +1349,0,-7848379025576209733,31,547893480189511308 +1350,0,1977110971269560399,31,-6148007919495286082 +1351,0,2026765724811466304,31,7720771829945238454 +1352,0,9004994755727389006,31,-773945117527945984 +1353,0,-2875238066205385075,31,1926677274737226261 +1354,0,-6183036361941845026,31,-6395798274518387944 +1355,0,-2386657827628040463,31,8593880147691248907 +1356,0,-4350668673682921339,31,9078205046699764726 +1357,0,5862965863197982604,31,1687061396259984242 +1358,0,-8441011186955249281,31,8052647438310490310 +1359,0,-7186928257432232499,31,-2643398387883903466 +1360,0,4577738672815669344,31,-4206363768767332703 +1361,0,-4699309429317703093,31,1726776956507483937 +1362,0,1727205267222358381,31,-6675064540332803407 +1363,0,-6451216071831055595,31,1040682393064289820 +1364,0,-3419094732699739587,31,-5285773616960943848 +1365,0,-9202486234602916474,31,434318734906302558 +1366,0,7995498040430401544,31,-4230281909112344236 +1367,0,2322468220197016729,31,-7139562929162532361 +1368,0,6579662275874920800,31,-2569686954046045597 +1369,0,7479989025114804641,31,6201937960763936246 +1370,0,7484110942964095819,31,-5547043311424419618 +1371,0,2864220530563314806,31,299661338590996294 +1372,0,-8398057079307137296,31,-3447282770090137982 +1373,0,6439003393908427189,31,5959772595151396608 +1374,0,-7835388314568774857,31,-4523545650550080589 +1375,0,5595140202807403856,31,1068131050982366703 +1376,0,-587980358622679054,31,-7210078574068325784 +1377,0,5729028629565035445,31,-7186569810512191399 +1378,0,7294164757654120979,31,-3512847835598728608 +1379,0,-7034561723919575604,31,-7798318498826057498 +1380,0,5344573969684937116,31,4828632647536227516 +1381,0,3196215998156871328,31,7616512367153518100 +1382,0,-1123378572589443417,31,456941449675651748 +1383,0,6074546259209406933,31,-2125865780786014509 +1384,0,2893792398378492069,31,2772768724928622706 +1385,0,-4483476567799717014,31,-883412667814721111 +1386,0,-3363408847369344926,31,-8613158900946070097 +1387,0,7141254867533804482,31,8135324419687651895 +1388,0,-5940527802490951736,31,-1194113849600637273 +1389,0,-1094882559952364017,31,2361149298432221122 +1390,0,8329622896679444321,31,-4716251904888106051 +1391,0,-3173141862687107863,31,6744621741378228841 +1392,0,-7280018015022509268,31,-724826652301613576 +1393,0,-2089330837882663590,31,-8620183010606605469 +1394,0,-354683141083920270,31,9128768904894841126 +1395,0,-4079664314326720324,31,6131176950544377544 +1396,0,7616886288174535159,31,-7833646956648271553 +1397,0,8554847071096590810,31,-7187383640229138971 +1398,0,-8173759087524336468,31,-267002394503707695 +1399,0,-3448863502458656393,31,7209543280015115843 +1400,0,-5738508186162418231,31,1475304113542697746 +1401,0,-5111997041556312344,31,5714716858751525046 +1402,0,-8550681297377936354,31,-453338945835125902 +1403,0,-4330402296580745208,31,-8280406129777924162 +1404,0,67088796475747867,31,-1723876462380215154 +1405,0,-6874504283145514740,31,-4153650179440474048 +1406,0,8707156726330695854,31,-7407526946010167827 +1407,0,-8450062796293630088,31,7383682852847268826 +1408,0,327731584813515290,31,-7005415203511781457 +1409,0,7304259244110792264,31,-1424806910208714465 +1410,0,419104563434390334,31,-5120603821653367717 +1411,0,-9153064691975026716,31,-784654374739437520 +1412,0,7490483813653854554,31,-4152498313566997456 +1413,0,7077589656341495466,31,3202291314838145155 +1414,0,-5945353789867862552,31,-823213179020025725 +1415,0,5486988927099214347,31,-8317449711832238793 +1416,0,4267202661349380766,31,770123597240742004 +1417,0,-735203469934508862,31,4049332027330868264 +1418,0,300049113155592253,31,-1264176141295376110 +1419,0,6668837619034437534,31,-7257804177236164416 +1420,0,213993526072465908,31,719084983893255897 +1421,0,8835245471465274914,31,2872851284460907160 +1422,0,8183790714937497863,31,-3390325751089064230 +1423,0,8258711456036176276,31,8702161796977756670 +1424,0,7136444522589690162,31,-4828026332674381313 +1425,0,1211565004822707193,31,-6545988973636660968 +1426,0,1989924245575051080,31,909398275945906770 +1427,0,-218487864794566557,31,6578631306061015627 +1428,0,2952924548635767820,31,-6494846674076871257 +1429,0,-6462002167772557833,31,1884482413051746814 +1430,0,5913246427219973975,31,8691877339916484986 +1431,0,-3174533491330927888,31,6929157584169324976 +1432,0,-8785311174506482406,31,3721912659054478772 +1433,0,-6684494991311010323,31,5146063180002518019 +1434,0,-2482601218412888093,31,3624713011040032805 +1435,0,-7285335761215045787,31,-2122492621654982750 +1436,0,1211034790718408728,31,-7230434892940931692 +1437,0,-9100855059113049869,31,-2398896312111433829 +1438,0,-1486270963118123907,31,-869822057140650903 +1439,0,5275833683049609995,31,-4758591337022464180 +1440,0,8459420716417000011,31,7004712475030691125 +1441,0,5533842052546250233,31,-3837746789488563172 +1442,0,-6743116187090502104,31,-4055758593424186120 +1443,0,-8218081861923503701,31,632115993725059630 +1444,0,5761628519765780332,31,306644948110924080 +1445,0,183841883985945582,31,1875867706748728858 +1446,0,6376290782250169855,31,-3923102052446483843 +1447,0,-775214822639981928,31,-6999797789296961347 +1448,0,-8823028331753034219,31,5290324744261904033 +1449,0,-7585331840565087967,31,4969404180175210389 +1450,0,2975478445973141542,31,-2730739625916746418 +1451,0,-5063889138086837402,31,-8343986707408135458 +1452,0,-2979700995440085783,31,2274310818866490500 +1453,0,-1219607777405733761,31,-626236163973712695 +1454,0,-7530208062940995205,31,-9090545746429455584 +1455,0,1583477077636770548,31,5657003377752873674 +1456,0,687603337248263893,31,-6262855098212673065 +1457,0,-7494884423475008422,31,-8221694672796744368 +1458,0,8422729696142094927,31,130240802961314586 +1459,0,-2688483407638967316,31,525383487683594432 +1460,0,3899397712568319078,31,-2697507998890969567 +1461,0,7271622649506188466,31,7368525887601399519 +1462,0,5081817906386987096,31,902712528866115468 +1463,0,-916174376204972738,31,2954659748892033432 +1464,0,1540653617218284471,31,6762783032482935669 +1465,0,-9108776863627327658,31,-5342731084335712914 +1466,0,409951124500633339,31,6121290673794748038 +1467,0,-1411012041120099174,31,-7659911523331982391 +1468,0,5254818079101287689,31,-1615137735067697376 +1469,0,4655192715659848616,31,277299894245705448 +1470,0,-4055996322312971483,31,7607802475537217535 +1471,0,-3525221214301544451,31,-4986401132408916251 +1472,0,-857176511645353866,31,4540023580256456370 +1473,0,-9137977946340218096,31,3602284571945687942 +1474,0,-2464138987127699380,31,8901792530205760649 +1475,0,-1572944913716776527,31,-3283270161870570588 +1476,0,-5382357127457681304,31,6674115172615201455 +1477,0,3400456476820781019,31,6248148326109445334 +1478,0,7092666713014777182,31,-8268294003024657719 +1479,0,-1016869719262402776,31,-408443003361218219 +1480,0,-4296380651220352294,31,5498525018929337795 +1481,0,-3137955217832540411,31,3762006546756769943 +1482,0,6899747201222115049,31,1701076292642917215 +1483,0,5612318743221858846,31,-7115030731968249138 +1484,0,-3082611894693908037,31,-5892075079386643888 +1485,0,-8765593464570788072,31,6449587463500869872 +1486,0,-8518170211087455673,31,-6917879046518239235 +1487,0,4127210266223470126,31,-353111888804835446 +1488,0,-480745760307138952,31,6927625917855992662 +1489,0,6366437837796426817,31,7424251771789564942 +1490,0,8633027726559958619,31,142402705050952765 +1491,0,-4876440158972240126,31,-438105538640266923 +1492,0,1910667810356463924,31,-5960731346921648849 +1493,0,525819879391508442,31,-1686570089633230451 +1494,0,728364790223504935,31,6141628203053996124 +1495,0,1801852490210258450,31,-1842823328756321882 +1496,0,1693556137065594317,31,3313048183435379426 +1497,0,7512677136171374024,31,-8237142772472388608 +1498,0,-8502671549747219751,31,3460475359887835541 +1499,0,6750465734377947195,31,-2292331365146689954 +1500,0,79926463486212071,31,-1253174424435683853 +1501,0,-1606928706353092712,31,5501619565599049878 +1502,0,205498205560429840,31,2418768191716168973 +1503,0,-8511147442275932832,31,8342199630599762912 +1504,0,-8428335428540761347,31,-8065780331273351973 +1505,0,-7426388905907916885,31,-3132299735264956582 +1506,0,-6514050737271088879,31,2610663711411492781 +1507,0,-2450758388754574856,31,8251008496895885504 +1508,0,-5091230991480586360,31,-1605126450064605047 +1509,0,-5169952131144179624,31,6504132816646661452 +1510,0,4447490729022261013,31,8117636585462009089 +1511,0,-3692318537052447395,31,-823608428324467627 +1512,0,1078660998337165744,31,-4004292216022047892 +1513,0,-3916568308067450676,31,5808844558534697803 +1514,0,6024800331836073525,31,-3176466681256973887 +1515,0,-8107333408030092167,31,-5478279072915502282 +1516,0,-7607289536558565257,31,-6116419517253386760 +1517,0,5247807205554828460,31,-1486130841208941303 +1518,0,136732938448579124,31,-2025001407223213670 +1519,0,-7158883148260417938,31,-1474730998167529221 +1520,0,-6099971793579365853,31,3674796743143537215 +1521,0,4854881589738432309,31,-3995562865001788186 +1522,0,7711527295835389228,31,4672295032091128142 +1523,0,-8549957081212159598,31,492698501793370725 +1524,0,-7303058748474201722,31,-8994048947651777113 +1525,0,-7681406204943895241,31,-6690125161950899296 +1526,0,-4881190754207950300,31,-5123306877701772975 +1527,0,-6035776958688302906,31,-4725424548460192482 +1528,0,7214212236240295751,31,8379487360732605060 +1529,0,1981012208386034732,31,8715407164722874760 +1530,0,-1049989180117070494,31,2480637054358991004 +1531,0,3924935253660959406,31,4523237692580501679 +1532,0,512859785555014414,31,-9139799954562445615 +1533,0,5908617682678575542,31,-2675854135128900347 +1534,0,6758310316951005278,31,-3872644490922560916 +1535,0,6189924959604816301,31,3152216862159743541 +1536,0,-4920405470515789427,31,-7745613003147345121 +1537,0,-2117869367297703052,31,4478590347818001688 +1538,0,6707816747990551118,31,3886007225012010246 +1539,0,-4980047489747530190,31,3903762443162500718 +1540,0,-7365247289662920271,31,8649451918370117679 +1541,0,-5342685489927387987,31,2551882484754537410 +1542,0,-8590216048531947264,31,7417186694097051390 +1543,0,6817356446955049603,31,-5910515771080350348 +1544,0,-1378280258813293636,31,-6450380214828447523 +1545,0,-3592400710075707758,31,-2584439515122125222 +1546,0,-8871693364702999347,31,3380286353220297559 +1547,0,-6373833613639184348,31,4849579374586237234 +1548,0,4797638018086956108,31,-8048188954053251840 +1549,0,-5647576741545902954,31,2030449488852558020 +1550,0,-7901112803680191059,31,1468479466452068121 +1551,0,-1362942868170890798,31,-4312456575587708153 +1552,0,-5813135684692802772,31,-7784926856375021920 +1553,0,-711135680335633766,31,-144500340341085306 +1554,0,1062354220967606079,31,-7938330212246834369 +1555,0,-7871043181645557885,31,-6693949692997202942 +1556,0,6112341712359859833,31,-3047931642589356223 +1557,0,7916891160508372008,31,-1500789987490263236 +1558,0,-8003652862887082098,31,-6079189243200184008 +1559,0,-2396517101239953792,31,7259251483134319376 +1560,0,4370059680750956803,31,-8167237408297444262 +1561,0,1363641917746765215,31,9087149472788743409 +1562,0,-5876946297329039758,31,512834098670444796 +1563,0,-103128310036998617,31,-9060808515421624985 +1564,0,-3800790044039752368,31,5003919547956589412 +1565,0,5199080865813174926,31,-1534321850211880554 +1566,0,5691839759690453434,31,-6264045366498862142 +1567,0,8175397015029172130,31,-7044399646154620345 +1568,0,480520985319940721,31,-7540182410902932448 +1569,0,-8578753082637254739,31,3079720217841320120 +1570,0,-6716879961856683419,31,5691972151083511524 +1571,0,3597461575855927530,31,-6142334113402187681 +1572,0,4979191387439246058,31,-4379710325253860696 +1573,0,-8320455146441525699,31,3496810531868503971 +1574,0,-2114691132483379200,31,-114055726838586895 +1575,0,-4537130860792099169,31,6680994871556853902 +1576,0,-5718306086279916956,31,-9107747842020075669 +1577,0,5136790107805442544,31,8761111883904799114 +1578,0,7289096860375296487,31,-4858202759311862535 +1579,0,2880058958308819603,31,-694392375857900041 +1580,0,3767398060224293737,31,1100182336871277451 +1581,0,-492404481239348279,31,6874146868008813423 +1582,0,9012315970305384994,31,-2523105079291018598 +1583,0,-2684151666886841943,31,-3053087028902059144 +1584,0,7272790214055332206,31,4698131095941248406 +1585,0,-965422762587779909,31,-303537347749785398 +1586,0,-5443848734878691959,31,-7514871436104884062 +1587,0,-8153873600234827448,31,-6560244785225102510 +1588,0,2490597961970604400,31,1521747356569719035 +1589,0,2281204882791254127,31,-8295674533604781424 +1590,0,9133290251048762192,31,-1703213624621952896 +1591,0,-1491895733843702610,31,-4804477384264892032 +1592,0,-3474774710279245800,31,8207935783784517718 +1593,0,4612394989169216779,31,-6987049628417358029 +1594,0,2622616589522119419,31,-3796484408825302795 +1595,0,4355987380154620492,31,3290520685445316149 +1596,0,-2850604048799570616,31,9006701388219487047 +1597,0,-4107832232055765572,31,8708427672292799522 +1598,0,-3723943963188375533,31,-6608378816136562398 +1599,0,-8366293232338256548,31,-2561730648568514641 +1600,0,-8701054798330196757,31,-4985222178864561223 +1601,0,8878901433891377891,31,-72158127029889083 +1602,0,7295106607144564961,31,5974520254723079492 +1603,0,5312667635062107659,31,1718895117914698019 +1604,0,-2358396954926641322,31,-7367461374016167152 +1605,0,-4984697743423066531,31,-771754974935351714 +1606,0,8939820283882288854,31,7693803497114536679 +1607,0,4023787057481178052,31,-5733771690716639642 +1608,0,4597747073035337711,31,-3625282639781486923 +1609,0,-3865522208345382306,31,-97178489596118825 +1610,0,6560083733272461230,31,3471518280955644630 +1611,0,2427578708615942986,31,-6076910763184615578 +1612,0,221210573151544106,31,586483219340103505 +1613,0,-694084245105944199,31,7185018032446798722 +1614,0,2078710449028907801,31,-8801244497135251241 +1615,0,-823943775911009298,31,-6770784791463045956 +1616,0,6602372026224749570,31,6074381543906089779 +1617,0,-6054136931573131159,31,-1571165415863465427 +1618,0,601483741465077007,31,-8342817277620040939 +1619,0,6742891241881907768,31,3668579149078483576 +1620,0,4262941380660230060,31,-4148083455873439065 +1621,0,-2511197275383350546,31,5039041153698328221 +1622,0,-9092751631744236653,31,7043403344300603900 +1623,0,-4870448764794484926,31,-8093489280068737369 +1624,0,1830385011126178734,31,-3860051960084685157 +1625,0,-6596888154152123634,31,4813250720225111396 +1626,0,5648158405496157638,31,8124821534821200067 +1627,0,6386181707589856071,31,-3497873875322458692 +1628,0,3363359913697235141,31,3998109692907979406 +1629,0,-7056659780210553822,31,6390369185303017995 +1630,0,-5261178176756493055,31,396425943408265577 +1631,0,-3944960812874472523,31,-2692232402347660825 +1632,0,2763181386445379193,31,6840445060735569376 +1633,0,-2619663536437942233,31,8954469449632825712 +1634,0,8897272156543942808,31,-5295402695392921704 +1635,0,-1257206140816012022,31,-1920651075915818302 +1636,0,5942440353528557164,31,5096765216956018463 +1637,0,4786157224137440415,31,3633717050993926511 +1638,0,-9220126986536151642,31,7546641829837738669 +1639,0,4182399256221021027,31,-5145489424088992633 +1640,0,5315354483278533273,31,1087676003297177944 +1641,0,8269371862567018757,31,-952850752543603402 +1642,0,-7830778159860165874,31,-4826832616797592566 +1643,0,-4812100746794420620,31,8137576600215637910 +1644,0,3498354375067608851,31,-2798081926379730950 +1645,0,-746722368941475584,31,-619590117689970164 +1646,0,7380715032997081755,31,5969852545378306178 +1647,0,5189957981103089885,31,-3814364506261489288 +1648,0,-4300428216272672646,31,2461660054950023092 +1649,0,-408627655218877478,31,5597601437448433895 +1650,0,3669295430170749153,31,-4887481378357019181 +1651,0,-3178922344308130598,31,3280238153948157938 +1652,0,808687805654478372,31,-1470674079996626317 +1653,0,7382854145017135524,31,-3571117063995739223 +1654,0,-6443473827958318421,31,3798408058614980840 +1655,0,-3243447797010153128,31,-812900833639532237 +1656,0,-1263178138991133398,31,-2702018730712779446 +1657,0,8750726774705960543,31,4390916445319123944 +1658,0,6533471826240257695,31,-8892489183892335596 +1659,0,-7394781107965678936,31,8470570186578178107 +1660,0,7513264927729266721,31,-6161713094181869211 +1661,0,-3004378607368189670,31,-4391724401760607057 +1662,0,-6171795523163885499,31,-3365262610648979015 +1663,0,-5383549323957030811,31,5387623531697800242 +1664,0,1014976843641973640,31,3920042490567418828 +1665,0,2432193004343470889,31,-4624324103526262764 +1666,0,-2321713758391047034,31,4772576896757064774 +1667,0,-5925760547403348951,31,5627626050745960410 +1668,0,236543589293463223,31,-5680575341428790664 +1669,0,-6902103426228510687,31,-8370099320525929444 +1670,0,5049656219947439343,31,-5557429174897329666 +1671,0,5906696563051122955,31,4401980335830963586 +1672,0,-6356958402903730770,31,-3711843581873976218 +1673,0,7486754190124721854,31,-423914402526956386 +1674,0,-6788905906689198314,31,-1137414196244506394 +1675,0,7381793004093637930,31,-4759115388785476713 +1676,0,-4615937202128935315,31,3445256920605269985 +1677,0,-5266672324677452216,31,7168788291271279536 +1678,0,1047319090632526857,31,3077817759627777400 +1679,0,9103083281304922244,31,874944387737593527 +1680,0,-8812437015774444320,31,1733622794376968386 +1681,0,-4970183476407639031,31,-3511008874716662712 +1682,0,-5247957782476148736,31,6878949457976309973 +1683,0,4465954112135309385,31,-3952895110792946336 +1684,0,-1053934358778018400,31,7985279994738881943 +1685,0,5829139887286261453,31,7050467889020125388 +1686,0,4669463005092905624,31,2838055095382729090 +1687,0,-3286153457025266798,31,6722521543704887166 +1688,0,6416979317993515170,31,7662848871351748421 +1689,0,842322401817513616,31,-4896316492577728904 +1690,0,-1776383023933641969,31,5300613277848351983 +1691,0,-8880210007231865557,31,-997453019475068883 +1692,0,4508732217351572993,31,-8768198954305075611 +1693,0,1193868998902473261,31,-1803501361187929492 +1694,0,1613803703795008000,31,5560961771842864540 +1695,0,7204477604144047047,31,1353463323582628671 +1696,0,-8681096723143103693,31,3158439364573768190 +1697,0,-1746910701409113306,31,1629048084835322259 +1698,0,-8920378322388987992,31,-4065448942002497346 +1699,0,-8966483163014777443,31,-9193289700180634714 +1700,0,2824165487928805094,31,-6239654367158857570 +1701,0,-5662128102397495131,31,-3717769000171739626 +1702,0,-6624810964386882286,31,-3462290855752196167 +1703,0,5452692340292941871,31,-5169908963014350616 +1704,0,4316228119275391983,31,5138413778084781646 +1705,0,-9085964721275713953,31,8060442785845982383 +1706,0,-2133433404692719643,31,-6447349010640195867 +1707,0,-7343693486447937998,31,8718442974805509320 +1708,0,1109852172632293793,31,3517001683871458432 +1709,0,1921023425304227346,31,-5558314817030816375 +1710,0,4854131887624741149,31,-5840902616608224444 +1711,0,-8634651654935008313,31,1243517585108585470 +1712,0,-4727747937541913857,31,4507307872173224394 +1713,0,245894689954376778,31,1183675516452111283 +1714,0,-1171354806284191550,31,-5755238488499118479 +1715,0,-4449375760321500296,31,4260563280431814905 +1716,0,-2278035820133972979,31,-3294850938372750307 +1717,0,7026254152720723131,31,4360201917091798579 +1718,0,-5122868976531507196,31,-4838300818721180317 +1719,0,-5791020171604844054,31,3620568286582645952 +1720,0,1901595461796531398,31,1106095060151580233 +1721,0,-4888600188203895159,31,-7660289550108827378 +1722,0,5238583255328115684,31,-7561951365915325528 +1723,0,8191725727925819882,31,-6788589643431359424 +1724,0,6907331918345427440,31,-1674700630495734835 +1725,0,-8330998437541118229,31,7747028135636092892 +1726,0,-7677204855776214746,31,3002946543722607577 +1727,0,3733289736446750667,31,1005841947173237752 +1728,0,-6086367961329321564,31,-5265812176455684573 +1729,0,-2223139316713310111,31,-1918055153370972891 +1730,0,5551603720291777494,31,6563834197359447794 +1731,0,-7284366962105424622,31,-8162455203207213489 +1732,0,8307035520655908816,31,-8567623969233296250 +1733,0,3515558653608239510,31,-2257558412811172748 +1734,0,-2623185163047066159,31,6929943520001200757 +1735,0,-2881473020374695697,31,909487566440553474 +1736,0,-3119109298045318191,31,-7224956762544176331 +1737,0,3915842281774372758,31,8316875420796717239 +1738,0,4341838354106623860,31,5825658765688494249 +1739,0,3536460086838807366,31,708793603169837510 +1740,0,-400436201916140511,31,3960266910603389971 +1741,0,1034940505346304444,31,-7559638349395558712 +1742,0,-5677328290907787965,31,6444874301811631430 +1743,0,3241577004049148165,31,1643268936839836377 +1744,0,-2177296903540985003,31,3582057394396220061 +1745,0,1224705836089007055,31,4095958506142053337 +1746,0,-7226703706701449257,31,-2290967778028486664 +1747,0,-5217415576556159333,31,-3881507763731067529 +1748,0,2723639485365257427,31,-5951985185207384984 +1749,0,3532882935985140762,31,-3619106933554569826 +1750,0,-2367665914582725528,31,7410669988422137986 +1751,0,-1126240810191393257,31,-2904333433161169897 +1752,0,6572389991681822664,31,-4927875107898731215 +1753,0,3742078454964142074,31,2999578744814172341 +1754,0,2537741859858174488,31,-8643360718549746826 +1755,0,2863650720786458695,31,4683203171260427110 +1756,0,4444554472903165566,31,-5978387111600342191 +1757,0,4972147385910153832,31,1058723030645428441 +1758,0,565306137953874174,31,4837957640123351120 +1759,0,8228468642079060801,31,5415858183203507255 +1760,0,3686959913775111096,31,-6506022400105076940 +1761,0,5015958178622222071,31,5727255472085237633 +1762,0,5595710504305494790,31,1145875581940412248 +1763,0,3174461843483976916,31,260090775932538568 +1764,0,1297058991090722108,31,-993740256310566421 +1765,0,-2693601104595504655,31,2757010450924203632 +1766,0,-3961646960717704540,31,1048179590372826939 +1767,0,-329224545254449497,31,-8444668925875229016 +1768,0,8172319141947522776,31,-2116435553060913199 +1769,0,-3283750417712288364,31,159156480922693082 +1770,0,1484324135840360777,31,1853768360796123185 +1771,0,-4101313183342306762,31,5334898829740753544 +1772,0,487423326160209394,31,-3278069420949952053 +1773,0,-6984064475638587471,31,5669555652377002114 +1774,0,8613232447441028099,31,-364593442142215121 +1775,0,1138585794312519742,31,1772293317984021107 +1776,0,-5219522830444455097,31,-4132169189366398968 +1777,0,-7068591267064606505,31,513054321076209178 +1778,0,-214092808701416145,31,-36575187799378999 +1779,0,-2087748990108944657,31,-1672201466951678582 +1780,0,293814116254359703,31,-2230945024465730571 +1781,0,7396092072095010078,31,6605016297660664376 +1782,0,1104271143132319796,31,-6617678276744361194 +1783,0,5950063587854161963,31,-2678698558165405808 +1784,0,1918000905829023199,31,-6305894971343174095 +1785,0,3382742654219329797,31,-8150037353246491299 +1786,0,-7668064903330744354,31,3678425035471889023 +1787,0,6592480311131388529,31,-1684080104444103879 +1788,0,3771018342787175035,31,-7411212478526226752 +1789,0,-9209379343054099077,31,-1425638560555909011 +1790,0,8809433506817785437,31,-5243268023550557673 +1791,0,3622962127039251936,31,-5221208362821915133 +1792,0,4637085440835592271,31,2096414261058407013 +1793,0,6356420981957532639,31,6590930473450618644 +1794,0,-6037359062089609360,31,-1447617956637916758 +1795,0,2809649815120543037,31,2605101715248622905 +1796,0,4910545367671356353,31,8521422131988838314 +1797,0,-3641944013579376181,31,4717422591657921100 +1798,0,-4828543933815929748,31,7112935614590408476 +1799,0,-816942255851701146,31,5504255244144381136 +1800,0,4500737028494484698,31,2703471418426746587 +1801,0,-5360859409398459244,31,-1849204735662572729 +1802,0,-980188011105516319,31,-6195253884367460474 +1803,0,-5341147405229376051,31,-3500539620297278876 +1804,0,-5059204503101732424,31,8611238116462576624 +1805,0,2323241341608001835,31,-6286081010780504374 +1806,0,-7234489726660109408,31,-985710239526483106 +1807,0,-4399342489059768231,31,5125144516167589185 +1808,0,568957892278445175,31,5700845991765348177 +1809,0,-3128288682699716902,31,3697138142519358175 +1810,0,268059501110939604,31,-8893977446285428974 +1811,0,8869377529779418169,31,-4325040926100297691 +1812,0,-5191201845817789231,31,3897865352497137113 +1813,0,8742584095090015507,31,2164085756305823191 +1814,0,-1833031289184026905,31,8085579027974396611 +1815,0,441773167769005703,31,4694278697122468011 +1816,0,-2862985803782167939,31,4130221519996438564 +1817,0,-2217136279577453892,31,1094010903841477278 +1818,0,-4699777063743038799,31,2227435701301549010 +1819,0,2319030942204069894,31,935055964128355319 +1820,0,-3096829301818651315,31,2310785379231547412 +1821,0,2152089781530614740,31,-8764487801483848056 +1822,0,3591093109998414360,31,4839519040668557725 +1823,0,3737787276968062484,31,-5898811489432266178 +1824,0,-2075424185432267668,31,6383690336645412166 +1825,0,-1313631551970774685,31,3565292039313471062 +1826,0,-4919910057472342658,31,-7641448313491827103 +1827,0,-1163170530272854872,31,8425166256265357179 +1828,0,-3783140882996568908,31,905701998180266649 +1829,0,-8037533461827223438,31,-8950538973460282255 +1830,0,5147544332470383179,31,-2463525637753851406 +1831,0,1327994358379982364,31,4354904019192170400 +1832,0,4326125443692555139,31,284421042634062361 +1833,0,-1720554764987678589,31,4892087311193379392 +1834,0,-6224447350716142955,31,-8452729761746602354 +1835,0,-3664233167161816084,31,-8868318481588889392 +1836,0,-1358465093069484872,31,-1205088561733274087 +1837,0,-3170767669678732241,31,-7887008844221361350 +1838,0,3175800087146479659,31,6373312549986753272 +1839,0,-16337625285930414,31,98603530532231278 +1840,0,4460646835363181976,31,970735867522443305 +1841,0,-6184155055121584051,31,-6790952656974165768 +1842,0,8105205207275831311,31,-6467380891195390340 +1843,0,364645839147141988,31,-4748346748827166214 +1844,0,-3252358421106878137,31,-501139711161959672 +1845,0,-2379855386905973850,31,3966484485493264693 +1846,0,-717996509442787349,31,-6462239688008245292 +1847,0,7039157268142466226,31,1069541988740086264 +1848,0,8799412946070712593,31,-7182562687400323988 +1849,0,-2256794007843286070,31,147711710721127323 +1850,0,-3026828459050443467,31,3379785835928552073 +1851,0,6316354959643887085,31,2960110364961921893 +1852,0,-632743241481339103,31,-2227702709481377040 +1853,0,9192761499170372867,31,-9081182024274851277 +1854,0,7519964503218211187,31,-4135042870406214546 +1855,0,-3171788476130391814,31,4712373415990342518 +1856,0,4205532823146854278,31,-2534946886377479727 +1857,0,6513522002710255853,31,627238506201675002 +1858,0,4968793986534390139,31,776258745940141998 +1859,0,7924914011447575185,31,-88138427101334235 +1860,0,3506146014983106198,31,7285244106196600168 +1861,0,8511722175131586351,31,7209360541568099687 +1862,0,-3535216109813816630,31,8392118739618597903 +1863,0,3043419627940964079,31,-4640925843933947468 +1864,0,1989151438749037821,31,-6255508612328682685 +1865,0,7233464223954842358,31,-9186097562718236848 +1866,0,-3249615372439963990,31,3335475242156930340 +1867,0,-8665368429824794064,31,-7965147053611014272 +1868,0,-648378579874199315,31,5267105097018046672 +1869,0,-4727955777856631607,31,-5249163549112889248 +1870,0,-3689595611110413143,31,-6522662492521672481 +1871,0,3856183988075237273,31,2323347357817503889 +1872,0,5517263844496266427,31,1146141647783339969 +1873,0,-2433339568447789451,31,5679451937807547608 +1874,0,6589509038357236405,31,8902423819375883944 +1875,0,-6774119612186335761,31,-2032691265600190313 +1876,0,-4350036823275823154,31,-1265503329615437742 +1877,0,5834187175154047558,31,-2632103032773131190 +1878,0,-3767301317720281706,31,-2781683061566382891 +1879,0,-8702001427232534750,31,1018921307670691574 +1880,0,94015559239255499,31,7916949762467282391 +1881,0,-4379700402807826,31,4206899959636749921 +1882,0,-1859937611212626430,31,-8045931040100117693 +1883,0,1226887111095682425,31,-3941690438579822629 +1884,0,-1185076345898896498,31,-6283044631699640296 +1885,0,-7829178625122620180,31,-8488917788225155618 +1886,0,-2280062727697501740,31,-5844484612536941131 +1887,0,2556040939242422304,31,7974065112426383767 +1888,0,6251964074628081557,31,8106390013091102783 +1889,0,3066879182290958720,31,7745056254168118633 +1890,0,-8785644387968277547,31,6435952490652331167 +1891,0,-4488264477615612586,31,4452371672649142046 +1892,0,8127606717194526874,31,-82894512397335432 +1893,0,4890787706249869594,31,-632020021525688409 +1894,0,6356833732756963227,31,-556619358497726752 +1895,0,5174834866809420309,31,7168560720601203033 +1896,0,2027973333647796824,31,6766687485899280526 +1897,0,8053801885705963745,31,-1154303600322654539 +1898,0,-6944307380006370243,31,5538956461691970234 +1899,0,3113788140330654611,31,3774380430471753700 +1900,0,-2986910451567880470,31,-5504138886798374012 +1901,0,2425903292748474372,31,-1374764015936545283 +1902,0,-1715269818440437717,31,3952112615212420399 +1903,0,74338710306223399,31,-276922063029302878 +1904,0,5132849055217923687,31,7445253821719567887 +1905,0,-6714922651557874917,31,8992509102706278863 +1906,0,-1476767669230945550,31,-7703377438265459229 +1907,0,6267869827386314060,31,3391332086701887068 +1908,0,2151492872494414422,31,872732985233182992 +1909,0,-188287405141817418,31,-1657879631628837662 +1910,0,-2396141142455784570,31,8290464187538430168 +1911,0,-6107851785102021570,31,-4625958300108875914 +1912,0,2899506268788328800,31,-8708826054006355267 +1913,0,-7955799538392167846,31,3610650757917829226 +1914,0,-8939834619099069255,31,8586242413033658589 +1915,0,-2962366035946053462,31,-958651567969169516 +1916,0,3123384032637701312,31,-6473228178822408648 +1917,0,-6706608866229291712,31,-6453274285204844140 +1918,0,-3500046218323398125,31,4922298068423641028 +1919,0,-168870750581166069,31,-1452137033153825144 +1920,0,694099585994227916,31,5006202836744454933 +1921,0,430038091926664816,31,-790697648027150885 +1922,0,1624356164486366102,31,6778822504400160702 +1923,0,4334130261304381128,31,1535104111221710884 +1924,0,-7324629223026415329,31,8411326554077441971 +1925,0,8823152808567544116,31,-6487013848902025905 +1926,0,-8620326148777841379,31,-2005073305527714823 +1927,0,-788126204987848665,31,-4805481930093449964 +1928,0,-8814182475375947241,31,-7879958326373771473 +1929,0,1080002348337528081,31,-338544756385086198 +1930,0,3043074730722911830,31,3098871859881491802 +1931,0,8234596790989448752,31,6628086393571689352 +1932,0,4608358602898896255,31,-6177312002235156148 +1933,0,2343398753207867914,31,-4120328157217959055 +1934,0,-266697139298886785,31,-5463360853010017143 +1935,0,-159260171872612558,31,3071594995007984771 +1936,0,4370044052923372524,31,6600329085852513910 +1937,0,-2995614366415980410,31,4672833865784124212 +1938,0,-4209600344306251016,31,-7789753773676878700 +1939,0,-8755371846184338683,31,718272277234239160 +1940,0,-3955855588499799050,31,-6844146748312167038 +1941,0,-6787638727374739702,31,-1233237931409433781 +1942,0,-8849461119575970289,31,-390755247167237953 +1943,0,8716688164664398086,31,481811035577917687 +1944,0,1514577502053504108,31,5039695554483411022 +1945,0,2240729936627952880,31,3448858575158592838 +1946,0,2838465136424227986,31,123814878937838237 +1947,0,-1487161195056206463,31,-2996367544782904676 +1948,0,-391895021770092123,31,5683555672792043726 +1949,0,-717250607935411377,31,-3262688710423361089 +1950,0,725101643113018626,31,-3726559379441563306 +1951,0,2018234564447318861,31,-6884696398111271373 +1952,0,-5254575322305083709,31,-7636712594119609410 +1953,0,4424742596549423606,31,-9213856503712030189 +1954,0,5662970072122589602,31,7480923596864276983 +1955,0,3130397907087802883,31,-51187779667968897 +1956,0,8049486087948419299,31,4780343312451051979 +1957,0,5557801586424368035,31,-2236986371758163167 +1958,0,-7085534093136275857,31,3681290757468590007 +1959,0,5600569740806125553,31,-4842298456914446401 +1960,0,4128462226512133482,31,-2192107235472315258 +1961,0,-1574925284503437735,31,-2069199851182505299 +1962,0,-5135068613676616410,31,-7629609827777296199 +1963,0,7314046845044324564,31,4069551071462281185 +1964,0,-3686747832999142812,31,-3621370023249150426 +1965,0,-1564972575538757040,31,5273910104372724723 +1966,0,1120348884617118977,31,-6061766741949054490 +1967,0,3412879446395492399,31,-7398045156012933074 +1968,0,6962651138322613963,31,-782405253113935984 +1969,0,877006726541596979,31,1511543206421977809 +1970,0,-7866734399584535627,31,6174855481331785609 +1971,0,8572173997988387711,31,3840867321444217521 +1972,0,3835382868124934929,31,-2280372101617370310 +1973,0,-2583877131516514905,31,-8825542946491095297 +1974,0,-5102649011667592384,31,-4816963967398761176 +1975,0,-4798459575624269557,31,1095689172902026547 +1976,0,-8156429235664983329,31,-958864743625550143 +1977,0,-6239845266330519720,31,-100876134841728387 +1978,0,-1914747524813276529,31,5300807882064630568 +1979,0,5363997714419355781,31,-346066207506269852 +1980,0,9210533546107024609,31,-7363744521473872639 +1981,0,-5245165629299500976,31,2232258552216575805 +1982,0,-5193672401549237041,31,-2113762116215105192 +1983,0,6597128830638074557,31,-3093361157581265591 +1984,0,-5969845161062876521,31,6180913678782091406 +1985,0,-2445089653030403139,31,-6684090657960000453 +1986,0,-4797981019593561429,31,-3125613786568519089 +1987,0,-1962888612492761260,31,-5447412418306369536 +1988,0,1803013398616297242,31,9047449907624155944 +1989,0,8744887681327442130,31,-1903114558378133059 +1990,0,5851196282496012008,31,3486289729716970858 +1991,0,892128523146305717,31,7249373956076981386 +1992,0,4170022229766562081,31,5943278435955384500 +1993,0,-2134478426920707338,31,1167185766207186701 +1994,0,1238027773513435748,31,-1240770407242611596 +1995,0,8866916391213127576,31,-1780526540309153532 +1996,0,-5827099544905007258,31,2857040368005011191 +1997,0,-1552818987126555097,31,-546086186170195027 +1998,0,1979982077379021084,31,4389538373894473402 +1999,0,3998394901457623548,31,-640954487257843677 +2000,0,2787580374700656688,31,153217449483067838 +2001,0,8372209727011402499,31,-4870401927830906950 +2002,0,3409775566082298245,31,-5056263359957356800 +2003,0,1114413850985679686,31,-9119470237143336509 +2004,0,-609417232397692848,31,-8411050498571767804 +2005,0,1762759225268672019,31,3252503569226423906 +2006,0,-378983625905076170,31,345051425424123093 +2007,0,7435306721054054073,31,-7586661297405315665 +2008,0,-5155196407132036358,31,4046131178537982053 +2009,0,-1668786196380559129,31,2983386022685252076 +2010,0,4519643915893375417,31,2681297491421176422 +2011,0,-8609870523645938036,31,3424900816108665122 +2012,0,8590593064246052287,31,-6223133567579654430 +2013,0,-7126254452521759890,31,1110620705559144917 +2014,0,-2826314600096007100,31,-4050043014658671535 +2015,0,1624568634286818020,31,-7324601638759360390 +2016,0,-450700576225246242,31,5869895845962199292 +2017,0,7539390560191158137,31,-6307795730042123956 +2018,0,-2188075991300573837,31,-4714400998474230150 +2019,0,-4681497720947957856,31,-2696920935225302099 +2020,0,-4688143896220383919,31,1070306854328751259 +2021,0,-4305920512968147039,31,5223541849580944308 +2022,0,2656654774987994840,31,-7499374986301963109 +2023,0,-4854606985975851256,31,-4952411436073368454 +2024,0,-5361383744936804655,31,-4046171465546574534 +2025,0,-8947485315238255267,31,2242969734918811843 +2026,0,3311598196079410229,31,-1517375733458352354 +2027,0,607952732017041432,31,-4454420856961501821 +2028,0,4481836561581728625,31,-7338967505278665913 +2029,0,1856670507280870266,31,-2114211903259591285 +2030,0,-8371889865268432118,31,-5014037997328088687 +2031,0,-794649732821127929,31,4023057612100664840 +2032,0,-6144467833645861578,31,4730183288314175119 +2033,0,-5870596264115217421,31,3636543208881771460 +2034,0,1547182795679877050,31,-5087030769322711975 +2035,0,3554393108243259363,31,-8804005408516186896 +2036,0,6096915670896392585,31,4441857404539621740 +2037,0,-7585113688284079403,31,-5791139904213933738 +2038,0,6283800140108182083,31,-8301261451536656721 +2039,0,7325444638523598785,31,-5925688893666427167 +2040,0,-2676741791420355695,31,8397228664090667004 +2041,0,7399210828703529226,31,9065314697901668098 +2042,0,-5153686314010544980,31,1414542467646697991 +2043,0,4553182987876882087,31,-8323584617414148073 +2044,0,-8475602433165535745,31,-3187678774597501009 +2045,0,-7549754731031245776,31,3798552692068437804 +2046,0,383864735074387336,31,-5956449531759319304 +2047,0,-1462360910626047142,31,-3647046316154688527 +2048,0,-2503433555198690048,31,-2570301041608687289 +2049,0,7124680608501705883,31,6352243651661792603 From 9281600d983a39f20ccc85776a5c35f8464e55dd Mon Sep 17 00:00:00 2001 From: jinhyukify Date: Wed, 11 Feb 2026 22:49:19 +0900 Subject: [PATCH 4/6] HBASE-29889 Add 64bit Bloom filter hash support --- .../hadoop/hbase/util/BloomFilterChunk.java | 17 ++--- .../hadoop/hbase/util/BloomFilterUtil.java | 32 ++++++++- .../hbase/util/TestBloomFilterUtil.java | 68 +++++++++++++++++++ 3 files changed, 104 insertions(+), 13 deletions(-) create mode 100644 hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestBloomFilterUtil.java diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterChunk.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterChunk.java index bc0ca0490932..def827859976 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterChunk.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterChunk.java @@ -161,9 +161,7 @@ void add(byte[] buf, int offset, int len) { * http://www.eecs.harvard.edu/~kirsch/pubs/bbbf/esa06.pdf */ HashKey hashKey = new ByteArrayHashKey(buf, offset, len); - int hash1 = this.hash.hash(hashKey, 0); - int hash2 = this.hash.hash(hashKey, hash1); - setHashLoc(hash1, hash2); + setHashLoc(hashKey); } public void add(Cell cell) { @@ -171,22 +169,19 @@ public void add(Cell cell) { * For faster hashing, use combinatorial generation * http://www.eecs.harvard.edu/~kirsch/pubs/bbbf/esa06.pdf */ - int hash1; - int hash2; HashKey hashKey; if (this.bloomType == BloomType.ROWCOL) { hashKey = new RowColBloomHashKey(cell); - hash1 = this.hash.hash(hashKey, 0); - hash2 = this.hash.hash(hashKey, hash1); } else { hashKey = new RowBloomHashKey(cell); - hash1 = this.hash.hash(hashKey, 0); - hash2 = this.hash.hash(hashKey, hash1); } - setHashLoc(hash1, hash2); + setHashLoc(hashKey); } - private void setHashLoc(int hash1, int hash2) { + private void setHashLoc(HashKey hashKey) { + Pair hashPair = BloomFilterUtil.getHashPair(this.hash, hashKey); + final int hash1 = hashPair.getFirst(); + final int hash2 = hashPair.getSecond(); for (int i = 0; i < this.hashCount; i++) { long hashLoc = Math.abs((hash1 + i * hash2) % (this.byteSize * 8)); set(hashLoc); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterUtil.java index 5b24a2714747..571dd6489546 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterUtil.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/BloomFilterUtil.java @@ -179,7 +179,8 @@ public static boolean contains(byte[] buf, int offset, int length, ByteBuff bloo private static boolean contains(ByteBuff bloomBuf, int bloomOffset, int bloomSize, Hash hash, int hashCount, HashKey hashKey) { - int hash1 = hash.hash(hashKey, 0); + Pair hashPair = getHashPair(hash, hashKey); + int hash1 = hashPair.getFirst(); int bloomBitSize = bloomSize << 3; int hash2 = 0; @@ -188,7 +189,7 @@ private static boolean contains(ByteBuff bloomBuf, int bloomOffset, int bloo if (randomGeneratorForTest == null) { // Production mode compositeHash = hash1; - hash2 = hash.hash(hashKey, hash1); + hash2 = hashPair.getSecond(); } for (int i = 0; i < hashCount; i++) { @@ -278,4 +279,31 @@ public static byte[] getBloomFilterParam(BloomType bloomFilterType, Configuratio } return bloomParam; } + + /** + * Generate the two hash values needed for Bloom filter index generation. Bloom filters require a + * (hash1, hash2) pair to derive multiple probe locations. + *

    + *
  • If the hash implementation provides a 64-bit hash, we split the 64-bit value into two + * 32-bit hashes to avoid extra hashing cost.
  • + *
  • Otherwise, fall back to classic double hashing by rehashing with hash1 as the seed.
  • + *
+ * @param hash the hash function + * @param key the hash key + * @return a pair of hash values (hash1, hash2) + */ + public static Pair getHashPair(Hash hash, HashKey key) { + if (hash instanceof Hash64) { + long hash64 = ((Hash64) hash).hash64(key); + // Use lower 32 bits as first hash, upper 32 bits as second hash. + int hash1 = (int) hash64; + int hash2 = (int) (hash64 >>> 32); + return Pair.newPair(hash1, hash2); + } else { + // Use double hashing + int hash1 = hash.hash(key, 0); + int hash2 = hash.hash(key, hash1); + return Pair.newPair(hash1, hash2); + } + } } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestBloomFilterUtil.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestBloomFilterUtil.java new file mode 100644 index 000000000000..1583b6acf7c4 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestBloomFilterUtil.java @@ -0,0 +1,68 @@ +/* + * 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.hbase.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.testclassification.MiscTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.junit.ClassRule; +import org.junit.experimental.categories.Category; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@Category({ MiscTests.class, SmallTests.class }) +public class TestBloomFilterUtil { + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestBloomFilterUtil.class); + private HashKey hashKey; + + @BeforeEach + public void setup() { + byte[] SAMPLE_DATA = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + hashKey = new ByteArrayHashKey(SAMPLE_DATA, 0, SAMPLE_DATA.length); + } + + @Test + public void testGetHashPairHash64() { + Hash xxh3 = new XXH3(); + assertInstanceOf(Hash64.class, xxh3); + + long hash64 = ((Hash64) xxh3).hash64(hashKey); + Pair hashPair = BloomFilterUtil.getHashPair(xxh3, hashKey); + assertEquals((int) hash64, hashPair.getFirst()); + assertEquals((int) (hash64 >>> 32), hashPair.getSecond()); + } + + @Test + public void testGetHashPairDoubleHashing() { + Hash murmurHash = new MurmurHash(); + assertFalse(murmurHash instanceof Hash64); + + int expectedHash1 = murmurHash.hash(hashKey, 0); + int expectedHash2 = murmurHash.hash(hashKey, expectedHash1); + + Pair hashPair = BloomFilterUtil.getHashPair(murmurHash, hashKey); + assertEquals(expectedHash1, hashPair.getFirst()); + assertEquals(expectedHash2, hashPair.getSecond()); + } +} From db169a0d3b56f6a71de9246d277ab0dcd91c6d54 Mon Sep 17 00:00:00 2001 From: jinhyukify Date: Wed, 11 Feb 2026 22:50:44 +0900 Subject: [PATCH 5/6] HBASE-29889 Add XXH3 to Bloom filter hashing --- .../src/main/java/org/apache/hadoop/hbase/util/Hash.java | 9 ++++++++- .../hadoop/hbase/io/hfile/CompoundBloomFilter.java | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash.java index d692d712dcdd..ce14f1fb7260 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Hash.java @@ -35,10 +35,13 @@ public abstract class Hash { public static final int MURMUR_HASH = 1; /** Constant to denote {@link MurmurHash3}. */ public static final int MURMUR_HASH3 = 2; + /** Constant to denote {@link XXH3}. */ + public static final int XXH3_HASH = 3; /** * This utility method converts String representation of hash function name to a symbolic - * constant. Currently three function types are supported, "jenkins", "murmur" and "murmur3". + * constant. Currently three function types are supported, "jenkins", "murmur", "murmur3" and + * "xxh3". * @param name hash function name * @return one of the predefined constants */ @@ -49,6 +52,8 @@ public static int parseHashType(String name) { return MURMUR_HASH; } else if ("murmur3".equalsIgnoreCase(name)) { return MURMUR_HASH3; + } else if ("xxh3".equalsIgnoreCase(name)) { + return XXH3_HASH; } else { return INVALID_HASH; } @@ -77,6 +82,8 @@ public static Hash getInstance(int type) { return MurmurHash.getInstance(); case MURMUR_HASH3: return MurmurHash3.getInstance(); + case XXH3_HASH: + return XXH3.getInstance(); default: return null; } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CompoundBloomFilter.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CompoundBloomFilter.java index b1cb519fb585..617a034d118c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CompoundBloomFilter.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CompoundBloomFilter.java @@ -19,6 +19,7 @@ import java.io.DataInput; import java.io.IOException; +import java.util.Optional; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.HBaseInterfaceAudience; import org.apache.hadoop.hbase.nio.ByteBuff; @@ -217,6 +218,9 @@ public String toString() { sb.append(BloomFilterUtil.STATS_RECORD_SEP + ((comparator != null) ? "Comparator: " + comparator.getClass().getSimpleName() : "Comparator: " + Bytes.BYTES_RAWCOMPARATOR.getClass().getSimpleName())); + sb.append(BloomFilterUtil.STATS_RECORD_SEP + "Hash type: " + hashType) + .append(" (" + Optional.ofNullable(Hash.getInstance(hashType)) + .map(i -> i.getClass().getSimpleName()).orElse("UNKNOWN") + ")"); return sb.toString(); } From 53f0315bf82880cc439f5c3860c2f8f4cf928320 Mon Sep 17 00:00:00 2001 From: jinhyukify Date: Fri, 13 Feb 2026 20:44:00 +0900 Subject: [PATCH 6/6] HBASE-29889 Fix CI failure --- .../org/apache/hadoop/hbase/util/XXH3.java | 21 +++++++++++++------ .../apache/hadoop/hbase/util/TestXXH3.java | 3 +++ .../src/test/resources/xxh3/README.md | 19 +++++++++++++++++ .../src/test/resources/xxh3/xxh3_vectors.csv | 21 +++++++++++++++++++ 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java index 51c029f016af..14a388b24ef1 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/XXH3.java @@ -119,10 +119,14 @@ public class XXH3 extends Hash implements Hash64 { private static final long DEFAULT_SECRET_BITFLIP_0 = ((DEFAULT_SECRET_LONG_0 >>> 32) ^ (DEFAULT_SECRET_LONG_0 & MASK32)); - private static final long DEFAULT_SECRET_BITFLIP_1 = (DEFAULT_SECRET_LONG_1 ^ DEFAULT_SECRET_LONG_2); - private static final long DEFAULT_SECRET_BITFLIP_2 = (DEFAULT_SECRET_LONG_3 ^ DEFAULT_SECRET_LONG_4); - private static final long DEFAULT_SECRET_BITFLIP_3 = (DEFAULT_SECRET_LONG_5 ^ DEFAULT_SECRET_LONG_6); - private static final long DEFAULT_SECRET_BITFLIP_4 = (DEFAULT_SECRET_LONG_7 ^ DEFAULT_SECRET_LONG_8); + private static final long DEFAULT_SECRET_BITFLIP_1 = + (DEFAULT_SECRET_LONG_1 ^ DEFAULT_SECRET_LONG_2); + private static final long DEFAULT_SECRET_BITFLIP_2 = + (DEFAULT_SECRET_LONG_3 ^ DEFAULT_SECRET_LONG_4); + private static final long DEFAULT_SECRET_BITFLIP_3 = + (DEFAULT_SECRET_LONG_5 ^ DEFAULT_SECRET_LONG_6); + private static final long DEFAULT_SECRET_BITFLIP_4 = + (DEFAULT_SECRET_LONG_7 ^ DEFAULT_SECRET_LONG_8); public static Hash getInstance() { return _instance; @@ -195,6 +199,7 @@ private static long rrmxmx(long hash, int inputLength) { } private static long mul128AndFold64(long x, long y) { + // Consider switching to Math.unsignedMultiplyHigh(x, y) when we can drop Java 8. long xLow = x & MASK32; long xHigh = x >>> 32; long yLow = y & MASK32; @@ -282,10 +287,12 @@ private long hashSmall(HashKey hashKey, int length, long seed) { return hashEmpty(seed); } + @edu.umd.cs.findbugs.annotations.SuppressWarnings( + value = { "SF_SWITCH_FALLTHROUGH", "SF_SWITCH_NO_DEFAULT" }, justification = "Intentional") private long hashLength17To128(HashKey hashKey, int length, long seed) { assert length >= 17 && length <= 128; long acc = length * PRIME64_1; - switch ((length - 1) / 32) { + switch ((length - 1) / 32) { // all case statements fall through case 3: acc += mix16(hashKey, 48, DEFAULT_SECRET_LONG_12, DEFAULT_SECRET_LONG_13, seed); acc += mix16(hashKey, length - 64, DEFAULT_SECRET_LONG_14, DEFAULT_SECRET_LONG_15, seed); @@ -304,6 +311,8 @@ private long hashLength17To128(HashKey hashKey, int length, long seed) { return avalanche(acc); } + @edu.umd.cs.findbugs.annotations.SuppressWarnings( + value = { "SF_SWITCH_FALLTHROUGH", "SF_SWITCH_NO_DEFAULT" }, justification = "Intentional") private long hashLength129To240(HashKey hashKey, int length, long seed) { assert length >= 129 && length <= 240; long acc = length * PRIME64_1; @@ -319,7 +328,7 @@ private long hashLength129To240(HashKey hashKey, int length, long seed) { acc = avalanche(acc); - switch ((length - 128) >> 4) { + switch ((length - 128) >> 4) { // all case statements fall through case 7: acc += mix16(hashKey, 16 * 14, DEFAULT_SECRET_3_LONG_12, DEFAULT_SECRET_3_LONG_13, seed); case 6: diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java index bab3ad35ae06..37e3ebfc34b2 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestXXH3.java @@ -63,6 +63,9 @@ static Stream vectors() throws Exception { List out = new ArrayList<>(4096); br.lines().filter(s -> !s.isEmpty()).forEach(line -> { + if (line.startsWith("#")) { + return; + } String[] p = line.split(","); int len = Integer.parseInt(p[0]); diff --git a/hbase-common/src/test/resources/xxh3/README.md b/hbase-common/src/test/resources/xxh3/README.md index c8266982c01e..e24170da9a67 100644 --- a/hbase-common/src/test/resources/xxh3/README.md +++ b/hbase-common/src/test/resources/xxh3/README.md @@ -1,3 +1,22 @@ + + # Generating XXH3 Test Vectors This snippet shows how to generate test vectors for the XXH3 hash function using the upstream implementation. diff --git a/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv b/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv index 57fbdb1147ab..27f36e3348f1 100644 --- a/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv +++ b/hbase-common/src/test/resources/xxh3/xxh3_vectors.csv @@ -1,3 +1,24 @@ +# +# 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. +# +# This file describes 'Actions' that should be taken for the specified git commit. As new commits +# land in the repo that have commit messages that are not recognized by the regular expressions +# in the application, this file provides overrides on a per-sha basis. +# 0,0,3244421341483603138,31,-5533455083687115210 1,0,-4302098779834749733,31,-8203419927524778795 2,0,-2998166160713018281,31,507397404195618438