s_llrint.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /* Round argument to nearest integral value according to current rounding
  2. direction.
  3. Copyright (C) 1997-2026 Free Software Foundation, Inc.
  4. This file is part of the GNU C Library.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, see
  15. <https://www.gnu.org/licenses/>. */
  16. #include <fenv.h>
  17. #include <limits.h>
  18. #include <math.h>
  19. #include <math-narrow-eval.h>
  20. #include <math_private.h>
  21. #include <libm-alias-double.h>
  22. #include <fix-fp-int-convert-overflow.h>
  23. long long int
  24. __llrint (double x)
  25. {
  26. #if USE_LLRINT_BUILTIN
  27. return __builtin_llrint (x);
  28. #else
  29. /* Use generic implementation. */
  30. static const double two52[2] =
  31. {
  32. 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
  33. -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
  34. };
  35. int32_t j0;
  36. uint32_t i1, i0;
  37. long long int result;
  38. double w;
  39. double t;
  40. int sx;
  41. EXTRACT_WORDS (i0, i1, x);
  42. j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
  43. sx = i0 >> 31;
  44. i0 &= 0xfffff;
  45. i0 |= 0x100000;
  46. if (j0 < 20)
  47. {
  48. w = math_narrow_eval (two52[sx] + x);
  49. t = w - two52[sx];
  50. EXTRACT_WORDS (i0, i1, t);
  51. j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
  52. i0 &= 0xfffff;
  53. i0 |= 0x100000;
  54. result = (j0 < 0 ? 0 : i0 >> (20 - j0));
  55. }
  56. else if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
  57. {
  58. if (j0 >= 52)
  59. result = (((long long int) i0 << 32) | i1) << (j0 - 52);
  60. else
  61. {
  62. w = math_narrow_eval (two52[sx] + x);
  63. t = w - two52[sx];
  64. EXTRACT_WORDS (i0, i1, t);
  65. j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
  66. i0 &= 0xfffff;
  67. i0 |= 0x100000;
  68. if (j0 == 20)
  69. result = (long long int) i0;
  70. else
  71. result = ((long long int) i0 << (j0 - 20)) | (i1 >> (52 - j0));
  72. }
  73. }
  74. else
  75. {
  76. #ifdef FE_INVALID
  77. /* The number is too large. Unless it rounds to LLONG_MIN,
  78. FE_INVALID must be raised and the return value is
  79. unspecified. */
  80. if (FIX_DBL_LLONG_CONVERT_OVERFLOW && x != (double) LLONG_MIN)
  81. {
  82. feraiseexcept (FE_INVALID);
  83. return sx == 0 ? LLONG_MAX : LLONG_MIN;
  84. }
  85. #endif
  86. return (long long int) x;
  87. }
  88. return sx ? -result : result;
  89. #endif /* ! USE_LLRINT_BUILTIN */
  90. }
  91. libm_alias_double (__llrint, llrint)