rs_f16_math.c revision f9760483073d9f452e4701fbf367dc518f7e6531
1/* Implementations for copysign, ilogb, and nextafter for float16 based on
2 * corresponding float32 implementations in
3 * bionic/libm/upstream-freebsd/lib/msun/src
4 */
5
6/*
7 * ====================================================
8 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
9 *
10 * Developed at SunPro, a Sun Microsystems, Inc. business.
11 * Permission to use, copy, modify, and distribute this
12 * software is freely granted, provided that this notice
13 * is preserved.
14 * ====================================================
15 */
16
17#include "rs_core.rsh"
18#include "rs_f16_util.h"
19
20// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_copysignf.c
21extern half __attribute__((overloadable)) copysign(half x, half y) {
22    short hx, hy;
23    GET_HALF_WORD(hx, x);
24    GET_HALF_WORD(hy, y);
25
26    SET_HALF_WORD(hx, (hx & 0x7fff) | (hy & 0x8000));
27    return x;
28}
29
30// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_ilogbf.c
31extern int __attribute__((overloadable)) ilogb(half x) {
32    const int RS_INT_MAX = 0x7fffffff;
33    const int RS_INT_MIN = 0x80000000;
34
35    short hx, ix;
36    GET_HALF_WORD(hx, x);
37    hx &= 0x7fff;
38
39    if (hx < 0x0400) { // subnormal
40        if (hx == 0)
41            return RS_INT_MIN; // for zero
42        for (hx <<= 5, ix = -14; hx > 0; hx <<= 1)
43            ix -= 1;
44        return ix;
45    }
46    else if (hx < 0x7c00) {
47        return (hx >> 10) - 15;
48    }
49    else { // hx >= 0x7c00
50        return RS_INT_MAX; // for NaN and infinity
51    }
52}
53
54// Based on bionic/libm/upstream-freebsd/lib/msun/src/s_nextafterf.c
55extern half __attribute__((overloadable)) nextafter(half x, half y) {
56  volatile half t;
57  short hx, hy, ix, iy;
58
59  GET_HALF_WORD(hx, x);
60  GET_HALF_WORD(hy, y);
61  ix = hx & 0x7fff; // |x|
62  iy = hy & 0x7fff; // |y|
63
64  if ((ix > 0x7c00) || // x is nan
65      (iy > 0x7c00))   // y is nan
66    return x + y;      // return nan
67
68  if (x == y) return y; // x == y.  return y
69  if (ix == 0) {
70    SET_HALF_WORD(x, (hy & 0x8000) | 1);
71    return x;
72  }
73
74  if (hx >= 0) {  // x >= 0
75    if (hx > hy)
76      hx -= 1;    // x > y, x -= 1 ulp
77    else
78      hx += 1;    // x < y, x += 1 ulp
79  }
80  else {          // x < 0
81    if (hy>= 0 || hx > hy)
82      hx -= 1;    // x < y, x -= 1 ulp
83    else
84      hx += 1;
85  }
86
87  SET_HALF_WORD(x, hx);
88  return x;
89}
90