Merge "Move Half implementations to libcore to allow ART optimizations"
am: f54cb9109c

Change-Id: I9d03803ae3e39bd52afa7d6ee3bd84e8dbff0034
diff --git a/luni/src/main/java/libcore/util/FP16.java b/luni/src/main/java/libcore/util/FP16.java
new file mode 100644
index 0000000..88fe43a
--- /dev/null
+++ b/luni/src/main/java/libcore/util/FP16.java
@@ -0,0 +1,719 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package libcore.util;
+
+/**
+ * <p>The {@code FP16} 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>
+ * floating point data types (also called fp16 or binary16). A half-precision float can be
+ * created from or converted to single-precision floats, and is stored in a short data type.
+ *
+ * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p>
+ * <ul>
+ * <li>Sign bit: 1 bit</li>
+ * <li>Exponent width: 5 bits</li>
+ * <li>Significand: 10 bits</li>
+ * </ul>
+ *
+ * <p>The format is laid out as follows:</p>
+ * <pre>
+ * 1   11111   1111111111
+ * ^   --^--   -----^----
+ * sign  |          |_______ significand
+ *       |
+ *       -- exponent
+ * </pre>
+ *
+ * <p>Half-precision floating points can be useful to save memory and/or
+ * bandwidth at the expense of range and precision when compared to single-precision
+ * floating points (fp32).</p>
+ * <p>To help you decide whether fp16 is the right storage type for you need, please
+ * refer to the table below that shows the available precision throughout the range of
+ * possible values. The <em>precision</em> column indicates the step size between two
+ * consecutive numbers in a specific part of the range.</p>
+ *
+ * <table summary="Precision of fp16 across the range">
+ *     <tr><th>Range start</th><th>Precision</th></tr>
+ *     <tr><td>0</td><td>1 &frasl; 16,777,216</td></tr>
+ *     <tr><td>1 &frasl; 16,384</td><td>1 &frasl; 16,777,216</td></tr>
+ *     <tr><td>1 &frasl; 8,192</td><td>1 &frasl; 8,388,608</td></tr>
+ *     <tr><td>1 &frasl; 4,096</td><td>1 &frasl; 4,194,304</td></tr>
+ *     <tr><td>1 &frasl; 2,048</td><td>1 &frasl; 2,097,152</td></tr>
+ *     <tr><td>1 &frasl; 1,024</td><td>1 &frasl; 1,048,576</td></tr>
+ *     <tr><td>1 &frasl; 512</td><td>1 &frasl; 524,288</td></tr>
+ *     <tr><td>1 &frasl; 256</td><td>1 &frasl; 262,144</td></tr>
+ *     <tr><td>1 &frasl; 128</td><td>1 &frasl; 131,072</td></tr>
+ *     <tr><td>1 &frasl; 64</td><td>1 &frasl; 65,536</td></tr>
+ *     <tr><td>1 &frasl; 32</td><td>1 &frasl; 32,768</td></tr>
+ *     <tr><td>1 &frasl; 16</td><td>1 &frasl; 16,384</td></tr>
+ *     <tr><td>1 &frasl; 8</td><td>1 &frasl; 8,192</td></tr>
+ *     <tr><td>1 &frasl; 4</td><td>1 &frasl; 4,096</td></tr>
+ *     <tr><td>1 &frasl; 2</td><td>1 &frasl; 2,048</td></tr>
+ *     <tr><td>1</td><td>1 &frasl; 1,024</td></tr>
+ *     <tr><td>2</td><td>1 &frasl; 512</td></tr>
+ *     <tr><td>4</td><td>1 &frasl; 256</td></tr>
+ *     <tr><td>8</td><td>1 &frasl; 128</td></tr>
+ *     <tr><td>16</td><td>1 &frasl; 64</td></tr>
+ *     <tr><td>32</td><td>1 &frasl; 32</td></tr>
+ *     <tr><td>64</td><td>1 &frasl; 16</td></tr>
+ *     <tr><td>128</td><td>1 &frasl; 8</td></tr>
+ *     <tr><td>256</td><td>1 &frasl; 4</td></tr>
+ *     <tr><td>512</td><td>1 &frasl; 2</td></tr>
+ *     <tr><td>1,024</td><td>1</td></tr>
+ *     <tr><td>2,048</td><td>2</td></tr>
+ *     <tr><td>4,096</td><td>4</td></tr>
+ *     <tr><td>8,192</td><td>8</td></tr>
+ *     <tr><td>16,384</td><td>16</td></tr>
+ *     <tr><td>32,768</td><td>32</td></tr>
+ * </table>
+ *
+ * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p>
+ *
+ * @hide
+ */
+
+@libcore.api.CorePlatformApi
+public class FP16 {
+    /**
+     * The number of bits used to represent a half-precision float value.
+     */
+    @libcore.api.CorePlatformApi
+    public static final int SIZE = 16;
+
+    /**
+     * Epsilon is the difference between 1.0 and the next value representable
+     * by a half-precision floating-point.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short EPSILON = (short) 0x1400;
+
+    /**
+     * Maximum exponent a finite half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final int MAX_EXPONENT = 15;
+    /**
+     * Minimum exponent a normalized half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final int MIN_EXPONENT = -14;
+
+    /**
+     * Smallest negative value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short LOWEST_VALUE = (short) 0xfbff;
+    /**
+     * Maximum positive finite value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short MAX_VALUE = (short) 0x7bff;
+    /**
+     * Smallest positive normal value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short MIN_NORMAL = (short) 0x0400;
+    /**
+     * Smallest positive non-zero value a half-precision float may have.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short MIN_VALUE = (short) 0x0001;
+    /**
+     * A Not-a-Number representation of a half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short NaN = (short) 0x7e00;
+    /**
+     * Negative infinity of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short NEGATIVE_INFINITY = (short) 0xfc00;
+    /**
+     * Negative 0 of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short NEGATIVE_ZERO = (short) 0x8000;
+    /**
+     * Positive infinity of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short POSITIVE_INFINITY = (short) 0x7c00;
+    /**
+     * Positive 0 of type half-precision float.
+     */
+    @libcore.api.CorePlatformApi
+    public static final short POSITIVE_ZERO = (short) 0x0000;
+
+    @libcore.api.CorePlatformApi
+    public static final int SIGN_SHIFT                = 15;
+    @libcore.api.CorePlatformApi
+    public static final int EXPONENT_SHIFT            = 10;
+    @libcore.api.CorePlatformApi
+    public static final int SIGN_MASK                 = 0x8000;
+    @libcore.api.CorePlatformApi
+    public static final int SHIFTED_EXPONENT_MASK     = 0x1f;
+    @libcore.api.CorePlatformApi
+    public static final int SIGNIFICAND_MASK          = 0x3ff;
+    @libcore.api.CorePlatformApi
+    public static final int EXPONENT_SIGNIFICAND_MASK = 0x7fff;
+    @libcore.api.CorePlatformApi
+    public static final int EXPONENT_BIAS             = 15;
+
+    private static final int FP32_SIGN_SHIFT            = 31;
+    private static final int FP32_EXPONENT_SHIFT        = 23;
+    private static final int FP32_SHIFTED_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);
+
+    /** Hidden constructor to prevent instantiation. */
+    private FP16() {}
+
+    /**
+     * <p>Compares the two specified half-precision float values. The following
+     * conditions apply during the comparison:</p>
+     *
+     * <ul>
+     * <li>{@link #NaN} is considered by this method to be equal to itself and greater
+     * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li>
+     * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than
+     * {@link #NEGATIVE_ZERO}.</li>
+     * </ul>
+     *
+     * @param x The first half-precision float value to compare.
+     * @param y The second half-precision float value to compare
+     *
+     * @return  The value {@code 0} if {@code x} is numerically equal to {@code y}, a
+     *          value less than {@code 0} if {@code x} is numerically less than {@code y},
+     *          and a value greater than {@code 0} if {@code x} is numerically greater
+     *          than {@code y}
+     */
+    @libcore.api.CorePlatformApi
+    public static int compare(short x, 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 & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY ? NaN : x;
+        short yBits = (y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY ? NaN : y;
+
+        return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1));
+    }
+
+    /**
+     * Returns the closest integral half-precision float value to the specified
+     * half-precision float value. Special values are handled in the
+     * following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The value of the specified half-precision float rounded to the nearest
+     *         half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short rint(short h) {
+        int bits = h & 0xffff;
+        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= 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;
+    }
+
+    /**
+     * Returns the smallest half-precision float value toward negative infinity
+     * greater than or equal to the specified half-precision float value.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The smallest half-precision float value toward negative infinity
+     *         greater than or equal to the specified half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short ceil(short h) {
+        int bits = h & 0xffff;
+        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= 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;
+    }
+
+    /**
+     * Returns the largest half-precision float value toward positive infinity
+     * less than or equal to the specified half-precision float value.
+     * Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The largest half-precision float value toward positive infinity
+     *         less than or equal to the specified half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short floor(short h) {
+        int bits = h & 0xffff;
+        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= 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;
+    }
+
+    /**
+     * Returns the truncated half-precision float value of the specified
+     * half-precision float value. Special values are handled in the following ways:
+     * <ul>
+     * <li>If the specified half-precision float is NaN, the result is NaN</li>
+     * <li>If the specified half-precision float is infinity (negative or positive),
+     * the result is infinity (with the same sign)</li>
+     * <li>If the specified half-precision float is zero (negative or positive),
+     * the result is zero (with the same sign)</li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return The truncated half-precision float value of the specified
+     *         half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short trunc(short h) {
+        int bits = h & 0xffff;
+        int e = bits & EXPONENT_SIGNIFICAND_MASK;
+        int result = bits;
+
+        if (e < 0x3c00) {
+            result &= SIGN_MASK;
+        } else if (e < 0x6400) {
+            e = 25 - (e >> 10);
+            int mask = (1 << e) - 1;
+            result &= ~mask;
+        }
+
+        return (short) result;
+    }
+
+    /**
+     * Returns the smaller of two half-precision float values (the value closest
+     * to negative infinity). Special values are handled in the following ways:
+     * <ul>
+     * <li>If either value is NaN, the result is NaN</li>
+     * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li>
+     * </ul>
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     * @return The smaller of the two specified half-precision values
+     */
+    @libcore.api.CorePlatformApi
+    public static short min(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
+
+        if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+            return (x & SIGN_MASK) != 0 ? x : y;
+        }
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+    }
+
+    /**
+     * Returns the larger of two half-precision float values (the value closest
+     * to positive infinity). Special values are handled in the following ways:
+     * <ul>
+     * <li>If either value is NaN, the result is NaN</li>
+     * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li>
+     * </ul>
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return The larger of the two specified half-precision values
+     */
+    @libcore.api.CorePlatformApi
+    public static short max(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return NaN;
+
+        if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) {
+            return (x & SIGN_MASK) != 0 ? y : x;
+        }
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y;
+    }
+
+    /**
+     * Returns true if the first half-precision float value is less (smaller
+     * toward negative infinity) than the second half-precision float value.
+     * If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is less than y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean less(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is less (smaller
+     * toward negative infinity) than or equal to the second half-precision
+     * float value. If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is less than or equal to y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean lessEquals(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <=
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is greater (larger
+     * toward positive infinity) than the second half-precision float value.
+     * If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is greater than y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean greater(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the first half-precision float value is greater (larger
+     * toward positive infinity) than or equal to the second half-precision float
+     * value. If either of the values is NaN, the result is false.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is greater than y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean greaterEquals(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+
+        return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >=
+               ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff);
+    }
+
+    /**
+     * Returns true if the two half-precision float values are equal.
+     * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO}
+     * and {@link #NEGATIVE_ZERO} are considered equal.
+     *
+     * @param x The first half-precision value
+     * @param y The second half-precision value
+     *
+     * @return True if x is equal to y, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean equals(short x, short y) {
+        if ((x & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+        if ((y & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY) return false;
+
+        return x == y || ((x | y) & EXPONENT_SIGNIFICAND_MASK) == 0;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value represents
+     * infinity, false otherwise.
+     *
+     * @param h A half-precision float value
+     * @return True if the value is positive infinity or negative infinity,
+     *         false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean isInfinite(short h) {
+        return (h & EXPONENT_SIGNIFICAND_MASK) == POSITIVE_INFINITY;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value represents
+     * a Not-a-Number, false otherwise.
+     *
+     * @param h A half-precision float value
+     * @return True if the value is a NaN, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean isNaN(short h) {
+        return (h & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY;
+    }
+
+    /**
+     * Returns true if the specified half-precision float value is normalized
+     * (does not have a subnormal representation). If the specified value is
+     * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY},
+     * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal
+     * number, this method returns false.
+     *
+     * @param h A half-precision float value
+     * @return True if the value is normalized, false otherwise
+     */
+    @libcore.api.CorePlatformApi
+    public static boolean isNormalized(short h) {
+        return (h & POSITIVE_INFINITY) != 0 && (h & POSITIVE_INFINITY) != POSITIVE_INFINITY;
+    }
+
+    /**
+     * <p>Converts the specified half-precision float value into a
+     * single-precision float value. The following special cases are handled:</p>
+     * <ul>
+     * <li>If the input is {@link #NaN}, the returned value is {@link Float#NaN}</li>
+     * <li>If the input is {@link #POSITIVE_INFINITY} or
+     * {@link #NEGATIVE_INFINITY}, the returned value is respectively
+     * {@link Float#POSITIVE_INFINITY} or {@link Float#NEGATIVE_INFINITY}</li>
+     * <li>If the input is 0 (positive or negative), the returned value is +/-0.0f</li>
+     * <li>Otherwise, the returned value is a normalized single-precision float value</li>
+     * </ul>
+     *
+     * @param h The half-precision float value to convert to single-precision
+     * @return A normalized single-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static float toFloat(short h) {
+        int bits = h & 0xffff;
+        int s = bits & SIGN_MASK;
+        int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+        int m = (bits                        ) & 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 - EXPONENT_BIAS + FP32_EXPONENT_BIAS;
+            }
+        }
+
+        int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM;
+        return Float.intBitsToFloat(out);
+    }
+
+    /**
+     * <p>Converts the specified single-precision float value into a
+     * half-precision float value. The following special cases are handled:</p>
+     * <ul>
+     * <li>If the input is NaN (see {@link Float#isNaN(float)}), the returned
+     * value is {@link #NaN}</li>
+     * <li>If the input is {@link Float#POSITIVE_INFINITY} or
+     * {@link Float#NEGATIVE_INFINITY}, the returned value is respectively
+     * {@link #POSITIVE_INFINITY} or {@link #NEGATIVE_INFINITY}</li>
+     * <li>If the input is 0 (positive or negative), the returned value is
+     * {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+     * <li>If the input is a less than {@link #MIN_VALUE}, the returned value
+     * is flushed to {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li>
+     * <li>If the input is a less than {@link #MIN_NORMAL}, the returned value
+     * is a denorm half-precision float</li>
+     * <li>Otherwise, the returned value is rounded to the nearest
+     * representable half-precision float value</li>
+     * </ul>
+     *
+     * @param f The single-precision float value to convert to half-precision
+     * @return A half-precision float value
+     */
+    @libcore.api.CorePlatformApi
+    public static short toHalf(float f) {
+        int bits = Float.floatToRawIntBits(f);
+        int s = (bits >>> FP32_SIGN_SHIFT    );
+        int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_SHIFTED_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 + 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 << EXPONENT_SHIFT) | outM;
+                    out++;
+                    return (short) (out | (s << SIGN_SHIFT));
+                }
+            }
+        }
+
+        return (short) ((s << SIGN_SHIFT) | (outE << EXPONENT_SHIFT) | outM);
+    }
+
+    /**
+     * <p>Returns a hexadecimal string representation of the specified half-precision
+     * float value. If the value is a NaN, the result is <code>"NaN"</code>,
+     * otherwise the result follows this format:</p>
+     * <ul>
+     * <li>If the sign is positive, no sign character appears in the result</li>
+     * <li>If the sign is negative, the first character is <code>'-'</code></li>
+     * <li>If the value is inifinity, the string is <code>"Infinity"</code></li>
+     * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li>
+     * <li>If the value has a normalized representation, the exponent and
+     * significand are represented in the string in two fields. The significand
+     * starts with <code>"0x1."</code> followed by its lowercase hexadecimal
+     * representation. Trailing zeroes are removed unless all digits are 0, then
+     * a single zero is used. The significand representation is followed by the
+     * exponent, represented by <code>"p"</code>, itself followed by a decimal
+     * string of the unbiased exponent</li>
+     * <li>If the value has a subnormal representation, the significand starts
+     * with <code>"0x0."</code> followed by its lowercase hexadecimal
+     * representation. Trailing zeroes are removed unless all digits are 0, then
+     * a single zero is used. The significand representation is followed by the
+     * exponent, represented by <code>"p-14"</code></li>
+     * </ul>
+     *
+     * @param h A half-precision float value
+     * @return A hexadecimal string representation of the specified value
+     */
+    @libcore.api.CorePlatformApi
+    public static String toHexString(short h) {
+        StringBuilder o = new StringBuilder();
+
+        int bits = h & 0xffff;
+        int s = (bits >>> SIGN_SHIFT    );
+        int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK;
+        int m = (bits                   ) & 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 - EXPONENT_BIAS));
+            }
+        }
+
+        return o.toString();
+    }
+}
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index cc59804..b4912a1 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -1326,6 +1326,47 @@
     field public static final String[] STRING;
   }
 
+  public class FP16 {
+    method public static short ceil(short);
+    method public static int compare(short, short);
+    method public static boolean equals(short, short);
+    method public static short floor(short);
+    method public static boolean greater(short, short);
+    method public static boolean greaterEquals(short, short);
+    method public static boolean isInfinite(short);
+    method public static boolean isNaN(short);
+    method public static boolean isNormalized(short);
+    method public static boolean less(short, short);
+    method public static boolean lessEquals(short, short);
+    method public static short max(short, short);
+    method public static short min(short, short);
+    method public static short rint(short);
+    method public static float toFloat(short);
+    method public static short toHalf(float);
+    method public static String toHexString(short);
+    method public static short trunc(short);
+    field public static final short EPSILON = 5120; // 0x1400
+    field public static final int EXPONENT_BIAS = 15; // 0xf
+    field public static final int EXPONENT_SHIFT = 10; // 0xa
+    field public static final int EXPONENT_SIGNIFICAND_MASK = 32767; // 0x7fff
+    field public static final short LOWEST_VALUE = -1025; // 0xfffffbff
+    field public static final int MAX_EXPONENT = 15; // 0xf
+    field public static final short MAX_VALUE = 31743; // 0x7bff
+    field public static final int MIN_EXPONENT = -14; // 0xfffffff2
+    field public static final short MIN_NORMAL = 1024; // 0x400
+    field public static final short MIN_VALUE = 1; // 0x1
+    field public static final short NEGATIVE_INFINITY = -1024; // 0xfffffc00
+    field public static final short NEGATIVE_ZERO = -32768; // 0xffff8000
+    field public static final short NaN = 32256; // 0x7e00
+    field public static final short POSITIVE_INFINITY = 31744; // 0x7c00
+    field public static final short POSITIVE_ZERO = 0; // 0x0
+    field public static final int SHIFTED_EXPONENT_MASK = 31; // 0x1f
+    field public static final int SIGNIFICAND_MASK = 1023; // 0x3ff
+    field public static final int SIGN_MASK = 32768; // 0x8000
+    field public static final int SIGN_SHIFT = 15; // 0xf
+    field public static final int SIZE = 16; // 0x10
+  }
+
   public class HexEncoding {
     method public static byte[] decode(String) throws java.lang.IllegalArgumentException;
     method public static byte[] decode(String, boolean) throws java.lang.IllegalArgumentException;
diff --git a/non_openjdk_java_files.bp b/non_openjdk_java_files.bp
index 0d274ed..c1b3511 100644
--- a/non_openjdk_java_files.bp
+++ b/non_openjdk_java_files.bp
@@ -194,6 +194,7 @@
         "luni/src/main/java/libcore/util/CoreLibraryDebug.java",
         "luni/src/main/java/libcore/util/DebugInfo.java",
         "luni/src/main/java/libcore/util/EmptyArray.java",
+        "luni/src/main/java/libcore/util/FP16.java",
         "luni/src/main/java/libcore/util/HexEncoding.java",
         "luni/src/main/java/libcore/util/NativeAllocationRegistry.java",
         "luni/src/main/java/libcore/util/NonNull.java",