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

📄 microfloat.java

📁 This is a Java library for performing floating-point calculations on small devices such as mobile p
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
   * <ul><li>If the argument value is already equal to a mathematical 
   * integer, then the result is the same as the argument. 
   * <li>If the argument is NaN or an infinity or positive zero or 
   * negative zero, then the result is the same as the argument.</ul>
   *
   * @param   f   a <code>float</code> value.
   * @return the <code>float</code> of greatest magnitude (furthest from zero)
   *         whose magnitude is not greater than the argument's and which 
   *         is equal to a mathematical integer.
   */
  public static int truncate(int f) {
    return round(f, false, unpackSign(f));
  }

  /**
   * Mimics 
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#rint(double)">Math.rint(double)</a>, 
   * using single precision.
   */
  public static int rint(int f) {
    return round(f, true, false);
  }
  
  /**
   * Mimics
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#floor(double)">Math.floor(double)</a>, 
   * using single precision.
   */
  public static int floor(int f) {
    return round(f, false, false);
  }
  
  /**
   * Mimics
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#ceil(double)">Math.ceil(double)</a>, 
   * using single precision.
   */
  public static int ceil(int f) {
    return round(f, false, true);
  }

  /**
   * Mimics
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#round(double)">Math.round(double)</a>, 
   * using single precision.
   */
  public static int round(int f) {
    return intValue(floor(add(f, ONE_HALF)));
  }

  private static int round(int f, boolean round, boolean ceil) {
    if (isNaN(f)) {
      return NaN;
    } else if (isZero(f) || isInfinite(f)) {
      return f;
    }
    int x = unpackExponent(f);
    if (x >= 0) {
      return f;
    }
    boolean n = unpackSign(f);
    int m = unpackMantissa(f);
    if (round) {
      m = BitUtils.roundingRightShift(m, -x);
    } else {
      int r;
      if (x <= -32) {
        r = m;
        m = 0;
      } else {
        r = m << (32 + x);
        m >>>= -x;
      }
      if ((n ^ ceil) && (r != 0)) {
        m++;
      }
    }
    return pack(n, 0, m);
  }


  /////////////////////////////////////////////////////////////////////////////
  // String conversion
  /////////////////////////////////////////////////////////////////////////////

  // decimal -> binary
  
  // base 2 mantissas for 10**-54 through 10**38, at intervals of 100
  private static final int[] pow10m = {
          0xc428d05b, 0x993fe2c7, 0xef73d257, 0xbb127c54, 0x92267121, 
          0xe45c10c4, 0xb267ed19, 0x8b61313c, 0xd9c7dced, 0xaa242499, 
          0x84ec3c98, 0xcfb11ead, 0xa2425ff7, 0xfd87b5f3, 0xc6120625, 
          0x9abe14cd, 0xf1c90081, 0xbce50865, 0x9392ee8f, 0xe69594bf, 
          0xb424dc35, 0x8cbccc09, 0xdbe6fecf, 0xabcc7712, 0x8637bd06, 
          0xd1b71759, 0xa3d70a3d, 0x80000000, 0xc8000000, 0x9c400000, 
          0xf4240000, 0xbebc2000, 0x9502f900, 0xe8d4a510, 0xb5e620f5, 
          0x8e1bc9bf, 0xde0b6b3a, 0xad78ebc6, 0x87867832, 0xd3c21bcf, 
          0xa56fa5ba, 0x813f3979, 0xc9f2c9cd, 0x9dc5ada8, 0xf684df57, 
          0xc097ce7c, 0x96769951,
  };
  
  // base 2 exponents for 10**-54 through 10**38, at intervals of 100
  private static final short[] pow10x = {
          -211, -204, -198, -191, -184, -178, -171, -164, 
          -158, -151, -144, -138, -131, -125, -118, -111, 
          -105, -98, -91, -85, -78, -71, -65, -58, 
          -51, -45, -38, -31, -25, -18, -12, -5, 
          2, 8, 15, 22, 28, 35, 42, 48, 
          55, 62, 68, 75, 81, 88, 95,
  };
          
  private static int decToFloat(boolean negative, int base10x, int base10m) {
    if (base10m == 0) {
      return (negative ? NEGATIVE_ZERO : ZERO);
    }
    // maximize base10m to ensure consistency between toString and parseFloat
    while ((base10m > 0) && (base10m <= 0x19999999)) { // (Integer.MAX_VALUE / 5))) {
      base10m = (base10m << 3) + (base10m << 1);
      base10x--;
    }
    // base10x needs to be a multiple of 2, because the tables are
    // spaced at intervals of 100 (not 10).
    base10x += 54;
    boolean mod = ((base10x & 1) != 0);
    base10x >>= 1;
    if (base10x < 0) { // -54
      return (negative ? NEGATIVE_ZERO : ZERO);
    } else if (base10x > 46) { // 38
      return (negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
    }
    int base2x = pow10x[base10x];
    long base2m = (base10m & 0xffffffffL) * (pow10m[base10x] & 0xffffffffL);
    if (mod) {
      if (base2m < 0) {
        base2m >>>= 1;
        base2x++;
      }
      base2m += base2m >>> 2;
      base2x += 3;
    }
    return pack(negative, base2x, base2m);
  }

  /**
   * Mimics
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#parseFloat(String)">Float.parseFloat(String)</a>.
   * <p>
   * <b>This implementation is known to be inaccurate, and 
   * does not always return the same value as 
   * <code>Float.parseFloat</code>.</b>  However the difference should be no 
   * greater than 1 ulp.
   *
   * @exception  NumberFormatException  if the string does not contain a
   *               parsable number.
   */
  public static int parseFloat(String s) {
    // remove leading & trailing whitespace
    s = s.trim().toUpperCase();
    
    // check length
    int len = s.length();
    if (len == 0) {
      throw new NumberFormatException(s);
    }
    
    // check for NaN
    if ("NAN".equals(s)) {
      return NaN;
    }
    
    // begin parsing, one character at a time
    int idx = 0;
    
    // read sign
    boolean negative = false;
    char c = s.charAt(0);
    negative = (c == '-');
    if (negative || (c == '+')) {
      idx = 1;
    }

    // check for "Infinity"
    if (idx < len) {
      c = s.charAt(idx);
      if ((c == 'I') || (c == 'i')) {
        if ("INFINITY".equals(s.substring(idx))) {
          return (negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
        }
      }
    }

    // read Digits.Digits
    int mantissa = 0;
    int exponent = 0;
    int fractionChars = 0;
    boolean sticky = false;
    boolean readingFraction = false;
    while (idx < len) {
      c = s.charAt(idx);
      if (c == '.') {
        if (readingFraction) {
          throw new NumberFormatException(s);
        }
        readingFraction = true;
      } else if ((c < '0') || (c > '9')) {
        break;
      } else {
        fractionChars++;
        if (mantissa <= 0x19999998) { // ((Integer.MAX_VALUE / 5) - 1)) { 
          mantissa = (mantissa << 3) + (mantissa << 1) + (c - '0');
          if (readingFraction) {
            exponent--;
          }
        } else {
          if (! readingFraction) {
            exponent++;
          }
          sticky |= (c != '0');
        }
      }
      idx++;
    }
    if (fractionChars == 0) {
      throw new NumberFormatException(s);
    }
    
    // read exponent
    if (((idx + 1) < len) && ((s.charAt(idx) == 'E') || (s.charAt(idx) == 'e'))) {
      try {
        exponent += Integer.parseInt(s.substring(idx + 1));
      } catch (NumberFormatException e) {
        throw new NumberFormatException(s);
      }
      idx = len;
    } else if (idx != len) {
      // check that we parsed the entire string
      throw new NumberFormatException(s);
    }

    // convert the decimal to a float
    return decToFloat(negative, exponent, mantissa);
  }

  // binary -> decimal
  
  // base 10 mantissas for 2**-150 through 2**98, at intervals of 2**8
  private static final int[] pow2m = {
          0xb35dbf82, 0x2deaf18a, 0x758ca7c7, 
          0x1e17b843, 0x4d0985cb, 0xc5371912, 
          0x327cb273, 0x813f3979, 0x21165458, 
          0x54b40b20, 0xd8d726b7, 0x3782dacf, 
          0x8e1bc9bf, 0x246139cb, 0x5d21dba0, 
          0xee6b2800, 0x3d090000, 0x9c400000, 
          0x28000000, 0x66666666, 0x1a36e2eb, 
          0x431bde83, 0xabcc7712, 0x2bfaffc3, 
          0x709709a1, 0x1cd2b298, 0x49c97747, 
          0xbce50865, 0x305b6680, 0x7bcb43d7, 
          0x1fb0f6be, 0x51212ffc, 
  };

  // base 10 exponents for 2 ^ -150 through 2 ^ 98, at intervals of 2 ^ 8
  private static final byte[] pow2x = {
          -45, -42, -40, -37, -35, -33, -30, -28, 
          -25, -23, -21, -18, -16, -13, -11, -9, 
          -6, -4, -1, 1, 4, 6, 8, 11, 
          13, 16, 18, 20, 23, 25, 28, 30, 
  };

  /**
   * Mimics
   * <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Float.html#toString(float)">Float.toString(float)</a>.
   * <p>
   * <b>This implementation is known to be inaccurate, and 
   * does not always return the same value as 
   * <code>Float.toString</code>.</b>  However the difference should be no 
   * greater than 1 ulp.
   */
  public static String toString(int f) {
    if (isNaN(f)) {
      return "NaN";
    }
    boolean n = unpackSign(f);
    StringBuffer sb = new StringBuffer(15);
    if (n) {
      sb.append('-');
    }
    if (isZero(f)) {
      sb.append("0.0");
      return sb.toString();
    } else if (isInfinite(f)) {
      sb.append("Infinity");
      return sb.toString();
    }
    // convert from base 2 to base 10
    int base2x = unpackExponent(f);
    int base2m = unpackMantissa(f);
    int idx = base2x + 150;
    int dx = idx & 7;
    base2m <<= dx;
    idx >>= 3;
    int base10x = pow2x[idx];
    while (base2m <= 0xccccccc) {
      base2m = (base2m << 3) + (base2m << 1); // base2m *= 10;
      base10x--;
    }
    long base10ml = base2m * (pow2m[idx] & 0xffffffffL);
    int base10m = (int) (base10ml >>> 32);
    if ((base10ml << 32) < 0) {
      base10m++;
    }

    // reduce the number of digits in m10 
    boolean roundedUp = false;
    while (true) {
      int r = base10m % 10;
      int mt = base10m / 10;
      int xt = base10x + 1;
      if (r != 0) {
        if ((r > 5) || ((r == 5) && (! roundedUp))) {
          roundedUp = true;
          mt++;
        } else {
          roundedUp = false;
        }
        int ft = decToFloat(n, xt, mt);
        if (ft != f) {
          if (roundedUp) {
            mt--;
          } else {
            mt++;
          }
          roundedUp ^= true;
          ft = decToFloat(n, xt, mt);
          if (ft != f) {
            break;
          }
        }
      }
      base10m = mt;
      base10x = xt;
    }
    
    // convert to string
    String s = Integer.toString(base10m);
    base10x += s.length() - 1;
    boolean scientific = ((base10x < -3) || (base10x >= 7));
    int dp; // index of decimal point in final string
    if (scientific) {
      dp = 1;
    } else {
      dp = base10x + 1;
      if (dp < 1) {
        sb.append('0');
      }
    }
    for (int i=0; i<dp; i++) {
      if (i < s.length()) {
        sb.append(s.charAt(i));
      } else {
        sb.append('0');
      }
    }
    sb.append('.');
    if (dp >= s.length()) {
      sb.append('0');
    } else {
      for (int i=dp; i<s.length(); i++) {
        if (i < 0) {
          sb.append('0');
        } else {
          sb.append(s.charAt(i));
        }
      }
    }
    if (scientific) {
      sb.append('E');
      sb.append(Integer.toString(base10x));
    }
    return sb.toString();
  }

  
  /////////////////////////////////////////////////////////////////////////////
  // Instance members
  /////////////////////////////////////////////////////////////////////////////

  private final int value;

  
  /////////////////////////////////////////////////////////////////////////////
  // Constructors
  /////////////////////////////////////////////////////////////////////////////

  
  /**
   * Constructs a newly-allocated <code>MicroFloat</code> object that represents 
   * the argument. 
   *
   * @param f the <code>float</code> value to be represented by the <code>MicroFloat</code>.
   */
  public MicroFloat(int f) {
    // canonicalize NaN values so that hashCode() and equals() can be simpler
    if (isNaN(f)) {
      f = NaN;
    }
    value = f;
  }
  
  /**
   * Constructs a newly-allocated <code>MicroFloat</code> object that represents 
   * the argument.
   *
   * @param s a <code>String</code> to be converted to a <code>MicroFloat</code>.
   * @throws NumberFormatException if the <code>String</code> does not contain a
   *         parsable number.
   * @see #parseFloat(String)
   */
  public MicroFloat(String s) {
    this(parseFloat(s));
  }

  
  /////////////////////////////////////////////////////////////////////////////
  // Instance methods
  /////////////////////////////////////////////////////////////////////////////
  
  /**
   * Returns the <code>float</code> value of this <code>MicroFloat</code>
   * object.
   */
  public int floatValue() {
    return value;
  }

  /**
   * Returns a String object representing this MicroFloat's value.
   * Equivalent to <code>toString(floatValue())</code>.
   *
   * @see #toString(int)
   */
  public String toString() {
    return toString(value);
  }

  /**
   * Returns a hash code for this <code>MicroFloat</code> object.
   * Equivalent to floatValue().
   */
  public int hashCode() {
    return value;
  }

  /**
   * Compares this object against the specified object.
   * Equivalent to <code>((obj instanceof MicroFloat) && (compare(((MicroFloat) obj).floatValue(), floatValue()) == 0))</code>
   * 
   * @see #compare(int, int)
   */
  public boolean equals(Object obj) {
    return ((obj instanceof MicroFloat)
            && (((MicroFloat) obj).value == value));
  }
  
}

⌨️ 快捷键说明

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