mirror of https://github.com/apache/lucene.git
SmallFloat: generalized and faster versions of floatToByte/byteToFloat
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@345681 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a5cd1e7e1b
commit
6798e96355
|
@ -0,0 +1,125 @@
|
|||
package org.apache.lucene.util;
|
||||
/**
|
||||
* Copyright 2005 The Apache Software Foundation
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
|
||||
/** Floating point numbers smaller than 32 bits.
|
||||
*
|
||||
* @author yonik
|
||||
* @version $Id$
|
||||
*/
|
||||
class SmallFloat {
|
||||
|
||||
/** Converts a 32 bit float to an 8 bit float.
|
||||
* <br>Values less than zero are all mapped to zero.
|
||||
* <br>Values are truncated (rounded down) to the nearest 8 bit value.
|
||||
* <br>Values between zero and the smallest representable value
|
||||
* are rounded up.
|
||||
*
|
||||
* @param f the 32 bit float to be converted to an 8 bit float (byte)
|
||||
* @param numMantissaBits the number of mantissa bits to use in the byte, with the remainder to be used in the exponent
|
||||
* @param zeroExp the zero-point in the range of exponent values
|
||||
* @return the 8 bit float representation
|
||||
*/
|
||||
public static byte floatToByte(float f, int numMantissaBits, int zeroExp) {
|
||||
// Adjustment from a float zero exponent to our zero exponent,
|
||||
// shifted over to our exponent position.
|
||||
int fzero = (63-zeroExp)<<numMantissaBits;
|
||||
int bits = Float.floatToRawIntBits(f);
|
||||
int smallfloat = bits >> (24-numMantissaBits);
|
||||
if (smallfloat < fzero) {
|
||||
return (bits<=0) ?
|
||||
(byte)0 // negative numbers and zero both map to 0 byte
|
||||
:(byte)1; // underflow is mapped to smallest non-zero number.
|
||||
} else if (smallfloat >= fzero + 0x100) {
|
||||
return -1; // overflow maps to largest number
|
||||
} else {
|
||||
return (byte)(smallfloat - fzero);
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts an 8 bit float to a 32 bit float. */
|
||||
public static float byteToFloat(byte b, int numMantissaBits, int zeroExp) {
|
||||
// on Java1.5 & 1.6 JVMs, prebuilding a decoding array and doing a lookup
|
||||
// is only a little bit faster (anywhere from 0% to 7%)
|
||||
if (b == 0) return 0.0f;
|
||||
int bits = (b&0xff) << (24-numMantissaBits);
|
||||
bits += (63-zeroExp) << 24;
|
||||
return Float.intBitsToFloat(bits);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Some specializations of the generic functions follow.
|
||||
// The generic functions are just as fast with current (1.5)
|
||||
// -server JVMs, but still slower with client JVMs.
|
||||
//
|
||||
|
||||
/** floatToByte(b, mantissaBits=3, zeroExponent=15)
|
||||
* <br>smallest non-zero value = 5.820766E-10
|
||||
* <br>largest value = 7.5161928E9
|
||||
* <br>epsilon = 0.125
|
||||
*/
|
||||
public static byte floatToByte315(float f) {
|
||||
int bits = Float.floatToRawIntBits(f);
|
||||
int smallfloat = bits >> (24-3);
|
||||
if (smallfloat < (63-15)<<3) {
|
||||
return (bits<=0) ? (byte)0 : (byte)1;
|
||||
}
|
||||
if (smallfloat >= ((63-15)<<3) + 0x100) {
|
||||
return -1;
|
||||
}
|
||||
return (byte)(smallfloat - ((63-15)<<3));
|
||||
}
|
||||
|
||||
/** byteToFloat(b, mantissaBits=3, zeroExponent=15) */
|
||||
public static float byte315ToFloat(byte b) {
|
||||
// on Java1.5 & 1.6 JVMs, prebuilding a decoding array and doing a lookup
|
||||
// is only a little bit faster (anywhere from 0% to 7%)
|
||||
if (b == 0) return 0.0f;
|
||||
int bits = (b&0xff) << (24-3);
|
||||
bits += (63-15) << 24;
|
||||
return Float.intBitsToFloat(bits);
|
||||
}
|
||||
|
||||
|
||||
/** floatToByte(b, mantissaBits=5, zeroExponent=2)
|
||||
* <br>smallest nonzero value = 0.033203125
|
||||
* <br>largest value = 1984.0
|
||||
* <br>epsilon = 0.03125
|
||||
*/
|
||||
public static byte floatToByte52(float f) {
|
||||
int bits = Float.floatToRawIntBits(f);
|
||||
int smallfloat = bits >> (24-5);
|
||||
if (smallfloat < (63-2)<<5) {
|
||||
return (bits<=0) ? (byte)0 : (byte)1;
|
||||
}
|
||||
if (smallfloat >= ((63-2)<<5) + 0x100) {
|
||||
return -1;
|
||||
}
|
||||
return (byte)(smallfloat - ((63-2)<<5));
|
||||
}
|
||||
|
||||
/** byteToFloat(b, mantissaBits=5, zeroExponent=2) */
|
||||
public static float byte52ToFloat(byte b) {
|
||||
// on Java1.5 & 1.6 JVMs, prebuilding a decoding array and doing a lookup
|
||||
// is only a little bit faster (anywhere from 0% to 7%)
|
||||
if (b == 0) return 0.0f;
|
||||
int bits = (b&0xff) << (24-5);
|
||||
bits += (63-2) << 24;
|
||||
return Float.intBitsToFloat(bits);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package org.apache.lucene.util;
|
||||
|
||||
/**
|
||||
* Copyright 2005 The Apache Software Foundation
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author yonik
|
||||
* @version $Id$
|
||||
*/
|
||||
public class TestSmallFloat extends TestCase {
|
||||
|
||||
// original lucene byteToFloat
|
||||
static float orig_byteToFloat(byte b) {
|
||||
if (b == 0) // zero is a special case
|
||||
return 0.0f;
|
||||
int mantissa = b & 7;
|
||||
int exponent = (b >> 3) & 31;
|
||||
int bits = ((exponent+(63-15)) << 24) | (mantissa << 21);
|
||||
return Float.intBitsToFloat(bits);
|
||||
}
|
||||
|
||||
// original lucene floatToByte
|
||||
static byte orig_floatToByte(float f) {
|
||||
if (f < 0.0f) // round negatives up to zero
|
||||
f = 0.0f;
|
||||
|
||||
if (f == 0.0f) // zero is a special case
|
||||
return 0;
|
||||
|
||||
int bits = Float.floatToIntBits(f); // parse float into parts
|
||||
int mantissa = (bits & 0xffffff) >> 21;
|
||||
int exponent = (((bits >> 24) & 0x7f) - 63) + 15;
|
||||
|
||||
if (exponent > 31) { // overflow: use max value
|
||||
exponent = 31;
|
||||
mantissa = 7;
|
||||
}
|
||||
|
||||
if (exponent < 0) { // underflow: use min value
|
||||
exponent = 0;
|
||||
mantissa = 1;
|
||||
}
|
||||
|
||||
return (byte)((exponent << 3) | mantissa); // pack into a byte
|
||||
}
|
||||
|
||||
public void testByteToFloat() {
|
||||
for (int i=0; i<256; i++) {
|
||||
float f1 = orig_byteToFloat((byte)i);
|
||||
float f2 = SmallFloat.byteToFloat((byte)i, 3,15);
|
||||
float f3 = SmallFloat.byte315ToFloat((byte)i);
|
||||
assertEquals(f1,f2,0.0);
|
||||
assertEquals(f2,f3,0.0);
|
||||
|
||||
float f4 = SmallFloat.byteToFloat((byte)i,5,2);
|
||||
float f5 = SmallFloat.byte52ToFloat((byte)i);
|
||||
assertEquals(f4,f5,0.0);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFloatToByte() {
|
||||
Random rand = new Random(0);
|
||||
rand.nextFloat();
|
||||
// up iterations for more exhaustive test after changing something
|
||||
for (int i=0; i<100000; i++) {
|
||||
float f = Float.intBitsToFloat(rand.nextInt());
|
||||
if (f!=f) continue; // skip NaN
|
||||
byte b1 = orig_floatToByte(f);
|
||||
byte b2 = SmallFloat.floatToByte(f,3,15);
|
||||
byte b3 = SmallFloat.floatToByte315(f);
|
||||
assertEquals(b1,b2);
|
||||
assertEquals(b2,b3);
|
||||
|
||||
byte b4 = SmallFloat.floatToByte(f,5,2);
|
||||
byte b5 = SmallFloat.floatToByte52(f);
|
||||
assertEquals(b4,b5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue