/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program 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; version 2 of the License.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Feb 3, 2007
*/
package com.bigdata.btree.keys;
import java.util.Arrays;
import junit.framework.TestCase2;
/**
* Test suite for {@link SuccessorUtil}.
*
* @todo finish the double precision tests per the single precision tests, e.g.,
* for successor(double), etc.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
*/
public class TestSuccessorUtil extends TestCase2 {
/**
*
*/
public TestSuccessorUtil() {
}
/**
* @param name
*/
public TestSuccessorUtil(String name) {
super(name);
}
public void test_float_data_points() {
// positive value space.
assertTrue(SuccessorUtil.FPOS_ZERO<SuccessorUtil.FPOS_MAX);
assertTrue(SuccessorUtil.FPOS_ZERO<SuccessorUtil.FPOS_MIN);
assertTrue(SuccessorUtil.FPOS_MIN<SuccessorUtil.FPOS_ONE);
// negative value space.
assertTrue(SuccessorUtil.FNEG_MIN>SuccessorUtil.FNEG_MAX);
assertTrue(SuccessorUtil.FNEG_ZERO>SuccessorUtil.FNEG_MIN);
assertTrue(SuccessorUtil.FNEG_MIN>SuccessorUtil.FNEG_ONE);
/*
* Note: +0f and -0f will compare as _equal_ in the language. This means
* that you can not write tests that directly distinguish positive and
* negative zero using >, <, or ==.
*/
assertTrue(SuccessorUtil.FNEG_ZERO == SuccessorUtil.FPOS_ZERO);
}
public void test_double_data_points() {
// positive value space.
assertTrue(SuccessorUtil.DPOS_ZERO<SuccessorUtil.DPOS_MAX);
assertTrue(SuccessorUtil.DPOS_ZERO<SuccessorUtil.DPOS_MIN);
assertTrue(SuccessorUtil.DPOS_MIN<SuccessorUtil.DPOS_ONE);
// negative value space.
assertTrue(SuccessorUtil.DNEG_MIN>SuccessorUtil.DNEG_MAX);
assertTrue(SuccessorUtil.DNEG_ZERO>SuccessorUtil.DNEG_MIN);
assertTrue(SuccessorUtil.DNEG_MIN>SuccessorUtil.DNEG_ONE);
/*
* Note: +0f and -0f will compare as _equal_ in the language. This means
* that you can not write tests that directly distinguish positive and
* negative zero using >, <, or ==.
*/
assertTrue(SuccessorUtil.DNEG_ZERO == SuccessorUtil.DPOS_ZERO);
}
// /**
// * The double precision number that is one less than zero in the double
// * precision value space.
// */
// final protected double dm1 = Double.longBitsToDouble(UnicodeKeyBuilder.d2l(0d)-1);
//
// /**
// * The double precision number that is one more than zero in the double
// * precision value space.
// */
// final protected double DPOS_ONE = Double.longBitsToDouble(UnicodeKeyBuilder.d2l(0d)-1);
/**
* The value space for <code>float</code> and <code>double</code> is
* complex. The "next" floating point value is defined in terms of the next
* bit pattern for the underlying floating point representation. Also, we
* have to be aware of the trade off between precision and magnitude, the
* maximum expressible value, NaNs, positive and negative infinity, etc.
* <p>
*
* First we verify the data that we are going to use in the test. Each of
* these asserts verifies that a bit pattern, expressed as an int, is
* equilivant to the specified float. This SHOULD be true, but it is down to
* the metal enough to make it worth checking.
* <p>
*
* These test data were derived from: <a
* href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">
* Comparing floating point numbers </a> by Bruce Dawson.
*/
public void test_keyBuilder_successor_float_data()
{
assertZeroUlps
( 1.99999976f, // 0x3FFFFFFE
Float.intBitsToFloat( 1073741822 )
);
assertZeroUlps
( 1.99999988f, // 0x3FFFFFFF
Float.intBitsToFloat( 1073741823 )
);
assertZeroUlps
( 2.00000000f, // 0x40000000
Float.intBitsToFloat( 1073741824 )
);
assertZeroUlps
( 2.00000024f, // 0x40000001
Float.intBitsToFloat( 1073741825 )
);
assertZeroUlps
( 2.00000048f, // 0x40000002
Float.intBitsToFloat( 1073741826 )
);
}
/**
* Now verify the successor for each of the data points that we
* verified in the previous test as being successors in the float
* value space.
*/
public void test_keyBuilder_successor_float_positiveValue()
throws NoSuccessorException
{
assertZeroUlps(1.99999988f, SuccessorUtil.successor(1.99999976f));
assertZeroUlps(2.00000000f, SuccessorUtil.successor(1.99999988f));
assertZeroUlps(2.00000024f, SuccessorUtil.successor(2.00000000f));
assertZeroUlps(2.00000048f, SuccessorUtil.successor(2.00000024f));
}
/**
* Test a few values from the middle of the negative region of the value
* space. The successor is formed by subtracting one from the integer
* representation when in the negative value space.
*/
public void test_keyBuilder_successor_float_negativeValue()
throws NoSuccessorException
{
float neg1 = Float.intBitsToFloat(0x81111111);
float neg2 = Float.intBitsToFloat(0x81111110);
System.err.println("neg1="+neg1);
System.err.println("neg2="+neg2);
assertTrue("neg1<neg2", neg1<neg2);
assertZeroUlps(neg2, SuccessorUtil.successor(neg1));
}
/**
* Verifies some data points that we use in the next test. These test data
* were derived from:
*
* <a
* href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm">
* Comparing floating point numbers </a> by Bruce Dawson.
*/
public void test_keyBuilder_successor_float_nearZero_data()
{
assertZeroUlps
( 4.2038954e-045f, // 0x00000003
Float.intBitsToFloat( 3 )
);
assertZeroUlps
( 2.8025969e-045f, // 0x00000002
Float.intBitsToFloat( 2 )
);
assertZeroUlps
( 1.4012985e-045f, // 0x00000001
Float.intBitsToFloat( 1 )
);
assertZeroUlps
( +0.00000000f, // 0x00000000
Float.intBitsToFloat( 0 )
);
assertZeroUlps
( -0.00000000f, // 0x80000000
Float.intBitsToFloat( -2147483648 )
);
// Note: -0.0f and +0.0f are often conflated by the language.
// assertTrue( +0.00000000f != // 0x00000000
// -0.00000000f // 0x80000000
// );
//
// assertEquals(1,
// getUlps( +0.00000000f, // 0x00000000
// -0.00000000f) // 0x80000000
// );
assertZeroUlps
( -1.4012985e-045f, // 0x80000001
Float.intBitsToFloat( -2147483647 )
);
assertZeroUlps
( -2.8025969e-045f, // 0x80000002
Float.intBitsToFloat( -2147483646 )
);
assertZeroUlps
( -4.2038954e-045f, // 0x80000003
Float.intBitsToFloat( -2147483645 )
);
}
/**
* Verifies that the successor function imposes the correct ordering as we
* approach and cross zero from the positive region of the value space into
* the negative region of the value space. Note that the value set includes
* not only the finite nonzero values, NaN values, and positive infinity,
* and negative infinity, but also positive zero and negative zero, which
* Java hides from you most of the time since positive zero and negative
* zero compare as equals (for Java).
* <p>
*
* Note: The data points used in this test are verified by the previous
* test.
* <p>
*/
public void test_keyBuilder_successor_float_nearZero()
throws NoSuccessorException
{
// assertEquals
// ( 4.2038954e-045f, // 0x00000003
// Float.intBitsToFloat( 3 )
// );
/*
* successor of small positive numbers.
*/
assertZeroUlps
( 4.2038954e-045f, // 0x00000003
SuccessorUtil.successor( 2.8025969e-045f ) // 0x00000002
);
assertZeroUlps
( 2.8025969e-045f, // 0x00000002
SuccessorUtil.successor( 1.4012985e-045f) // 0x00000001
);
assertZeroUlps
( 1.4012985e-045f, // 0x00000001
SuccessorUtil.successor( +0.00000000f) // 0x00000000
);
/*
* successor of negative zero is positive zero.
*/
assertTrue(-0.00000000f == Float.intBitsToFloat(0x80000000));
assertEquals(Float.intBitsToFloat(0x00000000), SuccessorUtil
.successor(Float.intBitsToFloat(0x80000000)));
assertZeroUlps
( +0.00000000f, // 0x00000000
SuccessorUtil.successor( -0.00000000f ) // 0x80000000
);
/*
* successor of small negative numbers.
*/
assertZeroUlps
( -0.00000000f, // 0x80000000
SuccessorUtil.successor( -1.4012985e-045f ) // 0x80000001
);
assertZeroUlps
( -0.00000000f, // 0x80000000
SuccessorUtil.successor( -1.4012985e-045f ) // 0x80000001
);
assertZeroUlps
( -1.4012985e-045f, // 0x80000001
SuccessorUtil.successor( -2.8025969e-045f ) // 0x80000002
);
}
/**
* Verifies that the successor of the penultimate float is
* correct.
*/
public void test_keyBuilder_successor_float_penultimateValue()
throws NoSuccessorException
{
int maxValueAsInt = Float.floatToIntBits(Float.MAX_VALUE);
float penultimateValue = Float.intBitsToFloat(maxValueAsInt - 1);
assertZeroUlps(Float.MAX_VALUE, SuccessorUtil.successor(penultimateValue));
}
/**
* Verifies that successor of the maximum float value is positive infinity.
*/
public void test_keyBuilder_successor_float_maxValue()
throws NoSuccessorException
{
assertZeroUlps(Float.POSITIVE_INFINITY, SuccessorUtil
.successor(Float.MAX_VALUE));
}
/**
* Verifies that there is no successor for a NaN.
*/
public void test_keyBuilder_successor_float_NaN() {
try {
SuccessorUtil.successor(Float.NaN);
fail("Expecting: " + NoSuccessorException.class);
} catch (NoSuccessorException ex) {
System.err.println("Ignoring expected exception: " + ex);
}
}
/**
* Verifies that there is no successor for negative infinity.
*
* @todo Alternatively, we could make the successor the largest
* negative floating point value - if we knew what that was.
*/
public void test_keyBuilder_successor_float_negativeInfinity()
{
try {
SuccessorUtil.successor(Float.NEGATIVE_INFINITY);
fail("Expecting: " + NoSuccessorException.class);
} catch (NoSuccessorException ex) {
System.err.println("Ignoring expected exception: " + ex);
}
}
/**
* Verifies that there is no successor for positive infinity.
*/
public void test_keyBuilder_successor_float_positiveInfinity()
{
try {
SuccessorUtil.successor(Float.POSITIVE_INFINITY);
fail("Expecting: " + NoSuccessorException.class);
} catch (NoSuccessorException ex) {
System.err.println("Ignoring expected exception: " + ex);
}
}
/**
* Test computation of the successor of a fixed length bit string.
*/
public void test_bitString_successor() {
// simplest case
{
// original data.
byte[] b = new byte[]{0x00};
// successor.
byte[] s = SuccessorUtil.successor(b.clone());
// expected successor.
byte[] e = new byte[]{0x01};
assertEquals(e,s);
}
// successor of the smallest value.
{
// original data.
byte[] b = new byte[]{Byte.MIN_VALUE};
// successor.
byte[] s = SuccessorUtil.successor(b.clone());
// expected successor.
byte[] e = new byte[]{Byte.MIN_VALUE+1};
assertEquals(e,s);
}
// handle overflow in the 1st byte.
{
// original data.
// byte[] b = new byte[]{0x00,Byte.MAX_VALUE};
byte[] b = new byte[]{0x00,-1};
// successor.
byte[] s = SuccessorUtil.successor(b.clone());
System.err.println("b: "+Arrays.toString(b));
System.err.println("s: "+Arrays.toString(s));
// expected successor.
// byte[] e = new byte[]{0x01,Byte.MIN_VALUE};
byte[] e = new byte[]{0x01,0x00};
assertEquals(e,s);
}
// no successor - byte[0].
{
// original data.
byte[] b = new byte[]{};
// successor.
try {
SuccessorUtil.successor(b.clone());
fail("Expecting: " + NoSuccessorException.class);
} catch (NoSuccessorException ex) {
System.err.println("Ignoring expected exception: "+ex);
}
}
// no successor - byte[1].
{
// original data.
// byte[] b = new byte[]{Byte.MAX_VALUE};
byte[] b = new byte[]{-1};
// successor.
try {
SuccessorUtil.successor(b.clone());
fail("Expecting: " + NoSuccessorException.class);
} catch (NoSuccessorException ex) {
System.err.println("Ignoring expected exception: "+ex);
}
}
// compare behavior with (int+1)
{
// Random r = new Random();
// int LIMIT = 100000;
// int LIMIT = 1;
// System.err.println("-1: " + Integer.toBinaryString(-1));
// System.err.println("MAX_BYTE: " + Integer.toBinaryString(Byte.MAX_VALUE));
// System.err.println("MIN_BYTE: " + Integer.toBinaryString(Byte.MIN_VALUE));
for(int i=Short.MIN_VALUE; i<=Short.MAX_VALUE; i++) {
// int v = r.nextInt();
// int v = 1197420429;
// int v = -1950493185;
short v = (short)i;
// short v = -1;
// original data.
byte[] b = TestKeyBuilder.asSortKey(v);
if(true){
boolean allones = true;
for(int k=0;k<b.length;k++) {
if(b[k]!=-1) allones = false;
}
if(allones) {
System.err.println("short "+v+" is all ones.");
}}
if (v == Short.MAX_VALUE) {
// no successor.
try {
SuccessorUtil.successor(b.clone());
fail("Expecting: " + NoSuccessorException.class);
} catch (NoSuccessorException ex) {
System.err
.println("Ignoring expected exception: " + ex);
}
} else {
// expected successor.
byte[] e = TestKeyBuilder.asSortKey((short) (v + 1));
// successor.
byte[] s = SuccessorUtil.successor(b.clone());
if (false) {
System.err.println("v = " + v);
System.err.println("b: " + Arrays.toString(b));
System.err.println("s: " + Arrays.toString(s));
System.err.println("e: " + Arrays.toString(e));
}
assertEquals(e, s);
}
}
}
}
}