1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.util; 18 19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import android.annotation.SystemApi; 22 23 /** 24 * <p>The {@code FP16} class is a wrapper and a utility class to manipulate half-precision 16-bit 25 * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a> 26 * floating point data types (also called fp16 or binary16). A half-precision float can be 27 * created from or converted to single-precision floats, and is stored in a short data type. 28 * 29 * <p>The IEEE 754 standard specifies an fp16 as having the following format:</p> 30 * <ul> 31 * <li>Sign bit: 1 bit</li> 32 * <li>Exponent width: 5 bits</li> 33 * <li>Significand: 10 bits</li> 34 * </ul> 35 * 36 * <p>The format is laid out as follows:</p> 37 * <pre> 38 * 1 11111 1111111111 39 * ^ --^-- -----^---- 40 * sign | |_______ significand 41 * | 42 * -- exponent 43 * </pre> 44 * 45 * <p>Half-precision floating points can be useful to save memory and/or 46 * bandwidth at the expense of range and precision when compared to single-precision 47 * floating points (fp32).</p> 48 * <p>To help you decide whether fp16 is the right storage type for you need, please 49 * refer to the table below that shows the available precision throughout the range of 50 * possible values. The <em>precision</em> column indicates the step size between two 51 * consecutive numbers in a specific part of the range.</p> 52 * 53 * <table summary="Precision of fp16 across the range"> 54 * <tr><th>Range start</th><th>Precision</th></tr> 55 * <tr><td>0</td><td>1 ⁄ 16,777,216</td></tr> 56 * <tr><td>1 ⁄ 16,384</td><td>1 ⁄ 16,777,216</td></tr> 57 * <tr><td>1 ⁄ 8,192</td><td>1 ⁄ 8,388,608</td></tr> 58 * <tr><td>1 ⁄ 4,096</td><td>1 ⁄ 4,194,304</td></tr> 59 * <tr><td>1 ⁄ 2,048</td><td>1 ⁄ 2,097,152</td></tr> 60 * <tr><td>1 ⁄ 1,024</td><td>1 ⁄ 1,048,576</td></tr> 61 * <tr><td>1 ⁄ 512</td><td>1 ⁄ 524,288</td></tr> 62 * <tr><td>1 ⁄ 256</td><td>1 ⁄ 262,144</td></tr> 63 * <tr><td>1 ⁄ 128</td><td>1 ⁄ 131,072</td></tr> 64 * <tr><td>1 ⁄ 64</td><td>1 ⁄ 65,536</td></tr> 65 * <tr><td>1 ⁄ 32</td><td>1 ⁄ 32,768</td></tr> 66 * <tr><td>1 ⁄ 16</td><td>1 ⁄ 16,384</td></tr> 67 * <tr><td>1 ⁄ 8</td><td>1 ⁄ 8,192</td></tr> 68 * <tr><td>1 ⁄ 4</td><td>1 ⁄ 4,096</td></tr> 69 * <tr><td>1 ⁄ 2</td><td>1 ⁄ 2,048</td></tr> 70 * <tr><td>1</td><td>1 ⁄ 1,024</td></tr> 71 * <tr><td>2</td><td>1 ⁄ 512</td></tr> 72 * <tr><td>4</td><td>1 ⁄ 256</td></tr> 73 * <tr><td>8</td><td>1 ⁄ 128</td></tr> 74 * <tr><td>16</td><td>1 ⁄ 64</td></tr> 75 * <tr><td>32</td><td>1 ⁄ 32</td></tr> 76 * <tr><td>64</td><td>1 ⁄ 16</td></tr> 77 * <tr><td>128</td><td>1 ⁄ 8</td></tr> 78 * <tr><td>256</td><td>1 ⁄ 4</td></tr> 79 * <tr><td>512</td><td>1 ⁄ 2</td></tr> 80 * <tr><td>1,024</td><td>1</td></tr> 81 * <tr><td>2,048</td><td>2</td></tr> 82 * <tr><td>4,096</td><td>4</td></tr> 83 * <tr><td>8,192</td><td>8</td></tr> 84 * <tr><td>16,384</td><td>16</td></tr> 85 * <tr><td>32,768</td><td>32</td></tr> 86 * </table> 87 * 88 * <p>This table shows that numbers higher than 1024 lose all fractional precision.</p> 89 * 90 * @hide 91 */ 92 93 @SystemApi(client = MODULE_LIBRARIES) 94 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 95 public final class FP16 { 96 /** 97 * The number of bits used to represent a half-precision float value. 98 * 99 * @hide 100 */ 101 @SystemApi(client = MODULE_LIBRARIES) 102 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 103 public static final int SIZE = 16; 104 105 /** 106 * Epsilon is the difference between 1.0 and the next value representable 107 * by a half-precision floating-point. 108 * 109 * @hide 110 */ 111 @SystemApi(client = MODULE_LIBRARIES) 112 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 113 public static final short EPSILON = (short) 0x1400; 114 115 /** 116 * Maximum exponent a finite half-precision float may have. 117 * 118 * @hide 119 */ 120 @SystemApi(client = MODULE_LIBRARIES) 121 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 122 public static final int MAX_EXPONENT = 15; 123 /** 124 * Minimum exponent a normalized half-precision float may have. 125 * 126 * @hide 127 */ 128 @SystemApi(client = MODULE_LIBRARIES) 129 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 130 public static final int MIN_EXPONENT = -14; 131 132 /** 133 * Smallest negative value a half-precision float may have. 134 * 135 * @hide 136 */ 137 @SystemApi(client = MODULE_LIBRARIES) 138 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 139 public static final short LOWEST_VALUE = (short) 0xfbff; 140 /** 141 * Maximum positive finite value a half-precision float may have. 142 * 143 * @hide 144 */ 145 @SystemApi(client = MODULE_LIBRARIES) 146 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 147 public static final short MAX_VALUE = (short) 0x7bff; 148 /** 149 * Smallest positive normal value a half-precision float may have. 150 * 151 * @hide 152 */ 153 @SystemApi(client = MODULE_LIBRARIES) 154 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 155 public static final short MIN_NORMAL = (short) 0x0400; 156 /** 157 * Smallest positive non-zero value a half-precision float may have. 158 * 159 * @hide 160 */ 161 @SystemApi(client = MODULE_LIBRARIES) 162 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 163 public static final short MIN_VALUE = (short) 0x0001; 164 /** 165 * A Not-a-Number representation of a half-precision float. 166 * 167 * @hide 168 */ 169 @SystemApi(client = MODULE_LIBRARIES) 170 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 171 public static final short NaN = (short) 0x7e00; 172 /** 173 * Negative infinity of type half-precision float. 174 * 175 * @hide 176 */ 177 @SystemApi(client = MODULE_LIBRARIES) 178 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 179 public static final short NEGATIVE_INFINITY = (short) 0xfc00; 180 /** 181 * Negative 0 of type half-precision float. 182 * 183 * @hide 184 */ 185 @SystemApi(client = MODULE_LIBRARIES) 186 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 187 public static final short NEGATIVE_ZERO = (short) 0x8000; 188 /** 189 * Positive infinity of type half-precision float. 190 * 191 * @hide 192 */ 193 @SystemApi(client = MODULE_LIBRARIES) 194 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 195 public static final short POSITIVE_INFINITY = (short) 0x7c00; 196 /** 197 * Positive 0 of type half-precision float. 198 * 199 * @hide 200 */ 201 @SystemApi(client = MODULE_LIBRARIES) 202 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 203 public static final short POSITIVE_ZERO = (short) 0x0000; 204 205 /** 206 * The offset to shift by to obtain the sign bit. 207 * 208 * @hide 209 */ 210 @SystemApi(client = MODULE_LIBRARIES) 211 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 212 public static final int SIGN_SHIFT = 15; 213 214 /** 215 * The offset to shift by to obtain the exponent bits. 216 * 217 * @hide 218 */ 219 @SystemApi(client = MODULE_LIBRARIES) 220 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 221 public static final int EXPONENT_SHIFT = 10; 222 223 /** 224 * The bitmask to AND a number with to obtain the sign bit. 225 * 226 * @hide 227 */ 228 @SystemApi(client = MODULE_LIBRARIES) 229 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 230 public static final int SIGN_MASK = 0x8000; 231 232 /** 233 * The bitmask to AND a number shifted by {@link #EXPONENT_SHIFT} right, to obtain exponent bits. 234 * 235 * @hide 236 */ 237 @SystemApi(client = MODULE_LIBRARIES) 238 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 239 public static final int SHIFTED_EXPONENT_MASK = 0x1f; 240 241 /** 242 * The bitmask to AND a number with to obtain significand bits. 243 * 244 * @hide 245 */ 246 @SystemApi(client = MODULE_LIBRARIES) 247 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 248 public static final int SIGNIFICAND_MASK = 0x3ff; 249 250 /** 251 * The bitmask to AND with to obtain exponent and significand bits. 252 * 253 * @hide 254 */ 255 @SystemApi(client = MODULE_LIBRARIES) 256 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 257 public static final int EXPONENT_SIGNIFICAND_MASK = 0x7fff; 258 259 /** 260 * The offset of the exponent from the actual value. 261 * 262 * @hide 263 */ 264 @SystemApi(client = MODULE_LIBRARIES) 265 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) 266 public static final int EXPONENT_BIAS = 15; 267 268 private static final int FP32_SIGN_SHIFT = 31; 269 private static final int FP32_EXPONENT_SHIFT = 23; 270 private static final int FP32_SHIFTED_EXPONENT_MASK = 0xff; 271 private static final int FP32_SIGNIFICAND_MASK = 0x7fffff; 272 private static final int FP32_EXPONENT_BIAS = 127; 273 private static final int FP32_QNAN_MASK = 0x400000; 274 private static final int FP32_DENORMAL_MAGIC = 126 << 23; 275 private static final float FP32_DENORMAL_FLOAT = Float.intBitsToFloat(FP32_DENORMAL_MAGIC); 276 277 /** Hidden constructor to prevent instantiation. */ FP16()278 private FP16() {} 279 280 /** 281 * <p>Compares the two specified half-precision float values. The following 282 * conditions apply during the comparison:</p> 283 * 284 * <ul> 285 * <li>{@link #NaN} is considered by this method to be equal to itself and greater 286 * than all other half-precision float values (including {@code #POSITIVE_INFINITY})</li> 287 * <li>{@link #POSITIVE_ZERO} is considered by this method to be greater than 288 * {@link #NEGATIVE_ZERO}.</li> 289 * </ul> 290 * 291 * @param x The first half-precision float value to compare. 292 * @param y The second half-precision float value to compare 293 * 294 * @return The value {@code 0} if {@code x} is numerically equal to {@code y}, a 295 * value less than {@code 0} if {@code x} is numerically less than {@code y}, 296 * and a value greater than {@code 0} if {@code x} is numerically greater 297 * than {@code y} 298 * 299 * @hide 300 */ 301 @SystemApi(client = MODULE_LIBRARIES) 302 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) compare(short x, short y)303 public static int compare(short x, short y) { 304 if (less(x, y)) return -1; 305 if (greater(x, y)) return 1; 306 307 // Collapse NaNs, akin to halfToIntBits(), but we want to keep 308 // (signed) short value types to preserve the ordering of -0.0 309 // and +0.0 310 short xBits = isNaN(x) ? NaN : x; 311 short yBits = isNaN(y) ? NaN : y; 312 313 return (xBits == yBits ? 0 : (xBits < yBits ? -1 : 1)); 314 } 315 316 /** 317 * Returns the closest integral half-precision float value to the specified 318 * half-precision float value. Special values are handled in the 319 * following ways: 320 * <ul> 321 * <li>If the specified half-precision float is NaN, the result is NaN</li> 322 * <li>If the specified half-precision float is infinity (negative or positive), 323 * the result is infinity (with the same sign)</li> 324 * <li>If the specified half-precision float is zero (negative or positive), 325 * the result is zero (with the same sign)</li> 326 * </ul> 327 * 328 * @param h A half-precision float value 329 * @return The value of the specified half-precision float rounded to the nearest 330 * half-precision float value 331 * 332 * @hide 333 */ 334 @SystemApi(client = MODULE_LIBRARIES) 335 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) rint(short h)336 public static short rint(short h) { 337 int bits = h & 0xffff; 338 int abs = bits & EXPONENT_SIGNIFICAND_MASK; 339 int result = bits; 340 341 if (abs < 0x3c00) { 342 result &= SIGN_MASK; 343 if (abs > 0x3800){ 344 result |= 0x3c00; 345 } 346 } else if (abs < 0x6400) { 347 int exp = 25 - (abs >> 10); 348 int mask = (1 << exp) - 1; 349 result += ((1 << (exp - 1)) - (~(abs >> exp) & 1)); 350 result &= ~mask; 351 } 352 if (isNaN((short) result)) { 353 // if result is NaN mask with qNaN 354 // (i.e. mask the most significant mantissa bit with 1) 355 // to comply with hardware implementations (ARM64, Intel, etc). 356 result |= NaN; 357 } 358 359 return (short) result; 360 } 361 362 /** 363 * Returns the smallest half-precision float value toward negative infinity 364 * greater than or equal to the specified half-precision float value. 365 * Special values are handled in the following ways: 366 * <ul> 367 * <li>If the specified half-precision float is NaN, the result is NaN</li> 368 * <li>If the specified half-precision float is infinity (negative or positive), 369 * the result is infinity (with the same sign)</li> 370 * <li>If the specified half-precision float is zero (negative or positive), 371 * the result is zero (with the same sign)</li> 372 * </ul> 373 * 374 * @param h A half-precision float value 375 * @return The smallest half-precision float value toward negative infinity 376 * greater than or equal to the specified half-precision float value 377 * 378 * @hide 379 */ 380 @SystemApi(client = MODULE_LIBRARIES) 381 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) ceil(short h)382 public static short ceil(short h) { 383 int bits = h & 0xffff; 384 int abs = bits & EXPONENT_SIGNIFICAND_MASK; 385 int result = bits; 386 387 if (abs < 0x3c00) { 388 result &= SIGN_MASK; 389 result |= 0x3c00 & -(~(bits >> 15) & (abs != 0 ? 1 : 0)); 390 } else if (abs < 0x6400) { 391 abs = 25 - (abs >> 10); 392 int mask = (1 << abs) - 1; 393 result += mask & ((bits >> 15) - 1); 394 result &= ~mask; 395 } 396 if (isNaN((short) result)) { 397 // if result is NaN mask with qNaN 398 // (i.e. mask the most significant mantissa bit with 1) 399 // to comply with hardware implementations (ARM64, Intel, etc). 400 result |= NaN; 401 } 402 403 return (short) result; 404 } 405 406 /** 407 * Returns the largest half-precision float value toward positive infinity 408 * less than or equal to the specified half-precision float value. 409 * Special values are handled in the following ways: 410 * <ul> 411 * <li>If the specified half-precision float is NaN, the result is NaN</li> 412 * <li>If the specified half-precision float is infinity (negative or positive), 413 * the result is infinity (with the same sign)</li> 414 * <li>If the specified half-precision float is zero (negative or positive), 415 * the result is zero (with the same sign)</li> 416 * </ul> 417 * 418 * @param h A half-precision float value 419 * @return The largest half-precision float value toward positive infinity 420 * less than or equal to the specified half-precision float value 421 * 422 * @hide 423 */ 424 @SystemApi(client = MODULE_LIBRARIES) 425 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) floor(short h)426 public static short floor(short h) { 427 int bits = h & 0xffff; 428 int abs = bits & EXPONENT_SIGNIFICAND_MASK; 429 int result = bits; 430 431 if (abs < 0x3c00) { 432 result &= SIGN_MASK; 433 result |= 0x3c00 & (bits > 0x8000 ? 0xffff : 0x0); 434 } else if (abs < 0x6400) { 435 abs = 25 - (abs >> 10); 436 int mask = (1 << abs) - 1; 437 result += mask & -(bits >> 15); 438 result &= ~mask; 439 } 440 if (isNaN((short) result)) { 441 // if result is NaN mask with qNaN 442 // i.e. (Mask the most significant mantissa bit with 1) 443 result |= NaN; 444 } 445 446 return (short) result; 447 } 448 449 /** 450 * Returns the truncated half-precision float value of the specified 451 * half-precision float value. Special values are handled in the following ways: 452 * <ul> 453 * <li>If the specified half-precision float is NaN, the result is NaN</li> 454 * <li>If the specified half-precision float is infinity (negative or positive), 455 * the result is infinity (with the same sign)</li> 456 * <li>If the specified half-precision float is zero (negative or positive), 457 * the result is zero (with the same sign)</li> 458 * </ul> 459 * 460 * @param h A half-precision float value 461 * @return The truncated half-precision float value of the specified 462 * half-precision float value 463 * 464 * @hide 465 */ 466 @SystemApi(client = MODULE_LIBRARIES) 467 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) trunc(short h)468 public static short trunc(short h) { 469 int bits = h & 0xffff; 470 int abs = bits & EXPONENT_SIGNIFICAND_MASK; 471 int result = bits; 472 473 if (abs < 0x3c00) { 474 result &= SIGN_MASK; 475 } else if (abs < 0x6400) { 476 abs = 25 - (abs >> 10); 477 int mask = (1 << abs) - 1; 478 result &= ~mask; 479 } 480 481 return (short) result; 482 } 483 484 /** 485 * Returns the smaller of two half-precision float values (the value closest 486 * to negative infinity). Special values are handled in the following ways: 487 * <ul> 488 * <li>If either value is NaN, the result is NaN</li> 489 * <li>{@link #NEGATIVE_ZERO} is smaller than {@link #POSITIVE_ZERO}</li> 490 * </ul> 491 * 492 * @param x The first half-precision value 493 * @param y The second half-precision value 494 * @return The smaller of the two specified half-precision values 495 * 496 * @hide 497 */ 498 @SystemApi(client = MODULE_LIBRARIES) 499 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) min(short x, short y)500 public static short min(short x, short y) { 501 if (isNaN(x)) return NaN; 502 if (isNaN(y)) return NaN; 503 504 if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) { 505 return (x & SIGN_MASK) != 0 ? x : y; 506 } 507 508 return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < 509 ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; 510 } 511 512 /** 513 * Returns the larger of two half-precision float values (the value closest 514 * to positive infinity). Special values are handled in the following ways: 515 * <ul> 516 * <li>If either value is NaN, the result is NaN</li> 517 * <li>{@link #POSITIVE_ZERO} is greater than {@link #NEGATIVE_ZERO}</li> 518 * </ul> 519 * 520 * @param x The first half-precision value 521 * @param y The second half-precision value 522 * 523 * @return The larger of the two specified half-precision values 524 * 525 * @hide 526 */ 527 @SystemApi(client = MODULE_LIBRARIES) 528 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) max(short x, short y)529 public static short max(short x, short y) { 530 if (isNaN(x)) return NaN; 531 if (isNaN(y)) return NaN; 532 533 if ((x & EXPONENT_SIGNIFICAND_MASK) == 0 && (y & EXPONENT_SIGNIFICAND_MASK) == 0) { 534 return (x & SIGN_MASK) != 0 ? y : x; 535 } 536 537 return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > 538 ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff) ? x : y; 539 } 540 541 /** 542 * Returns true if the first half-precision float value is less (smaller 543 * toward negative infinity) than the second half-precision float value. 544 * If either of the values is NaN, the result is false. 545 * 546 * @param x The first half-precision value 547 * @param y The second half-precision value 548 * 549 * @return True if x is less than y, false otherwise 550 * 551 * @hide 552 */ 553 @SystemApi(client = MODULE_LIBRARIES) 554 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) less(short x, short y)555 public static boolean less(short x, short y) { 556 if (isNaN(x)) return false; 557 if (isNaN(y)) return false; 558 559 return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) < 560 ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); 561 } 562 563 /** 564 * Returns true if the first half-precision float value is less (smaller 565 * toward negative infinity) than or equal to the second half-precision 566 * float value. If either of the values is NaN, the result is false. 567 * 568 * @param x The first half-precision value 569 * @param y The second half-precision value 570 * 571 * @return True if x is less than or equal to y, false otherwise 572 * 573 * @hide 574 */ 575 @SystemApi(client = MODULE_LIBRARIES) 576 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) lessEquals(short x, short y)577 public static boolean lessEquals(short x, short y) { 578 if (isNaN(x)) return false; 579 if (isNaN(y)) return false; 580 581 return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) <= 582 ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); 583 } 584 585 /** 586 * Returns true if the first half-precision float value is greater (larger 587 * toward positive infinity) than the second half-precision float value. 588 * If either of the values is NaN, the result is false. 589 * 590 * @param x The first half-precision value 591 * @param y The second half-precision value 592 * 593 * @return True if x is greater than y, false otherwise 594 * 595 * @hide 596 */ 597 @SystemApi(client = MODULE_LIBRARIES) 598 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) greater(short x, short y)599 public static boolean greater(short x, short y) { 600 if (isNaN(x)) return false; 601 if (isNaN(y)) return false; 602 603 return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) > 604 ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); 605 } 606 607 /** 608 * Returns true if the first half-precision float value is greater (larger 609 * toward positive infinity) than or equal to the second half-precision float 610 * value. If either of the values is NaN, the result is false. 611 * 612 * @param x The first half-precision value 613 * @param y The second half-precision value 614 * 615 * @return True if x is greater than y, false otherwise 616 * 617 * @hide 618 */ 619 @SystemApi(client = MODULE_LIBRARIES) 620 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) greaterEquals(short x, short y)621 public static boolean greaterEquals(short x, short y) { 622 if (isNaN(x)) return false; 623 if (isNaN(y)) return false; 624 625 return ((x & SIGN_MASK) != 0 ? 0x8000 - (x & 0xffff) : x & 0xffff) >= 626 ((y & SIGN_MASK) != 0 ? 0x8000 - (y & 0xffff) : y & 0xffff); 627 } 628 629 /** 630 * Returns true if the two half-precision float values are equal. 631 * If either of the values is NaN, the result is false. {@link #POSITIVE_ZERO} 632 * and {@link #NEGATIVE_ZERO} are considered equal. 633 * 634 * @param x The first half-precision value 635 * @param y The second half-precision value 636 * 637 * @return True if x is equal to y, false otherwise 638 * 639 * @hide 640 */ 641 @SystemApi(client = MODULE_LIBRARIES) 642 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) equals(short x, short y)643 public static boolean equals(short x, short y) { 644 if (isNaN(x)) return false; 645 if (isNaN(y)) return false; 646 647 return x == y || ((x | y) & EXPONENT_SIGNIFICAND_MASK) == 0; 648 } 649 650 /** 651 * Returns true if the specified half-precision float value represents 652 * infinity, false otherwise. 653 * 654 * @param h A half-precision float value 655 * @return True if the value is positive infinity or negative infinity, 656 * false otherwise 657 * 658 * @hide 659 */ 660 @SystemApi(client = MODULE_LIBRARIES) 661 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) isInfinite(short h)662 public static boolean isInfinite(short h) { 663 return (h & EXPONENT_SIGNIFICAND_MASK) == POSITIVE_INFINITY; 664 } 665 666 /** 667 * Returns true if the specified half-precision float value represents 668 * a Not-a-Number, false otherwise. 669 * 670 * @param h A half-precision float value 671 * @return True if the value is a NaN, false otherwise 672 * 673 * @hide 674 */ 675 @SystemApi(client = MODULE_LIBRARIES) 676 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) isNaN(short h)677 public static boolean isNaN(short h) { 678 return (h & EXPONENT_SIGNIFICAND_MASK) > POSITIVE_INFINITY; 679 } 680 681 /** 682 * Returns true if the specified half-precision float value is normalized 683 * (does not have a subnormal representation). If the specified value is 684 * {@link #POSITIVE_INFINITY}, {@link #NEGATIVE_INFINITY}, 685 * {@link #POSITIVE_ZERO}, {@link #NEGATIVE_ZERO}, NaN or any subnormal 686 * number, this method returns false. 687 * 688 * @param h A half-precision float value 689 * @return True if the value is normalized, false otherwise 690 * 691 * @hide 692 */ 693 @SystemApi(client = MODULE_LIBRARIES) 694 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) isNormalized(short h)695 public static boolean isNormalized(short h) { 696 return (h & POSITIVE_INFINITY) != 0 && (h & POSITIVE_INFINITY) != POSITIVE_INFINITY; 697 } 698 699 /** 700 * <p>Converts the specified half-precision float value into a 701 * single-precision float value. The following special cases are handled:</p> 702 * <ul> 703 * <li>If the input is {@link #NaN}, the returned value is {@link Float#NaN}</li> 704 * <li>If the input is {@link #POSITIVE_INFINITY} or 705 * {@link #NEGATIVE_INFINITY}, the returned value is respectively 706 * {@link Float#POSITIVE_INFINITY} or {@link Float#NEGATIVE_INFINITY}</li> 707 * <li>If the input is 0 (positive or negative), the returned value is +/-0.0f</li> 708 * <li>Otherwise, the returned value is a normalized single-precision float value</li> 709 * </ul> 710 * 711 * @param h The half-precision float value to convert to single-precision 712 * @return A normalized single-precision float value 713 * 714 * @hide 715 */ 716 @SystemApi(client = MODULE_LIBRARIES) 717 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) toFloat(short h)718 public static float toFloat(short h) { 719 int bits = h & 0xffff; 720 int s = bits & SIGN_MASK; 721 int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK; 722 int m = (bits ) & SIGNIFICAND_MASK; 723 724 int outE = 0; 725 int outM = 0; 726 727 if (e == 0) { // Denormal or 0 728 if (m != 0) { 729 // Convert denorm fp16 into normalized fp32 730 float o = Float.intBitsToFloat(FP32_DENORMAL_MAGIC + m); 731 o -= FP32_DENORMAL_FLOAT; 732 return s == 0 ? o : -o; 733 } 734 } else { 735 outM = m << 13; 736 if (e == 0x1f) { // Infinite or NaN 737 outE = 0xff; 738 if (outM != 0) { // SNaNs are quieted 739 outM |= FP32_QNAN_MASK; 740 } 741 } else { 742 outE = e - EXPONENT_BIAS + FP32_EXPONENT_BIAS; 743 } 744 } 745 746 int out = (s << 16) | (outE << FP32_EXPONENT_SHIFT) | outM; 747 return Float.intBitsToFloat(out); 748 } 749 750 /** 751 * <p>Converts the specified single-precision float value into a 752 * half-precision float value. The following special cases are handled:</p> 753 * <ul> 754 * <li>If the input is NaN (see {@link Float#isNaN(float)}), the returned 755 * value is {@link #NaN}</li> 756 * <li>If the input is {@link Float#POSITIVE_INFINITY} or 757 * {@link Float#NEGATIVE_INFINITY}, the returned value is respectively 758 * {@link #POSITIVE_INFINITY} or {@link #NEGATIVE_INFINITY}</li> 759 * <li>If the input is 0 (positive or negative), the returned value is 760 * {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li> 761 * <li>If the input is a less than {@link #MIN_VALUE}, the returned value 762 * is flushed to {@link #POSITIVE_ZERO} or {@link #NEGATIVE_ZERO}</li> 763 * <li>If the input is a less than {@link #MIN_NORMAL}, the returned value 764 * is a denorm half-precision float</li> 765 * <li>Otherwise, the returned value is rounded to the nearest 766 * representable half-precision float value</li> 767 * </ul> 768 * 769 * @param f The single-precision float value to convert to half-precision 770 * @return A half-precision float value 771 * 772 * @hide 773 */ 774 @SystemApi(client = MODULE_LIBRARIES) 775 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) toHalf(float f)776 public static short toHalf(float f) { 777 int bits = Float.floatToRawIntBits(f); 778 int s = (bits >>> FP32_SIGN_SHIFT ); 779 int e = (bits >>> FP32_EXPONENT_SHIFT) & FP32_SHIFTED_EXPONENT_MASK; 780 int m = (bits ) & FP32_SIGNIFICAND_MASK; 781 782 int outE = 0; 783 int outM = 0; 784 785 if (e == 0xff) { // Infinite or NaN 786 outE = 0x1f; 787 outM = m != 0 ? 0x200 : 0; 788 } else { 789 e = e - FP32_EXPONENT_BIAS + EXPONENT_BIAS; 790 if (e >= 0x1f) { // Overflow 791 outE = 0x1f; 792 } else if (e <= 0) { // Underflow 793 if (e < -10) { 794 // The absolute fp32 value is less than MIN_VALUE, flush to +/-0 795 } else { 796 // The fp32 value is a normalized float less than MIN_NORMAL, 797 // we convert to a denorm fp16 798 m = m | 0x800000; 799 int shift = 14 - e; 800 outM = m >> shift; 801 802 int lowm = m & ((1 << shift) - 1); 803 int hway = 1 << (shift - 1); 804 // if above halfway or exactly halfway and outM is odd 805 if (lowm + (outM & 1) > hway){ 806 // Round to nearest even 807 // Can overflow into exponent bit, which surprisingly is OK. 808 // This increment relies on the +outM in the return statement below 809 outM++; 810 } 811 } 812 } else { 813 outE = e; 814 outM = m >> 13; 815 // if above halfway or exactly halfway and outM is odd 816 if ((m & 0x1fff) + (outM & 0x1) > 0x1000) { 817 // Round to nearest even 818 // Can overflow into exponent bit, which surprisingly is OK. 819 // This increment relies on the +outM in the return statement below 820 outM++; 821 } 822 } 823 } 824 // The outM is added here as the +1 increments for outM above can 825 // cause an overflow in the exponent bit which is OK. 826 return (short) ((s << SIGN_SHIFT) | (outE << EXPONENT_SHIFT) + outM); 827 } 828 829 /** 830 * <p>Returns a hexadecimal string representation of the specified half-precision 831 * float value. If the value is a NaN, the result is <code>"NaN"</code>, 832 * otherwise the result follows this format:</p> 833 * <ul> 834 * <li>If the sign is positive, no sign character appears in the result</li> 835 * <li>If the sign is negative, the first character is <code>'-'</code></li> 836 * <li>If the value is inifinity, the string is <code>"Infinity"</code></li> 837 * <li>If the value is 0, the string is <code>"0x0.0p0"</code></li> 838 * <li>If the value has a normalized representation, the exponent and 839 * significand are represented in the string in two fields. The significand 840 * starts with <code>"0x1."</code> followed by its lowercase hexadecimal 841 * representation. Trailing zeroes are removed unless all digits are 0, then 842 * a single zero is used. The significand representation is followed by the 843 * exponent, represented by <code>"p"</code>, itself followed by a decimal 844 * string of the unbiased exponent</li> 845 * <li>If the value has a subnormal representation, the significand starts 846 * with <code>"0x0."</code> followed by its lowercase hexadecimal 847 * representation. Trailing zeroes are removed unless all digits are 0, then 848 * a single zero is used. The significand representation is followed by the 849 * exponent, represented by <code>"p-14"</code></li> 850 * </ul> 851 * 852 * @param h A half-precision float value 853 * @return A hexadecimal string representation of the specified value 854 * 855 * @hide 856 */ 857 @SystemApi(client = MODULE_LIBRARIES) 858 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE) toHexString(short h)859 public static String toHexString(short h) { 860 StringBuilder o = new StringBuilder(); 861 862 int bits = h & 0xffff; 863 int s = (bits >>> SIGN_SHIFT ); 864 int e = (bits >>> EXPONENT_SHIFT) & SHIFTED_EXPONENT_MASK; 865 int m = (bits ) & SIGNIFICAND_MASK; 866 867 if (e == 0x1f) { // Infinite or NaN 868 if (m == 0) { 869 if (s != 0) o.append('-'); 870 o.append("Infinity"); 871 } else { 872 o.append("NaN"); 873 } 874 } else { 875 if (s == 1) o.append('-'); 876 if (e == 0) { 877 if (m == 0) { 878 o.append("0x0.0p0"); 879 } else { 880 o.append("0x0."); 881 String significand = Integer.toHexString(m); 882 o.append(significand.replaceFirst("0{2,}$", "")); 883 o.append("p-14"); 884 } 885 } else { 886 o.append("0x1."); 887 String significand = Integer.toHexString(m); 888 o.append(significand.replaceFirst("0{2,}$", "")); 889 o.append('p'); 890 o.append(Integer.toString(e - EXPONENT_BIAS)); 891 } 892 } 893 894 return o.toString(); 895 } 896 } 897