All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.kiprobinson.bigfraction.util.FloatUtil Maven / Gradle / Ivy

package com.github.kiprobinson.bigfraction.util;

/**
 * Additional utilities for working with floay values. Useful to prevent hard-coding IEEE 754 constants in code.
 * Consider this a complement to the methods provided in {@link Float}.
 * 
 * @author Kip Robinson, https://github.com/kiprobinson
 * 
 * @see Wikipedia overview of IEEE 754 float-precision floating point specifications
 */
public final class FloatUtil
{
  /** Mask to get sign bit in a raw float value. */
  private final static int SIGN_MASK = 0x80000000;
  /** Bit position of the sign bit in IEEE 754 float-precision binary representation. */
  private final static int SIGN_POS = 31;
  
  /** Mask to get exponent bits in a raw float value. */
  private final static int EXPONENT_BITS_MASK = 0x7f800000;
  /** Bit position of the exponent bits in IEEE 754 float-precision binary representation. */
  private final static int EXPONENT_POS = 23;
  /** Exponent offset, per IEEE 754 spec. */
  private final static int EXPONENT_OFFSET = 0x7f;
  
  /** Mask to get mantissa bits in a raw float value. */
  private final static int MANTISSA_MASK = 0x7fffff;
  
  /** The largest permitted mantissa value. */
  public final static int MAX_MANTISSA = MANTISSA_MASK;
  
  /** The largest permitted exponent value, when using raw exponent bits. */
  public final static int MAX_EXPONENT_BITS = (EXPONENT_BITS_MASK >> EXPONENT_POS);
  
  /** The smallest permitted exponent value, when using an exponent with offset. */
  public final static int MIN_EXPONENT = -EXPONENT_OFFSET;
  /** The largest permitted exponent value, when using an exponent with offset. */
  public final static int MAX_EXPONENT = MAX_EXPONENT_BITS - EXPONENT_OFFSET;
  
  
  /** Hide default constructor to prevent instantiation. */
  private FloatUtil() {}
  
  /**
   * Returns true if f is finite--not infinite and not NaN. (Equivalent to
   * Float.isFinite() available from Java 8.)
   * 
   * @param f a float value
   * @return whether this value is finite.
   */
  public static boolean isFinite(float f) {
    return !Float.isInfinite(f) && !Float.isNaN(f);
  }
  
  /**
   * Returns the sign bit (bit 63). 0=positive, 1=negative. This is returned even for NaN values.
   * 
   * @param f a float value
   * @return the sign bit
   */
  public static int getSign(float f)
  {
    return (int)((Float.floatToRawIntBits(f) & SIGN_MASK) >>> SIGN_POS);
  }
  
  /**
   * Returns the exponent, after adding the exponent offset to the exponent bits. In other words, the value
   * in bits 62-52, plus 0x3ff.
*
* Examples:
    *
  • {@code getExponent(0.5) == -1} because {@code 1.0 == 1.0 * 2^-1}
  • *
  • {@code getExponent(1.0) == 0} because {@code 1.0 == 1.0 * 2^0}
  • *
  • {@code getExponent(2.0) == 1} because {@code 2.0 == 1.0 * 2^1}
  • *
  • Subnormal values: Always returns -1023.
  • *
  • Zero: Always returns -1023.
  • *
  • Infinity: Always returns 1024.
  • *
  • NaN: Always returns 1024.
  • *
* * @param f any float value * @return adjusted exponent */ public static int getExponent(float f) { return getExponentBits(f) - EXPONENT_OFFSET; } /** * Returns the raw exponent bits, without adjusting for the offset. In other words, the value * in bits 62-52.
*
* Examples:
    *
  • {@code getExponentBits(0.5) == 0x3fe}
  • *
  • {@code getExponentBits(1.0) == 0x3ff}
  • *
  • {@code getExponentBits(2.0) == 0x400}
  • *
  • Subnormal values: Always returns 0x000.
  • *
  • Zero: Always returns 0x000.
  • *
  • Infinity: Always returns 0x7ff.
  • *
  • NaN: Always returns 0x7ff.
  • *
* * @param f a float value * @return raw exponent bits */ public static int getExponentBits(float f) { return (int)((Float.floatToRawIntBits(f) & EXPONENT_BITS_MASK) >>> EXPONENT_POS); } /** * Returns the mantissa bits (bits 51-0). Returned even for NaN values. * @param f a float value * @return mantissa bits */ public static int getMantissa(float f) { return Float.floatToRawIntBits(f) & MANTISSA_MASK; } /** * Returns whether or not this float is a subnormal value. * @param f a float value * @return whether or not this float is a subnormal value */ public static boolean isSubnormal(float f) { int bits = Float.floatToRawIntBits(f); return ((bits & EXPONENT_BITS_MASK) == 0) && ((bits & MANTISSA_MASK) != 0); } /** * Returns an array containing the parts of the float. Avoids the overhead of four separate function calls. * * @param f a float value * @return array with four elements:
    *
  • return[0]: Equivalent to getSign(f)
  • *
  • return[1]: Equivalent to getExponent(f)
  • *
  • return[2]: Equivalent to getMantissa(f)
  • *
  • return[3]: Equivalent to isSubnormal(f) - Uses zero for false, non-zero for true.
  • *
*/ public static int[] getAllParts(float f) { return getAllParts(f, false); } /** * Returns an array containing the parts of the float. Avoids the overhead of four separate function calls. * * @param f a float value * @param exponentAsBits whether to return exponent as raw bits rather than adjusted value * @return array with four elements:
    *
  • return[0]: Equivalent to getSign(f)
  • *
  • return[1]: Equivalent to (exponentAsBits ? getExponentBits(f) : getExponent(f))
  • *
  • return[2]: Equivalent to getMantissa(f)
  • *
  • return[3]: Equivalent to isSubnormal(f) - Uses zero for false, non-zero for true.
  • *
*/ public static int[] getAllParts(float f, boolean exponentAsBits) { int[] segments = new int[4]; int bits = Float.floatToRawIntBits(f); segments[0] = (bits & SIGN_MASK) >>> SIGN_POS; segments[1] = (bits & EXPONENT_BITS_MASK) >>> EXPONENT_POS; segments[2] = bits & MANTISSA_MASK; segments[3] = (segments[1] == 0 && segments[2] != 0 ? 1 : 0); if(!exponentAsBits) segments[1] -= EXPONENT_OFFSET; return segments; } /** * Creates a new float primitive using the provided component bits. Assumes the exponent parameter is signed. * * @param sign sign bit * @param exponent adjusted exponent * @param mantissa mantissa bits * * @return The float value represented by the provided binary parts. * * @throws IllegalArgumentException if any of the parts contain invalid bits. */ public static float getFloat(int sign, int exponent, int mantissa) { return getFloat(sign, exponent, mantissa, false); } /** * Creates a new float primitive using the provided component bits. * * @param sign sign bit * @param exponent exponent (either raw bits or adjusted value) * @param mantissa mantissa bits * @param exponentAsBits If true, assumes that exponent parameter represents the actual exponent bits. If false, * IEEE exponent offset value will be added to the offset to get the bits. * * @return The float value represented by the provided binary parts. * * @throws IllegalArgumentException if any of the parts contain invalid bits. */ public static float getFloat(int sign, int exponent, int mantissa, boolean exponentAsBits) { if(sign < 0 || sign > 1) throw new IllegalArgumentException("Illegal sign bit: " + sign); if(0 != (mantissa & ~MANTISSA_MASK)) throw new IllegalArgumentException("Illegal mantissa: " + mantissa); int offsetExponent = (exponentAsBits ? exponent : exponent + EXPONENT_OFFSET); if(0 != (offsetExponent & ~MAX_EXPONENT_BITS)) throw new IllegalArgumentException("Illegal exponent: " + exponent); return Float.intBitsToFloat((((int)sign) << SIGN_POS) | (((int)offsetExponent) << EXPONENT_POS) | mantissa); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy