1 /* Round argument to nearest integral value according to current rounding 2 direction. 3 Copyright (C) 1997-2018 Free Software Foundation, Inc. 4 This file is part of the GNU C Library. 5 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and 6 Jakub Jelinek <jj@ultra.linux.cz>, 1999. 7 8 The GNU C Library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Lesser General Public 10 License as published by the Free Software Foundation; either 11 version 2.1 of the License, or (at your option) any later version. 12 13 The GNU C Library is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public 19 License along with the GNU C Library; if not, see 20 <http://www.gnu.org/licenses/>. */ 21 22 #include "quadmath-imp.h" 23 24 static const __float128 two112[2] = 25 { 26 5.19229685853482762853049632922009600E+33Q, /* 0x406F000000000000, 0 */ 27 -5.19229685853482762853049632922009600E+33Q /* 0xC06F000000000000, 0 */ 28 }; 29 30 long int 31 lrintq (__float128 x) 32 { 33 int32_t j0; 34 uint64_t i0,i1; 35 __float128 w; 36 __float128 t; 37 long int result; 38 int sx; 39 40 GET_FLT128_WORDS64 (i0, i1, x); 41 j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; 42 sx = i0 >> 63; 43 i0 &= 0x0000ffffffffffffLL; 44 i0 |= 0x0001000000000000LL; 45 46 if (j0 < (int32_t) (8 * sizeof (long int)) - 1) 47 { 48 if (j0 < 48) 49 { 50 #if defined FE_INVALID || defined FE_INEXACT 51 /* X < LONG_MAX + 1 implied by J0 < 31. */ 52 if (sizeof (long int) == 4 53 && x > (__float128) LONG_MAX) 54 { 55 /* In the event of overflow we must raise the "invalid" 56 exception, but not "inexact". */ 57 t = nearbyintq (x); 58 feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID); 59 } 60 else 61 #endif 62 { 63 w = two112[sx] + x; 64 t = w - two112[sx]; 65 } 66 GET_FLT128_WORDS64 (i0, i1, t); 67 j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; 68 i0 &= 0x0000ffffffffffffLL; 69 i0 |= 0x0001000000000000LL; 70 71 result = (j0 < 0 ? 0 : i0 >> (48 - j0)); 72 } 73 else if (j0 >= 112) 74 result = ((long int) i0 << (j0 - 48)) | (i1 << (j0 - 112)); 75 else 76 { 77 #if defined FE_INVALID || defined FE_INEXACT 78 /* X < LONG_MAX + 1 implied by J0 < 63. */ 79 if (sizeof (long int) == 8 80 && x > (__float128) LONG_MAX) 81 { 82 /* In the event of overflow we must raise the "invalid" 83 exception, but not "inexact". */ 84 t = nearbyintq (x); 85 feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID); 86 } 87 else 88 #endif 89 { 90 w = two112[sx] + x; 91 t = w - two112[sx]; 92 } 93 GET_FLT128_WORDS64 (i0, i1, t); 94 j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; 95 i0 &= 0x0000ffffffffffffLL; 96 i0 |= 0x0001000000000000LL; 97 98 if (j0 == 48) 99 result = (long int) i0; 100 else 101 result = ((long int) i0 << (j0 - 48)) | (i1 >> (112 - j0)); 102 } 103 } 104 else 105 { 106 /* The number is too large. Unless it rounds to LONG_MIN, 107 FE_INVALID must be raised and the return value is 108 unspecified. */ 109 #if defined FE_INVALID || defined FE_INEXACT 110 if (x < (__float128) LONG_MIN 111 && x > (__float128) LONG_MIN - 1) 112 { 113 /* If truncation produces LONG_MIN, the cast will not raise 114 the exception, but may raise "inexact". */ 115 t = nearbyintq (x); 116 feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID); 117 return LONG_MIN; 118 } 119 else if (FIX_FLT128_LONG_CONVERT_OVERFLOW && x != (__float128) LONG_MIN) 120 { 121 feraiseexcept (FE_INVALID); 122 return sx == 0 ? LONG_MAX : LONG_MIN; 123 } 124 125 #endif 126 return (long int) x; 127 } 128 129 return sx ? -result : result; 130 } 131