/* * Copyright 2009-2016 Tilmann Zaeschke. All rights reserved. * * This file is part of ZooDB. * * ZooDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ZooDB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZooDB. If not, see <http://www.gnu.org/licenses/>. * * See the README and COPYING files for further information. */ package org.zoodb.test.index; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Random; import org.junit.Test; import org.zoodb.internal.server.index.BitTools; public class TestBitTools { @Test public void testMinMaxBug() { String s0 = ""; String s1 = "1"; String s2 = "A"; String s3 = "" + (char)142; // A-Umlaut, negative char-value! String s4 = "djfls7582943(*&*(a"; testMinMaxSubEq(s0, "xyz"); testMinMaxSub(s1, "1234567890"); testMinMaxSub(s2, "Alice"); testMinMaxSub(s3, s3 + "xxx"); testMinMaxSub(s4, s4 + "xxx"); } private void testMinMaxSubEq(String pre, String str) { long l0 = BitTools.toSortableLongPrefixMinHash(pre); long l1 = BitTools.toSortableLong(pre); long l2 = BitTools.toSortableLong(str); long l3 = BitTools.toSortableLongPrefixMaxHash(pre); assertTrue("" + l0 + " > " + l1, l0 <= l1 ); assertTrue("" + l1 + " > " + l2, l1 <= l2 ); assertTrue("" + l2 + " > " + l3, l2 <= l3 ); } private void testMinMaxSub(String pre, String str) { long l0 = BitTools.toSortableLongPrefixMinHash(pre); long l1 = BitTools.toSortableLong(pre); long l2 = BitTools.toSortableLong(str); long l3 = BitTools.toSortableLongPrefixMaxHash(pre); assertTrue("" + l0 + " > " + l1, l0 < l1 ); assertTrue("" + l0 + " > " + l2, l0 < l2 ); //This does not need to be true //assertTrue("" + l1 + " > " + l2, l1 < l2 ); assertTrue("" + l1 + " > " + l3, l1 < l3 ); assertTrue("" + l2 + " > " + l3, l2 < l3 ); } @Test public void testSorting() { String[] sa = { "1", "2", "3", "Msdfjdfa", "max", "maxmaxmax", "maxmaxmax@@@", "n" }; for (int i = 1; i < sa.length; i++) { long l0 = BitTools.toSortableLong(sa[i-1]); long l1 = BitTools.toSortableLong(sa[i]); assertTrue("" + sa[i-1] + " !< " + sa[i], l0 < l1 ); } } @Test public void testSortingDouble() { double[] sa = { -231.3, -12., -1.1, -0.0232, -0.0001, -0.0, 0., 0.0001, 0.002, 1, 12, 1231 }; for (int i = 1; i < sa.length; i++) { long l0 = BitTools.toSortableLong(sa[i-1]); long l1 = BitTools.toSortableLong(sa[i]); assertTrue("" + sa[i-1] + " !< " + sa[i] + " --- " + l0 + " !< " + l1, l0 < l1 ); } } /** * Test that sorting is still correct even if only the mantissa changes. */ @Test public void testSortingDoubleMantissa() { double[] sa = { -2.31121, -2.3112, -2.3111, -0.0, 0.0, 0.0001, 0.0002, 0.00021, 1231.1, 1231.11 }; for (int i = 1; i < sa.length; i++) { long l0 = BitTools.toSortableLong(sa[i-1]); long l1 = BitTools.toSortableLong(sa[i]); assertTrue("" + sa[i-1] + " !< " + sa[i] + " --- " + l0 + " !< " + l1, l0 < l1 ); } } @Test public void testSymmetryDouble() { double[] sa = { -231.3, -12., -1.1, -0.0232, -0.0001, -0.0, 0., 0.0001, 0.002, 1, 12, 1231 }; for (double d0: sa) { checkSymmetry(d0); } checkSymmetry(Double.MAX_VALUE); checkSymmetry(Double.MIN_VALUE); checkSymmetry(Double.MIN_NORMAL); checkSymmetry(Double.NaN); checkSymmetry(1./0.); checkSymmetry(-1./0.); checkSymmetry(-0.0); checkSymmetry(0.0); } private void checkSymmetry(double d) { long l = BitTools.toSortableLong(d); double d2 = BitTools.toDouble(l); if (Double.isNaN(d) && Double.isNaN(d2)) { return; //ok } assertTrue( d + " != " + d2 + " l=" + l, d == d2 ); } @Test public void testSortingFloat() { float[] sa = { -231.3f, -12f, -1.1f, -0.0232f, -0.0001f, -0.0f, 0f, 0.0001f, 0.002f, 1, 12, 1231 }; for (int i = 1; i < sa.length; i++) { long l0 = BitTools.toSortableLong(sa[i-1]); long l1 = BitTools.toSortableLong(sa[i]); assertTrue("" + sa[i-1] + " !< " + sa[i] + " --- " + l0 + " !< " + l1, l0 < l1 ); } } @Test public void testSymmetryFloat() { float[] sa = { -231.3f, -12f, -1.1f, -0.0232f, -0.0001f, 0f, 0.0001f, 0.002f, 1, 12, 1231 }; for (float d0: sa) { checkSymmetry(d0); } checkSymmetry(Float.MAX_VALUE); checkSymmetry(Float.MIN_VALUE); checkSymmetry(Float.MIN_NORMAL); checkSymmetry(Float.NaN); checkSymmetry(1.f/0.f); checkSymmetry(-1.f/0.f); checkSymmetry(-0.0f); checkSymmetry(0.0f); } /** * Check whether the input value matches the output value, i.e. whether encoding and decoding * a value results in the original value. * @param d */ private void checkSymmetry(float d) { long l = BitTools.toSortableLong(d); float d2 = BitTools.toFloat(l); if (Float.isNaN(d) && Float.isNaN(d2)) { return; //ok } assertTrue( d + " != " + d2 + " l=" + l, d == d2 ); } @Test public void testRandom() { Random R = new Random(0); int N = 10000; double[] da = new double[N]; long[] la = new long[da.length]; for (int i = 0; i < da.length; i++) { da[i] = (R.nextDouble()*2-1)*Double.MAX_VALUE; la[i] = BitTools.toSortableLong(da[i]); } Arrays.sort(da); Arrays.sort(la); for (int i = 0; i < da.length; i++) { assertTrue(BitTools.toDouble(la[i]) + " / " + da[i], Math.abs(BitTools.toDouble(la[i])-da[i]) < Double.MAX_VALUE); } } }