rs_f16_math.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
  8. *
  9. * Developed at SunPro, a Sun Microsystems, Inc. business.
  10. * Permission to use, copy, modify, and distribute this
  11. * software is freely granted, provided that this notice
  12. * is preserved.
  13. * ====================================================
  14. */
  15. #include "rs_core.rsh"
  16. #include "rs_f16_util.h"
  17. // Based on bionic/libm/upstream-freebsd/lib/msun/src/s_copysignf.c
  18. extern half __attribute__((overloadable)) copysign(half x, half y) {
  19. short hx, hy;
  20. GET_HALF_WORD(hx, x);
  21. GET_HALF_WORD(hy, y);
  22. SET_HALF_WORD(x, (hx & 0x7fff) | (hy & 0x8000));
  23. return x;
  24. }
  25. // Based on bionic/libm/upstream-freebsd/lib/msun/src/s_frexpf.c
  26. extern half __attribute__((overloadable)) frexp(half x, int *eptr) {
  27. short hx, ix;
  28. static const half two12 = 4096;
  29. GET_HALF_WORD(hx, x);
  30. ix = hx & 0x7fff;
  31. *eptr = 0;
  32. if (ix >= 0x7c00 || ix == 0) return x; // NaN, infinity or zero
  33. if (ix <= 0x0400) {
  34. // x is subnormal. Scale it by 2^12 (and adjust eptr accordingly) so
  35. // that even the smallest subnormal value becomes normal.
  36. x *= two12;
  37. GET_HALF_WORD(hx, x);
  38. ix = hx & 0x7fff;
  39. *eptr = -12;
  40. }
  41. // Adjust eptr by (non-biased exponent of hx + 1). Set the non-biased
  42. // exponent to be equal to -1 so that abs(hx) is between 0.5 and 1.
  43. *eptr += (ix >> 10) - 14;
  44. hx = (hx & 0x83ff) | 0x3800;
  45. SET_HALF_WORD(x, hx);
  46. return x;
  47. }
  48. // Based on bionic/libm/upstream-freebsd/lib/msun/src/s_ilogbf.c
  49. extern int __attribute__((overloadable)) ilogb(half x) {
  50. const int RS_INT_MAX = 0x7fffffff;
  51. const int RS_INT_MIN = 0x80000000;
  52. short hx, ix;
  53. GET_HALF_WORD(hx, x);
  54. hx &= 0x7fff;
  55. if (hx < 0x0400) { // subnormal
  56. if (hx == 0)
  57. return RS_INT_MIN; // for zero
  58. for (hx <<= 5, ix = -14; hx > 0; hx <<= 1)
  59. ix -= 1;
  60. return ix;
  61. }
  62. else if (hx < 0x7c00) {
  63. return (hx >> 10) - 15;
  64. }
  65. else { // hx >= 0x7c00
  66. return RS_INT_MAX; // for NaN and infinity
  67. }
  68. }
  69. // Based on bionic/libm/upstream-freebsd/lib/msun/src/s_modff.c
  70. extern half __attribute__((overloadable)) modf(half x, half *iptr) {
  71. short i0, j0;
  72. unsigned short i;
  73. GET_HALF_WORD(i0, x);
  74. j0 = ((i0 >> 10) & 0x1f) - 15; // exponent of x
  75. if (j0 < 10) {
  76. if (j0 < 0) { // No integral part
  77. SET_HALF_WORD(*iptr, i0 & 0x8000); // *iptr = +/- 0
  78. return x;
  79. }
  80. else {
  81. i = 0x03ff >> j0; // mask to check fractional parts of x
  82. if ((i0 & i) == 0) { // no bits set in fractional part
  83. *iptr = x;
  84. SET_HALF_WORD(x, i0 & 0x8000);
  85. return x;
  86. }
  87. else {
  88. SET_HALF_WORD(*iptr, i0 & ~i); // zero out fractional parts
  89. return x - *iptr;
  90. }
  91. }
  92. }
  93. else { // No fractional part
  94. unsigned short ix;
  95. *iptr = x;
  96. if (x != x)
  97. return x;
  98. GET_HALF_WORD(ix, x);
  99. SET_HALF_WORD(x, ix & 0x8000); // x = +/- 0
  100. return x;
  101. }
  102. }
  103. // Based on bionic/libm/upstream-freebsd/lib/msun/src/s_nextafterf.c
  104. extern half __attribute__((overloadable)) nextafter(half x, half y) {
  105. short hx, hy, ix, iy;
  106. GET_HALF_WORD(hx, x);
  107. GET_HALF_WORD(hy, y);
  108. ix = hx & 0x7fff; // |x|
  109. iy = hy & 0x7fff; // |y|
  110. if ((ix > 0x7c00) || // x is nan
  111. (iy > 0x7c00)) // y is nan
  112. return x + y; // return nan
  113. if (x == y) return y; // x == y. return y
  114. if (ix == 0) {
  115. SET_HALF_WORD(x, (hy & 0x8000) | 1);
  116. return x;
  117. }
  118. if (hx >= 0) { // x >= 0
  119. if (hx > hy)
  120. hx -= 1; // x > y, x -= 1 ulp
  121. else
  122. hx += 1; // x < y, x += 1 ulp
  123. }
  124. else { // x < 0
  125. if (hy>= 0 || hx > hy)
  126. hx -= 1; // x < y, x -= 1 ulp
  127. else
  128. hx += 1;
  129. }
  130. SET_HALF_WORD(x, hx);
  131. return x;
  132. }