⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 microfloat.java

📁 This is a Java library for performing floating-point calculations on small devices such as mobile p
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
// $Id: MicroFloat.java,v 1.2 2004/08/03 04:57:42 Dave Exp $
/*
 * Float.java
 * Copyright (C) 2003, 2004 David Clausen
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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.
 *
 */
package net.dclausen.microfloat;

/**
 * A software implementation of IEEE-754 single precision math which does not
 * rely on the <code>float</code> data type. 
 * This class overloads the <code>int</code> data type by storing 
 * <code>float</code> data in it.
 * See the 
 * <a href="package-summary.html#package_description">package description</a> 
 * for more information.
 * <p>
 * @author David Clausen
 * @see <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html">Float</a>
 * @see MicroDouble
 * @version $Revision: 1.2 $
 */
public final class MicroFloat {

  /////////////////////////////////////////////////////////////////////////////
  // General-purpose constants
  /////////////////////////////////////////////////////////////////////////////

  /**
   * A constant representing the same value as 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#POSITIVE_INFINITY">Float.POSITIVE_INFINITY</a>
   */
  public  static final int POSITIVE_INFINITY = 0x7f800000;

  /**
   * A constant holding the same value as 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#NEGATIVE_INFINITY">Float.NEGATIVE_INFINITY</a>
   */
  public  static final int NEGATIVE_INFINITY = 0xff800000;
  
  /**
   * A constant holding the same value as
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#NaN">Float.NaN</a>
   */
  public  static final int NaN               = 0x7fc00000;

  /**
   * A constant holding the same value as 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#MAX_VALUE">Float.MAX_VALUE</a>
   */
  public  static final int MAX_VALUE         = 0x7f7fffff;
  
  /**
   * A constant holding the same value as
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#MIN_VALUE">Float.MIN_VALUE</a>
   */
  public  static final int MIN_VALUE         = 0x00000001;

  /**
   * A single-precision version of {@link MicroDouble#E}
   */
  public  static final int E                 = 0x402df854;

  /**
   * A single-precision version of {@link MicroDouble#PI}
   */
  public  static final int PI                = 0x40490fdb;
  
  // Other constants needed internally, and exposed as a convenience.
  
  /** A constant holding the value of 0.0f */
  public static final int ZERO              = 0x00000000;

  /** A constant holding the value of -0.0f */
  public static final int NEGATIVE_ZERO     = 0x80000000;

  /** A constant holding the value of 1.0f */
  public static final int ONE               = 0x3f800000;

  /** A constant holding the value of 2.0f */
  public static final int TWO               = 0x40000000;

  /** A constant holding the value of 0.5f */
  public static final int ONE_HALF          = 0x3f000000;
  

  /////////////////////////////////////////////////////////////////////////////
  // Packing and unpacking the IEEE-754 single precision format
  /////////////////////////////////////////////////////////////////////////////

  private static final int ABS_MASK          = 0x7fffffff;
  private static final int SIGN_MASK         = 0x80000000; // 1 bit
  private static final int EXPONENT_MASK     = 0x7f800000; // 8 bits
  private static final int FRACTION_MASK     = 0x007fffff; // 23 bits
  private static final int IMPLIED_ONE       = 0x00800000; // 24th bit

  /** @return true iff d is negative */
  static boolean unpackSign(int f) {
    return (f < 0);
  }

  /** @return an integer in the range [-150, 105] */
  static int unpackExponent(int f) {
    return ((f >> 23) & 0xff) - 150;
  }
  
  /** @return an integer in the range [0, 0x00ffffff] */
  static int unpackMantissa(int f) {
    if ((f & EXPONENT_MASK) == 0) {
      return ((f & FRACTION_MASK) << 1);
    } else {
      return ((f & FRACTION_MASK) | IMPLIED_ONE);
    }
  }

  /** 
   * @return the float which most closely represents the given base-2 mantissa
   *         and exponent
   */
  static int pack(boolean negative, int exponent, int mantissa) {
    // left align mantissa
    int shift = BitUtils.countLeadingZeros(mantissa);
    mantissa <<= shift;
    exponent -= shift;
    return pack2(negative, exponent, mantissa);
  }

  /** 
   * @return the float which most closely represents the given base-2 mantissa
   *         and exponent
   */
  static int pack(boolean negative, int exponent, long mantissa) {
    // shift mantissa so that it is left-aligned when cast to an int
    int shift = 32 - BitUtils.countLeadingZeros(mantissa);
    exponent += shift;
    if (shift > 0) {
      mantissa = BitUtils.stickyRightShift(mantissa, shift);
    } else if (shift < 0) {
      mantissa <<= -shift;
    }
    return pack2(negative, exponent, (int) mantissa);
  }

  /**
   * @param mantissa must be left aligned (or zero)
   */
  private static int pack2(boolean negative, int exponent, int mantissa) {
    // reduce precision of mantissa, rounding if necessary
    if (mantissa != 0) {
      if (exponent < -157) {
        // subnormal
        mantissa = BitUtils.roundingRightShift(mantissa, -149 - exponent);
      } else {
        // normal
        mantissa = BitUtils.roundingRightShift(mantissa, 8);
        if (mantissa == 0x1000000) {
          // oops, the rounding carried into the 25th bit
          mantissa = 0x800000;
          exponent++;
        }
        // pack the exponent
        if (exponent > 96) {
          mantissa = POSITIVE_INFINITY;
        } else {
          mantissa ^= IMPLIED_ONE;
          mantissa |= (exponent + 158) << 23;
        }
      }
    }

    // pack the sign bit
    if (negative) {
      mantissa |= SIGN_MASK;
    }
    
    return mantissa;
  }

  
  /////////////////////////////////////////////////////////////////////////////
  // Simple tests 
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Mimics 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#isNaN(float)">Float.isNaN(float)</a>
   */
  public static boolean isNaN(int f) {
    return ((f & ABS_MASK) > POSITIVE_INFINITY);
  }

  /**
   * Mimics
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#isInfinite(float)">Float.isInfinite(float)</a>
   */
  public static boolean isInfinite(int f) {
    return ((f & ABS_MASK) == POSITIVE_INFINITY);
  }
  
  /**
   * Returns <code>true</code> if the specified number has zero
   * magnitude, <code>false</code> otherwise.
   *
   * @param   f   the <code>float</code> value to be tested.
   * @return  <code>true</code> if the value of the argument is positive
   *          zero or negative zero; <code>false</code> otherwise.
   */
  public static boolean isZero(int f) {
    return ((f & ABS_MASK) == 0);
  }

  
  /////////////////////////////////////////////////////////////////////////////
  // Sign changes
  /////////////////////////////////////////////////////////////////////////////
  
  /**
   * Mimics 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#abs(float)">Math.abs(float)</a>
   */
  public static int abs(int f) {
    //if (isNaN(f)) {
    //  return NaN;
    //}
    return (f & ABS_MASK);
  }

  /**
   * Returns the negation of a <code>float</code> value.
   * Special cases:
   * <ul>
   * <li>If the argument is negative zero, the result is positive zero.
   * <li>If the argument is positive zero, the result is negative zero.
   * <li>If the argument is negative infinity, the result is positive infinity.
   * <li>If the argument is positive infinity, the result is negative infinity.
   * <li>If the argument is NaN, the result is NaN.</ul>
   * <p>
   * This method takes the place of the unary <code>-</code> operator.
   *
   * @param   f   the <code>float</code> value whose negated value is to be 
   *              determined
   * @return  the negation of the argument.
   */
  public static int negate(int f) {
    if (isNaN(f)) {
      return NaN;
    }
    return (f ^ SIGN_MASK);
  }

  
  /////////////////////////////////////////////////////////////////////////////
  // Comparison
  /////////////////////////////////////////////////////////////////////////////

  /**
   * Returns <code>true</code> if the specified numbers are considered equal
   * according to 
   * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5198">section 15.21.1
   * of the JLS</a>.  Special cases:
   * <ul>
   * <li>If either operand is NaN, then the result is false
   * <li>Positive zero and negative zero are considered equal
   * </ul>
   * <p>
   * This method takes the place of the <code>==</code> operator.
   *
   * @param   f1   the first <code>float</code> value to be compared.
   * @param   f2   the second <code>float</code> value to be compared.
   * @return  <code>true</code> if the two values are considered equal;
   *          <code>false</code> otherwise.
   */
  public static boolean eq(int f1, int f2) {
    return (((f1 == f2) && (! isNaN(f1))) || (isZero(f1) && isZero(f2)));
  }
  
  /**
   * Returns <code>true</code> if the specified numbers are considered unequal
   * according to 
   * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5198">section
   * 15.21.1 of the JLS</a>.  Special cases:
   * <ul>
   * <li>If either operand is NaN, then the result is true
   * <li>Positive zero and negative zero are considered equal
   * </ul>
   * The value returned by <code>ne</code> is always the opposite of the value
   * returned by <code>eq</code> for the same arguments.
   * <p>
   * This method takes the place of the <code>!=</code> operator.
   *
   * @param   f1   the first <code>float</code> value to be compared.
   * @param   f2   the second <code>float</code> value to be compared.
   * @return  <code>true</code> if the two values are considered equal;
   *          <code>false</code> otherwise.
   */
  public static boolean ne(int f1, int f2) {
    return (! eq(f1, f2));
  }

  /**
   * Returns <code>true</code> if the first argument is considered less than
   * the second argument according to 
   * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#153654">section
   * 15.20.1 of the JLS</a>.  Special cases:
   * <ul>
   * <li>If either operand is NaN, then the result is false
   * <li>Positive zero and negative zero are considered equal
   * <li>Negative infinity is conisdered less than all other values except NaN
   * <li>Positive infinity is conisdered greater than all other values except NaN
   * </ul>
   * <p>
   * This method takes the place of the <code>&lt;</code> operator.
   *
   * @param   f1   the first <code>float</code> value to be compared.
   * @param   f2   the second <code>float</code> value to be compared.
   * @return  <code>true</code> if the first value is less than the second value;
   *          <code>false</code> otherwise.
   */
  public static boolean lt(int f1, int f2) {
    if (isNaN(f1) || isNaN(f2)) {
      return false;
    } else if (f2 == ZERO) {
      f2 = NEGATIVE_ZERO;
    }
    return (cmp(f1, f2) < 0);
  }
  
  /**
   * Returns <code>true</code> if the first argument is considered less than
   * or equal to the second argument according to 
   * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#153654">section
   * 15.20.1 of the JLS</a>.  Special cases:
   * <ul>
   * <li>If either operand is NaN, then the result is false
   * <li>Positive zero and negative zero are considered equal
   * <li>Negative infinity is conisdered less than all other values except NaN
   * <li>Positive infinity is conisdered greater than all other values except NaN
   * </ul>
   * <p>
   * This method takes the place of the <code>&lt;=</code> operator.
   *
   * @param   f1   the first <code>float</code> value to be compared.
   * @param   f2   the second <code>float</code> value to be compared.
   * @return  <code>true</code> if the first value is less than or equal to 
   *          the second value; <code>false</code> otherwise.
   */
  public static boolean le(int f1, int f2) {
    if (isNaN(f1) || isNaN(f2)) {
      return false;
    } else if (f2 == NEGATIVE_ZERO) {
      f2 = ZERO;
    }
    return (cmp(f1, f2) <= 0);
  }

  /**
   * Returns <code>true</code> if the first argument is considered greater than
   * the second argument according to 
   * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#153654">section
   * 15.20.1 of the JLS</a>.  Special cases:
   * <ul>
   * <li>If either operand is NaN, then the result is false
   * <li>Positive zero and negative zero are considered equal
   * <li>Negative infinity is conisdered less than all other values except NaN
   * <li>Positive infinity is conisdered greater than all other values except NaN
   * </ul>
   * <p>
   * This method takes the place of the <code>&gt;</code> operator.
   *
   * @param   f1   the first <code>float</code> value to be compared.
   * @param   f2   the second <code>float</code> value to be compared.
   * @return  <code>true</code> if the first value is greater than the second value;
   *          <code>false</code> otherwise.
   */
  public static boolean gt(int f1, int f2) {
    if (isNaN(f1) || isNaN(f2)) {
      return false;
    } else if (f1 == ZERO) {
      f1 = NEGATIVE_ZERO;
    }
    return (cmp(f1, f2) > 0);
  }
  
  /**
   * Returns <code>true</code> if the first argument is considered greater than
   * or equal to the second argument according to 
   * <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#153654">section
   * 15.20.1 of the JLS</a>.  Special cases:
   * <ul>
   * <li>If either operand is NaN, then the result is false
   * <li>Positive zero and negative zero are considered equal
   * <li>Negative infinity is conisdered less than all other values except NaN
   * <li>Positive infinity is conisdered greater than all other values except NaN
   * </ul>
   * <p>
   * This method takes the place of the <code>&gt;=</code> operator.
   *
   * @param   f1   the first <code>float</code> value to be compared.
   * @param   f2   the second <code>float</code> value to be compared.
   * @return  <code>true</code> if the first value is greater than or equal to 
   *          the second value; <code>false</code> otherwise.
   */
  public static boolean ge(int f1, int f2) {
    if (isNaN(f1) || isNaN(f2)) {
      return false;
    } else if (f1 == NEGATIVE_ZERO) {
      f1 = ZERO;
    }
    return (cmp(f1, f2) >= 0);
  }


  /**
   * Mimics 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#compare(float, float)">Float.compare(float, float)</a>.
   * <p>
   * Note that when using this method (as well as <code>Float.compare</code>),
   * the following rules apply:
   * <ul><li>
   *		<code>NaN</code> is considered 
   *		to be equal to itself and greater than all other
   *		<code>float</code> values (including
   *		<code>POSITIVE_INFINITY</code>).
   * <li>
   *		<code>0.0</code> is considered to be greater
   *		than <code>-0.0</code>.
   * </ul>
   */
  public static int compare(int f1, int f2) {
    boolean n1 = isNaN(f1);
    boolean n2 = isNaN(f2);
    if (n1 || n2) {
      if (n1 && n2) {
        return 0;
      }
      return (n1 ? 1 : -1);
    }
    return cmp(f1, f2);
  }

  /**
   * Mimics 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#max(float, float)">Math.max(float, float)</a>.
   */
  public static int max(int f1, int f2) {
    if (isNaN(f1) || isNaN(f2)) {
      return NaN;
    }
    return ((cmp(f1, f2) < 0) ? f2 : f1);
  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -