📄 microfloat.java
字号:
/**
* Mimics
* <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Math.html#min(float, float)">Math.min(float, float)</a>.
*/
public static int min(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return NaN;
}
return ((cmp(f1, f2) > 0) ? f2 : f1);
}
private static int cmp(int f1, int f2) {
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 (MicroDouble.isNaN(d)) {
return NaN;
}
boolean n = MicroDouble.unpackSign(d);
if (MicroDouble.isZero(d)) {
return (n ? NEGATIVE_ZERO : ZERO);
} else if (MicroDouble.isInfinite(d)) {
return (n ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
}
int x = MicroDouble.unpackExponent(d);
long m = MicroDouble.unpackMantissa(d);
return pack(n, x, m);
}
/**
* 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 = unpackSign(f);
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);
}
/**
* Convert the given <code>float</code> to a <code>double</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 result in neither a loss of magnitude nor precision.
*
* @param f the <code>float</code> to be converted
* @return the <code>double</code> representation of the argument
*/
public static long doubleValue(int f) {
return MicroDouble.floatToDouble(f);
}
/////////////////////////////////////////////////////////////////////////////
// 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 add(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return NaN;
}
boolean n1 = unpackSign(f1);
boolean n2 = unpackSign(f2);
// 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 NaN;
} 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 ZERO;
} 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 == NEGATIVE_ZERO) {
return ZERO;
}
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 sub(int f1, int f2) {
return add(f1, negate(f2));
}
/**
* 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 mul(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return NaN;
}
boolean negative = unpackSign(f1) ^ unpackSign(f2);
// special handling of infinity
if (isInfinite(f1) || isInfinite(f2)) {
if (isZero(f1) || isZero(f2)) {
return NaN;
} else {
return (negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
}
}
// 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 div(int f1, int f2) {
if (isNaN(f1) || isNaN(f2)) {
return NaN;
}
boolean negative = unpackSign(f1) ^ unpackSign(f2);
// special handling of infinity
boolean n1 = isInfinite(f1);
boolean n2 = isInfinite(f2);
if (n1 || n2) {
if (n1 && n2) {
return NaN;
} else if (n1) {
return (negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
} else {
return (negative ? NEGATIVE_ZERO : ZERO);
}
}
// neither value is infinite
// special handling of zero
n1 = isZero(f1);
n2 = isZero(f2);
if (n1 || n2) {
if (n1 && n2) {
return NaN;
} else if (n1) {
return (negative ? NEGATIVE_ZERO : ZERO);
} else {
return (negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY);
}
}
// 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 mod(int f1, int f2) {
if (isNaN(f1) || isNaN(f2) || isInfinite(f1) || isZero(f2)) {
return NaN;
} else if (isZero(f1) || isInfinite(f2)) {
return f1;
}
// unpack
int x1 = unpackExponent(f1);
int x2 = unpackExponent(f2);
if (x1 < x2) {
return f1;
}
boolean n = unpackSign(f1);
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) {
int s = Math.min(39, x1 - x2);
x1 -= s;
m1 = (int) ((((long) m1) << s) % m2);
}
}
return pack(n, x1, m1);
}
/////////////////////////////////////////////////////////////////////////////
// Rounding
/////////////////////////////////////////////////////////////////////////////
/**
* Returns the <code>float</code> of greatest magnitude (furthest from zero)
* that is equal to a mathematical integer and which has a mignitude not
* greater than the argument's magnitude. Special cases:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -