/*
 * 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.lucene.util;

Floating point numbers smaller than 32 bits.
@lucene.internal
/** Floating point numbers smaller than 32 bits. * * @lucene.internal */
public class SmallFloat {
No instance
/** No instance */
private SmallFloat() {}
Converts a 32 bit float to an 8 bit float.
Values less than zero are all mapped to zero.
Values are truncated (rounded down) to the nearest 8 bit value.
Values between zero and the smallest representable value are rounded up.
Params:
  • f – the 32 bit float to be converted to an 8 bit float (byte)
  • numMantissaBits – the number of mantissa bits to use in the byte, with the remainder to be used in the exponent
  • zeroExp – the zero-point in the range of exponent values
Returns:the 8 bit float representation
/** 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.
/** 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)
smallest non-zero value = 5.820766E-10
largest value = 7.5161928E9
epsilon = 0.125
/** 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)
/** 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); }
Float-like encoding for positive longs that preserves ordering and 4 significant bits.
/** Float-like encoding for positive longs that preserves ordering and 4 significant bits. */
public static int longToInt4(long i) { if (i < 0) { throw new IllegalArgumentException("Only supports positive values, got " + i); } int numBits = 64 - Long.numberOfLeadingZeros(i); if (numBits < 4) { // subnormal value return Math.toIntExact(i); } else { // normal value int shift = numBits - 4; // only keep the 5 most significant bits int encoded = Math.toIntExact(i >>> shift); // clear the most significant bit, which is implicit encoded &= 0x07; // encode the shift, adding 1 because 0 is reserved for subnormal values encoded |= (shift + 1) << 3; return encoded; } }
Decode values encoded with longToInt4(long).
/** * Decode values encoded with {@link #longToInt4(long)}. */
public static final long int4ToLong(int i) { long bits = i & 0x07; int shift = (i >>> 3) - 1; long decoded; if (shift == -1) { // subnormal value decoded = bits; } else { // normal value decoded = (bits | 0x08) << shift; } return decoded; } private static final int MAX_INT4 = longToInt4(Integer.MAX_VALUE); private static final int NUM_FREE_VALUES = 255 - MAX_INT4;
Encode an integer to a byte. It is built upon longToInt4(long) and leverages the fact that longToInt4(Integer.MAX_VALUE) is less than 255 to encode low values more accurately.
/** * Encode an integer to a byte. It is built upon {@link #longToInt4(long)} * and leverages the fact that {@code longToInt4(Integer.MAX_VALUE)} is * less than 255 to encode low values more accurately. */
public static byte intToByte4(int i) { if (i < 0) { throw new IllegalArgumentException("Only supports positive values, got " + i); } if (i < NUM_FREE_VALUES) { return (byte) i; } else { return (byte) (NUM_FREE_VALUES + longToInt4(i - NUM_FREE_VALUES)); } }
Decode values that have been encoded with intToByte4(int).
/** * Decode values that have been encoded with {@link #intToByte4(int)}. */
public static int byte4ToInt(byte b) { int i = Byte.toUnsignedInt(b); if (i < NUM_FREE_VALUES) { return i; } else { long decoded = NUM_FREE_VALUES + int4ToLong(i - NUM_FREE_VALUES); return Math.toIntExact(decoded); } } }