math_err.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* Double-precision math error handling.
  2. Copyright (C) 2018-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <math-barriers.h>
  16. #include "math_config.h"
  17. #if WANT_ERRNO
  18. #include <errno.h>
  19. /* NOINLINE reduces code size and avoids making math functions non-leaf
  20. when the error handling is inlined. */
  21. NOINLINE static double
  22. with_errno (double y, int e)
  23. {
  24. errno = e;
  25. return y;
  26. }
  27. NOINLINE static int
  28. with_errno_i (int y, int e)
  29. {
  30. errno = e;
  31. return y;
  32. }
  33. NOINLINE static long int
  34. with_errno_li (long int y, int e)
  35. {
  36. errno = e;
  37. return y;
  38. }
  39. #else
  40. #define with_errno(x, e) (x)
  41. #define with_errno_i(x, e) (x)
  42. #define with_errno_li(x, e) (x)
  43. #endif
  44. attribute_hidden double
  45. __math_edom (double y)
  46. {
  47. return with_errno (y, EDOM);
  48. }
  49. /* NOINLINE reduces code size. */
  50. NOINLINE static double
  51. xflow (uint32_t sign, double y)
  52. {
  53. y = math_opt_barrier (sign ? -y : y) * y;
  54. return with_errno (y, ERANGE);
  55. }
  56. attribute_hidden double
  57. __math_uflow (uint32_t sign)
  58. {
  59. return xflow (sign, 0x1p-767);
  60. }
  61. #if WANT_ERRNO_UFLOW
  62. /* Underflows to zero in some non-nearest rounding mode, setting errno
  63. is valid even if the result is non-zero, but in the subnormal range. */
  64. attribute_hidden double
  65. __math_may_uflow (uint32_t sign)
  66. {
  67. return xflow (sign, 0x1.8p-538);
  68. }
  69. attribute_hidden double
  70. __math_uflow_value (double x)
  71. {
  72. math_force_eval (0x1p-767 * 0x1p-767);
  73. return with_errno (x, ERANGE);
  74. }
  75. #endif
  76. attribute_hidden double
  77. __math_always_uflow (double x)
  78. {
  79. return with_errno (x, ERANGE);
  80. }
  81. attribute_hidden double
  82. __math_oflow (uint32_t sign)
  83. {
  84. return xflow (sign, 0x1p769);
  85. }
  86. attribute_hidden double
  87. __math_divzero (uint32_t sign)
  88. {
  89. double y = math_opt_barrier (sign ? -1.0 : 1.0) / 0.0;
  90. return with_errno (y, ERANGE);
  91. }
  92. attribute_hidden double
  93. __math_invalid (double x)
  94. {
  95. double y = (x - x) / (x - x);
  96. return isnan (x) ? y : with_errno (y, EDOM);
  97. }
  98. attribute_hidden int
  99. __math_invalid_i (int r)
  100. {
  101. double y = 0.0 / 0.0;
  102. math_force_eval (y);
  103. return with_errno_i (r, EDOM);
  104. }
  105. attribute_hidden long int
  106. __math_invalid_li (long int r)
  107. {
  108. double y = 0.0 / 0.0;
  109. math_force_eval (y);
  110. return with_errno_li (r, EDOM);
  111. }
  112. /* Check result and set errno if necessary. */
  113. attribute_hidden double
  114. __math_check_uflow (double y)
  115. {
  116. return y == 0.0 ? with_errno (y, ERANGE) : y;
  117. }
  118. attribute_hidden double
  119. __math_check_uflow_lt (double x, double y)
  120. {
  121. return fabs (x) < y ? with_errno (x, ERANGE) : x;
  122. }
  123. attribute_hidden double __math_check_uflow_zero_lt (double x, double y,
  124. double z)
  125. {
  126. return x != 0 && fabs (x) < y ? with_errno (z, ERANGE) : z;
  127. }
  128. attribute_hidden double
  129. __math_check_oflow (double y)
  130. {
  131. return isinf (y) ? with_errno (y, ERANGE) : y;
  132. }
  133. attribute_hidden double
  134. __math_erange (double y)
  135. {
  136. return with_errno (y, ERANGE);
  137. }