diff options
| -rw-r--r-- | core/java/android/util/Half.java | 274 |
1 files changed, 33 insertions, 241 deletions
diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java index 70d049a6e985..fe536a6e4e68 100644 --- a/core/java/android/util/Half.java +++ b/core/java/android/util/Half.java @@ -20,6 +20,8 @@ import android.annotation.HalfFloat; import android.annotation.NonNull; import android.annotation.Nullable; +import libcore.util.FP16; + /** * <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a> @@ -148,25 +150,6 @@ public final class Half extends Number implements Comparable<Half> { */ public static final @HalfFloat short POSITIVE_ZERO = (short) 0x0000; - private static final int FP16_SIGN_SHIFT = 15; - private static final int FP16_SIGN_MASK = 0x8000; - private static final int FP16_EXPONENT_SHIFT = 10; - private static final int FP16_EXPONENT_MASK = 0x1f; - private static final int FP16_SIGNIFICAND_MASK = 0x3ff; - private static final int FP16_EXPONENT_BIAS = 15; - private static final int FP16_COMBINED = 0x7fff; - private static final int FP16_EXPONENT_MAX = 0x7c00; - - private static final int FP32_SIGN_SHIFT = 31; - private static final int FP32_EXPONENT_SHIFT = 23; - private static final int FP32_EXPONENT_MASK = 0xff; - private static final int FP32_SIGNIFICAND_MASK = 0x7fffff; - private static final int FP32_EXPONENT_BIAS = 127; - private static final int FP32_QNAN_MASK = 0x400000; - - private static final int FP32_DENORMAL_MAGIC = 126 << 23; - private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC); - private final @HalfFloat short mValue; /** @@ -414,16 +397,7 @@ public final class Half extends Number implements Comparable<Half> { * than {@code y} */ public static int compare(@HalfFloat short x, @HalfFloat short y) { - if (less(x, y)) return -1; - if (greater(x, y)) return 1; - - // Collapse NaNs, akin to halfToIntBits(), but we want to keep - // (signed) short value types to preserve the ordering of -0.0 - // and +0.0 - short xBits = (x & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : x; - short yBits = (y & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : y; - - return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1)); + return FP16.compare(x, y); } /** @@ -440,7 +414,7 @@ public final class Half extends Number implements Comparable<Half> { * @see #halfToIntBits(short) */ public static @HalfFloat short halfToShortBits(@HalfFloat short h) { - return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h; + return (h & FP16.EXPONENT_SIGNIFICAND_MASK) > FP16.POSITIVE_INFINITY ? NaN : h; } /** @@ -459,7 +433,7 @@ public final class Half extends Number implements Comparable<Half> { * @see #intBitsToHalf(int) */ public static int halfToIntBits(@HalfFloat short h) { - return (h & FP16_COMBINED) > FP16_EXPONENT_MAX ? NaN : h & 0xffff; + return (h & FP16.EXPONENT_SIGNIFICAND_MASK) > FP16.POSITIVE_INFINITY ? NaN : h & 0xffff; } /** @@ -505,7 +479,7 @@ public final class Half extends Number implements Comparable<Half> { * of the second parameter */ public static @HalfFloat short copySign(@HalfFloat short magnitude, @HalfFloat short sign) { - return (short) ((sign & FP16_SIGN_MASK) | (magnitude & FP16_COMBINED)); + return (short) ((sign & FP16.SIGN_MASK) | (magnitude & FP16.EXPONENT_SIGNIFICAND_MASK)); } /** @@ -523,7 +497,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The absolute value of the specified half-precision float */ public static @HalfFloat short abs(@HalfFloat short h) { - return (short) (h & FP16_COMBINED); + return (short) (h & FP16.EXPONENT_SIGNIFICAND_MASK); } /** @@ -538,26 +512,18 @@ public final class Half extends Number implements Comparable<Half> { * the result is zero (with the same sign)</li> * </ul> * + * <p class=note> + * <strong>Note:</strong> Unlike the identically named + * <code class=prettyprint>int java.lang.Math.round(float)</code> method, + * this returns a Half value stored in a short, <strong>not</strong> an + * actual short integer result. + * * @param h A half-precision float value * @return The value of the specified half-precision float rounded to the nearest * half-precision float value */ public static @HalfFloat short round(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - result |= (0x3c00 & (e >= 0x3800 ? 0xffff : 0x0)); - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result += (1 << (e - 1)); - result &= ~mask; - } - - return (short) result; + return FP16.rint(h); } /** @@ -577,21 +543,7 @@ public final class Half extends Number implements Comparable<Half> { * greater than or equal to the specified half-precision float value */ public static @HalfFloat short ceil(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - result |= 0x3c00 & -(~(bits >> 15) & (e != 0 ? 1 : 0)); - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result += mask & ((bits >> 15) - 1); - result &= ~mask; - } - - return (short) result; + return FP16.ceil(h); } /** @@ -611,21 +563,7 @@ public final class Half extends Number implements Comparable<Half> { * less than or equal to the specified half-precision float value */ public static @HalfFloat short floor(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0); - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result += mask & -(bits >> 15); - result &= ~mask; - } - - return (short) result; + return FP16.floor(h); } /** @@ -644,19 +582,7 @@ public final class Half extends Number implements Comparable<Half> { * half-precision float value */ public static @HalfFloat short trunc(@HalfFloat short h) { - int bits = h & 0xffff; - int e = bits & 0x7fff; - int result = bits; - - if (e < 0x3c00) { - result &= FP16_SIGN_MASK; - } else if (e < 0x6400) { - e = 25 - (e >> 10); - int mask = (1 << e) - 1; - result &= ~mask; - } - - return (short) result; + return FP16.trunc(h); } /** @@ -672,15 +598,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The smaller of the two specified half-precision values */ public static @HalfFloat short min(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - - if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) { - return (x & FP16_SIGN_MASK) != 0 ? x : y; - } - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; + return FP16.min(x, y); } /** @@ -697,15 +615,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The larger of the two specified half-precision values */ public static @HalfFloat short max(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return NaN; - - if ((x & FP16_COMBINED) == 0 && (y & FP16_COMBINED) == 0) { - return (x & FP16_SIGN_MASK) != 0 ? y : x; - } - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; + return FP16.max(x, y); } /** @@ -719,11 +629,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is less than y, false otherwise */ public static boolean less(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.less(x, y); } /** @@ -737,11 +643,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is less than or equal to y, false otherwise */ public static boolean lessEquals(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <= - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.lessEquals(x, y); } /** @@ -755,11 +657,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is greater than y, false otherwise */ public static boolean greater(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.greater(x, y); } /** @@ -773,11 +671,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is greater than y, false otherwise */ public static boolean greaterEquals(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return ((x & FP16_SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >= - ((y & FP16_SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); + return FP16.greaterEquals(x, y); } /** @@ -791,10 +685,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if x is equal to y, false otherwise */ public static boolean equals(@HalfFloat short x, @HalfFloat short y) { - if ((x & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - if ((y & FP16_COMBINED) > FP16_EXPONENT_MAX) return false; - - return x == y || ((x | y) & FP16_COMBINED) == 0; + return FP16.equals(x, y); } /** @@ -804,7 +695,7 @@ public final class Half extends Number implements Comparable<Half> { * @return 1 if the value is positive, -1 if the value is negative */ public static int getSign(@HalfFloat short h) { - return (h & FP16_SIGN_MASK) == 0 ? 1 : -1; + return (h & FP16.SIGN_MASK) == 0 ? 1 : -1; } /** @@ -818,7 +709,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The unbiased exponent of the specified value */ public static int getExponent(@HalfFloat short h) { - return ((h >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK) - FP16_EXPONENT_BIAS; + return ((h >>> FP16.EXPONENT_SHIFT) & FP16.SHIFTED_EXPONENT_MASK) - FP16.EXPONENT_BIAS; } /** @@ -829,7 +720,7 @@ public final class Half extends Number implements Comparable<Half> { * @return The significand, or significand, of the specified vlaue */ public static int getSignificand(@HalfFloat short h) { - return h & FP16_SIGNIFICAND_MASK; + return h & FP16.SIGNIFICAND_MASK; } /** @@ -841,7 +732,7 @@ public final class Half extends Number implements Comparable<Half> { * false otherwise */ public static boolean isInfinite(@HalfFloat short h) { - return (h & FP16_COMBINED) == FP16_EXPONENT_MAX; + return FP16.isInfinite(h); } /** @@ -852,7 +743,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if the value is a NaN, false otherwise */ public static boolean isNaN(@HalfFloat short h) { - return (h & FP16_COMBINED) > FP16_EXPONENT_MAX; + return FP16.isNaN(h); } /** @@ -866,7 +757,7 @@ public final class Half extends Number implements Comparable<Half> { * @return True if the value is normalized, false otherwise */ public static boolean isNormalized(@HalfFloat short h) { - return (h & FP16_EXPONENT_MAX) != 0 && (h & FP16_EXPONENT_MAX) != FP16_EXPONENT_MAX; + return FP16.isNormalized(h); } /** @@ -885,35 +776,7 @@ public final class Half extends Number implements Comparable<Half> { * @return A normalized single-precision float value */ public static float toFloat(@HalfFloat short h) { - int bits = h & 0xffff; - int s = bits & FP16_SIGN_MASK; - int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (bits ) & FP16_SIGNIFICAND_MASK; - - int outE = 0; - int outM = 0; - - if (e == 0) { // Denormal or 0 - if (m != 0) { - // Convert denorm fp16 into normalized fp32 - float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m); - o -= FP32_DENORMAL_FLOAT; - return s == 0 ? o : -o; - } - } else { - outM = m << 13; - if (e == 0x1f) { // Infinite or NaN - outE = 0xff; - if (outM != 0) { // SNaNs are quieted - outM |= FP32_QNAN_MASK; - } - } else { - outE = e - FP16_EXPONENT_BIAS + FP32_EXPONENT_BIAS; - } - } - - int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM; - return Float.intBitsToFloat(out); + return FP16.toFloat(h); } /** @@ -940,44 +803,7 @@ public final class Half extends Number implements Comparable<Half> { */ @SuppressWarnings("StatementWithEmptyBody") public static @HalfFloat short toHalf(float f) { - int bits = Float.floatToRawIntBits(f); - int s = (bits >>> FP32_SIGN_SHIFT ); - int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_EXPONENT_MASK; - int m = (bits ) & FP32_SIGNIFICAND_MASK; - - int outE = 0; - int outM = 0; - - if (e == 0xff) { // Infinite or NaN - outE = 0x1f; - outM = m != 0 ? 0x200 : 0; - } else { - e = e - FP32_EXPONENT_BIAS + FP16_EXPONENT_BIAS; - if (e >= 0x1f) { // Overflow - outE = 0x31; - } else if (e <= 0) { // Underflow - if (e < -10) { - // The absolute fp32 value is less than MIN_VALUE, flush to +/-0 - } else { - // The fp32 value is a normalized float less than MIN_NORMAL, - // we convert to a denorm fp16 - m = (m | 0x800000) >> (1 - e); - if ((m & 0x1000) != 0) m += 0x2000; - outM = m >> 13; - } - } else { - outE = e; - outM = m >> 13; - if ((m & 0x1000) != 0) { - // Round to nearest "0.5" up - int out = (outE << FP16_EXPONENT_SHIFT) | outM; - out++; - return (short) (out | (s << FP16_SIGN_SHIFT)); - } - } - } - - return (short) ((s << FP16_SIGN_SHIFT) | (outE << FP16_EXPONENT_SHIFT) | outM); + return FP16.toHalf(f); } /** @@ -1073,40 +899,6 @@ public final class Half extends Number implements Comparable<Half> { */ @NonNull public static String toHexString(@HalfFloat short h) { - StringBuilder o = new StringBuilder(); - - int bits = h & 0xffff; - int s = (bits >>> FP16_SIGN_SHIFT ); - int e = (bits >>> FP16_EXPONENT_SHIFT) & FP16_EXPONENT_MASK; - int m = (bits ) & FP16_SIGNIFICAND_MASK; - - if (e == 0x1f) { // Infinite or NaN - if (m == 0) { - if (s != 0) o.append('-'); - o.append("Infinity"); - } else { - o.append("NaN"); - } - } else { - if (s == 1) o.append('-'); - if (e == 0) { - if (m == 0) { - o.append("0x0.0p0"); - } else { - o.append("0x0."); - String significand = Integer.toHexString(m); - o.append(significand.replaceFirst("0{2,}$", "")); - o.append("p-14"); - } - } else { - o.append("0x1."); - String significand = Integer.toHexString(m); - o.append(significand.replaceFirst("0{2,}$", "")); - o.append('p'); - o.append(Integer.toString(e - FP16_EXPONENT_BIAS)); - } - } - - return o.toString(); + return FP16.toHexString(h); } } |