/*
* 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.
*
*/
/*
* Adapted by Wolfgang Puffitsch for JOP.
*/
package com.jopdesign.sys;
public final class SoftFloat32 {
/////////////////////////////////////////////////////////////////////////////
// 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 an integer in the range [-150, 105] */
public static int unpackExponent(int f) {
return ((f >> 23) & 0xff) - 150;
}
/** @return an integer in the range [0, 0x00ffffff] */
public static int unpackMantissa(int f) {
if ((f & 0x7f800000) == 0) {
return ((f & 0x007fffff) << 1);
} else {
return ((f & 0x007fffff) | 0x00800000);
}
}
/**
* @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
*/
public 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 = 0x7f800000;
} else {
mantissa ^= 0x00800000;
mantissa |= (exponent + 158) << 23;
}
}
}
// pack the sign bit
if (negative) {
mantissa |= 0x80000000;
}
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 & 0x7fffffff) > 0x7f800000);
}
/**
* 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 & 0x7fffffff) == 0x7f800000);
}
/**
* 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 & 0x7fffffff) == 0);
}
/////////////////////////////////////////////////////////////////////////////
// Comparison
/////////////////////////////////////////////////////////////////////////////
public static int float_cmpg(int a, int b) {
if (isNaN(a) || isNaN(b)) {
return 1; // one is NaN
}
return cmp(a, b);
}
public static int float_cmpl(int a, int b) {
if (isNaN(a) || isNaN(b)) {
return -1; // one is NaN
}
return cmp(a, b);
}
private static int cmp(int f1, int f2) {
// test for equal
if (f1 == f2)
return 0;
// positive zero and negative zero are considered euqal
if (((f1 | f2) << 1) == 0)
return 0;
// actual comparison
if (f1 < 0) {
if (f2 < 0) {
return f2 - f1;
} else {
return -1;
}
} else if (f2 < 0) {
return 1;
} else {
return f1 - f2;
}
}
/////////////////////////////////////////////////////////////////////////////
// Type conversion
/////////////////////////////////////////////////////////////////////////////
/**
* Convert the given <code>int</code> to a <code>float</code> as would happen
* in a casting operation specified by
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25214">section
* 5.1.2 of the JLS</a>. This is a widening primitive conversion which
* will not result in a loss of magnitude, but might result in a loss of
* precision.
*
* @param x the <code>int</code> to be converted
* @return the <code>float</code> representation of the argument
*/
public static int intToFloat(int x) {
if (x < 0) {
return pack(true, 0, -x);
}
return pack(false, 0, x);
}
/**
* Convert the given <code>long</code> to a <code>float</code> as would happen
* in a casting operation specified by
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25214">section
* 5.1.2 of the JLS</a>. This is a widening primitive conversion which
* will not result in a loss of magnitude, but might result in a loss of
* precision.
*
* @param x the <code>long</code> to be converted
* @return the <code>float</code> representation of the argument
*/
public static int longToFloat(long x) {
if (x < 0) {
return pack(true, 0, -x);
}
return pack(false, 0, x);
}
/**
* Convert the given <code>double</code> to a <code>float</code> as would happen
* in a casting operation specified by
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25363">section
* 5.1.3 of the JLS</a>. This is a narrowing primitive conversion which
* may result in a loss of magnitude and/or precision.
*
* @param d the <code>double</code> to be converted
* @return the <code>float</code> representation of the argument
*/
public static int doubleToFloat(long d) {
if (Const.SUPPORT_DOUBLE) {
if (SoftFloat64.isNaN(d)) {
return 0x7fc00000;
}
boolean n = d < 0;
if (SoftFloat64.isZero(d)) {
return (n ? 0x80000000 : 0x00000000);
} else if (SoftFloat64.isInfinite(d)) {
return (n ? 0xff800000 : 0x7f800000);
}
int x = SoftFloat64.unpackExponent(d);
long m = SoftFloat64.unpackMantissa(d);
return pack(n, x, m);
} else {
throw new RuntimeException("Not implemented");
}
}
// /**
// * Convert the given <code>float</code> to a <code>byte</code> as would happen
// * in a casting operation specified by
// * <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25363">section
// * 5.1.3 of the JLS</a>. This is a narrowing primitive conversion which
// * may result in a loss of magnitude and/or precision.
// * <p>
// * Note that this is a non-intuitive conversion. If the argument is outside
// * of the range of the byte type, the result is basically meaningless.
// *
// * @param f the <code>float</code> to be converted
// * @return the <code>byte</code> representation of the argument
// */
// public static byte byteValue(int f) {
// long x = intValue(f);
// return (byte) x;
// }
// /**
// * Convert the given <code>float</code> to a <code>short</code> as would happen
// * in a casting operation specified by
// * <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25363">section
// * 5.1.3 of the JLS</a>. This is a narrowing primitive conversion which
// * may result in a loss of magnitude and/or precision.
// * <p>
// * Note that this is a non-intuitive conversion. If the argument is outside
// * of the range of the short type, the result is basically meaningless.
// *
// * @param f the <code>float</code> to be converted
// * @return the <code>short</code> representation of the argument
// */
// public static short shortValue(int f) {
// long x = intValue(f);
// return (short) x;
// }
/**
* Convert the given <code>float</code> to an <code>int</code> as would happen
* in a casting operation specified by
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25363">section
* 5.1.3 of the JLS</a>. This is a narrowing primitive conversion which
* may result in a loss of magnitude and/or precision.
*
* @param f the <code>float</code> to be converted
* @return the <code>int</code> representation of the argument
*/
public static int intValue(int f) {
long x = longValue(f);
if (x >= Integer.MAX_VALUE) {
return Integer.MAX_VALUE;
} else if (x <= Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
}
return (int) x;
}
/**
* Convert the given <code>float</code> to a <code>long</code> as would happen
* in a casting operation specified by
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#25363">section
* 5.1.3 of the JLS</a>. This is a narrowing primitive conversion which
* may result in a loss of magnitude and/or precision.
*
* @param f the <code>float</code> to be converted
* @return the <code>long</code> representation of the argument
*/
public static long longValue(int f) {
if (isNaN(f)) {
return 0;
}
boolean n = f < 0;
int x = unpackExponent(f);
long m = unpackMantissa(f);
if (x > 0) {
if ((x >= 63) || ((m >> (63 - x)) != 0)) {
return (n ? Long.MIN_VALUE : Long.MAX_VALUE);
}
m <<= x;
} else if (x <= -24) {
return 0;
} else {
m >>>= -x;
}
return (n ? -m : m);
}
/////////////////////////////////////////////////////////////////////////////
// Basic arithmetic
/////////////////////////////////////////////////////////////////////////////
/**
* Returns the sum of the two <code>float</code> arguments according to
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#13510">section
* 15.18.2 of the JLS</a>.
* <p>
* This method takes the place of the binary <code>+</code> operator.
*
* @param f1 the first <code>float</code> value to be summed.
* @param f2 the second <code>float</code> value to be summed.
* @return the sum of the two arguments
*/
public static int float_add(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return 0x7fc00000;
}
boolean n1 = f1 < 0;
boolean n2 = f2 < 0;
// special handling of infinity
boolean i1 = isInfinite(f1);
boolean i2 = isInfinite(f2);
if (i1 || i2) {
if (i1 && i2) {
if (n1 != n2) {
// infinites of opposite sign -> NaN
return 0x7fc00000;
} else {
// infinites of same sign -> infinity the same sign
return f1;
}
} else if (i1) {
return f1; // infinite + finite = infinite
} else {
return f2; // finite + infinite = infinite
}
}
// special handling of zero
boolean z1 = isZero(f1);
boolean z2 = isZero(f2);
if (z1 || z2) {
if (z1 && z2) {
if (n1 != n2) {
// zeros of opposite sign -> positive zero
return 0x00000000;
} else {
return f1; // zeros of same sign -> zero of the same sign
}
} else if (z1) {
return f2; // zero + nonzero = nonzero
} else {
return f1; // nonzero + zero = nonzero
}
}
// unpack, and add 3 guard digits
int m1 = unpackMantissa(f1) << 3;
int x1 = unpackExponent(f1) - 3;
int m2 = unpackMantissa(f2) << 3;
int x2 = unpackExponent(f2) - 3;
// make exponents equal
int dx = x1 - x2;
if (dx > 0) {
m2 = BitUtils.stickyRightShift(m2, dx);
x2 = x1;
} else if (dx < 0) {
m1 = BitUtils.stickyRightShift(m1, -dx);
x1 = x2;
}
// if the signs are different, negate the smaller mantissa and choose
// the sign of the larger
if (n1 ^ n2) {
if (m1 > m2) {
m2 = -m2;
} else {
m1 = -m1;
n1 = n2;
}
}
// add (or subtract) mantissas
m1 += m2;
// pack result, and handle special case of zero (which always returns +0.0)
int f = pack(n1, x1, m1);
if (f == 0x80000000) {
return 0x00000000;
}
return f;
}
/**
* Returns the difference of the two <code>float</code> arguments according to
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#13510">section
* 15.18.2 of the JLS</a>.
* <p>
* This method takes the place of the binary <code>-</code> operator.
*
* @param f1 the first <code>float</code> value
* @param f2 the second <code>float</code> value
* @return the difference of the two arguments
*/
public static int float_sub(int f1, int f2) {
return float_add(f1, f2 ^ 0x80000000);
}
/**
* Returns the product of the two <code>float</code> arguments according to
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5036">section
* 15.17.1 of the JLS</a>.
* <p>
* This method takes the place of the <code>*</code> operator.
*
* @param f1 the first <code>float</code> value
* @param f2 the second <code>float</code> value
* @return the product of the two arguments
*/
public static int float_mul(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return 0x7fc00000;
}
boolean negative = (f1 < 0) ^ (f2 < 0);
// special handling of infinity
if (isInfinite(f1) || isInfinite(f2)) {
if (isZero(f1) || isZero(f2)) {
return 0x7fc00000;
} else {
return (negative ? 0xff800000 : 0x7f800000);
}
}
// unpack
int m1 = unpackMantissa(f1);
int x1 = unpackExponent(f1);
int m2 = unpackMantissa(f2);
int x2 = unpackExponent(f2);
// compute the resultant exponent
x1 += x2;
// compute the resultant mantissa using integer multiplication
long m = ((long) m1) * ((long) m2);
// round and pack the result
return pack(negative, x1, m);
}
/**
* Returns the quotient of the two <code>float</code> arguments according to
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#5047">section
* 15.17.2 of the JLS</a>.
* <p>
* This method takes the place of the <code>/</code> operator.
*
* @param f1 the <code>float</code> dividend
* @param f2 the <code>float</code> divisor
* @return the quotient of the two arguments
*/
public static int float_div(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return 0x7fc00000;
}
boolean negative = (f1 < 0) ^ (f2 < 0);
// special handling of infinity
boolean n1 = isInfinite(f1);
boolean n2 = isInfinite(f2);
if (n1 || n2) {
if (n1 && n2) {
return 0x7fc00000;
} else if (n1) {
return (negative ? 0xff800000 : 0x7f800000);
} else {
return (negative ? 0x80000000 : 0x00000000);
}
}
// neither value is infinite
// special handling of zero
n1 = isZero(f1);
n2 = isZero(f2);
if (n1 || n2) {
if (n1 && n2) {
return 0x7fc00000;
} else if (n1) {
return (negative ? 0x80000000 : 0x00000000);
} else {
return (negative ? 0xff800000 : 0x7f800000);
}
}
// neither value is zero
// unpack
int m1 = unpackMantissa(f1);
int x1 = unpackExponent(f1);
int m2 = unpackMantissa(f2);
int x2 = unpackExponent(f2);
// shift the dividend to the left to increase precision, then do an integer
// divide
int s = BitUtils.countLeadingZeros(m1) + 22;
long m3 = ((long) m1) << s;
int x = x1 - x2 - s;
long m = m3 / m2;
boolean r = ((m * m2) != m3);
// put a non-zero fraction into the sticky bit
if (r) {
m |= 1;
}
return pack(negative, x, m);
}
/**
* Returns the remainder of the two <code>float</code> arguments according to
* <a href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#24956">section
* 15.17.3 of the JLS</a>.
* <p>
* This method takes the place of the <code>%</code> operator.
*
* @param f1 the <code>float</code> dividend
* @param f2 the <code>float</code> divisor
* @return the remainder of the two arguments
*/
public static int float_rem(int f1, int f2) {
if (isNaN(f1) || isNaN(f2) || isInfinite(f1) || isZero(f2)) {
return 0x7fc00000;
} else if (isZero(f1) || isInfinite(f2)) {
return f1;
}
// unpack
int x1 = unpackExponent(f1);
int x2 = unpackExponent(f2);
if (x1 < x2) {
return f1;
}
boolean n = f1 < 0;
int m1 = unpackMantissa(f1);
int m2 = unpackMantissa(f2);
if (x1 == x2) {
m1 %= m2;
} else {
// reduce m1 by left shifting and modding until the exponents x1 and x2 are
// equal
while (x1 != x2) { // @WCA loop <= 7
int s = x1-x2 < 39 ? x1-x2 : 39;
x1 -= s;
m1 = (int) ((((long) m1) << s) % m2);
}
}
return pack(n, x1, m1);
}
/////////////////////////////////////////////////////////////////////////////
// Rounding
/////////////////////////////////////////////////////////////////////////////
/**
* 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 float_round(int f) {
return intValue(round(float_add(f, 0x3f000000), false, false));
}
private static int round(int f, boolean round, boolean ceil) {
if (isNaN(f)) {
return 0x7fc00000;
} else if (isZero(f) || isInfinite(f)) {
return f;
}
int x = unpackExponent(f);
if (x >= 0) {
return f;
}
boolean n = f < 0;
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);
}
}