1 /* Round long double value to long long int. 2 Copyright (C) 1997-2018 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and 5 Jakub Jelinek <jj@ultra.linux.cz>, 1999. 6 7 The GNU C Library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 The GNU C Library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with the GNU C Library; if not, see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "quadmath-imp.h" 22 23 long long int 24 llroundq (__float128 x) 25 { 26 int64_t j0; 27 uint64_t i1, i0; 28 long long int result; 29 int sign; 30 31 GET_FLT128_WORDS64 (i0, i1, x); 32 j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; 33 sign = (i0 & 0x8000000000000000ULL) != 0 ? -1 : 1; 34 i0 &= 0x0000ffffffffffffLL; 35 i0 |= 0x0001000000000000LL; 36 37 if (j0 < 48) 38 { 39 if (j0 < 0) 40 return j0 < -1 ? 0 : sign; 41 else 42 { 43 i0 += 0x0000800000000000LL >> j0; 44 result = i0 >> (48 - j0); 45 } 46 } 47 else if (j0 < (int32_t) (8 * sizeof (long long int)) - 1) 48 { 49 if (j0 >= 112) 50 result = ((long long int) i0 << (j0 - 48)) | (i1 << (j0 - 112)); 51 else 52 { 53 uint64_t j = i1 + (0x8000000000000000ULL >> (j0 - 48)); 54 if (j < i1) 55 ++i0; 56 57 if (j0 == 48) 58 result = (long long int) i0; 59 else 60 { 61 result = ((long long int) i0 << (j0 - 48)) | (j >> (112 - j0)); 62 #ifdef FE_INVALID 63 if (sign == 1 && result == LLONG_MIN) 64 /* Rounding brought the value out of range. */ 65 feraiseexcept (FE_INVALID); 66 #endif 67 } 68 } 69 } 70 else 71 { 72 /* The number is too large. Unless it rounds to LLONG_MIN, 73 FE_INVALID must be raised and the return value is 74 unspecified. */ 75 #ifdef FE_INVALID 76 if (FIX_FLT128_LLONG_CONVERT_OVERFLOW 77 && !(sign == -1 && x > (__float128) LLONG_MIN - 0.5Q)) 78 { 79 feraiseexcept (FE_INVALID); 80 return sign == 1 ? LLONG_MAX : LLONG_MIN; 81 } 82 else if (!FIX_FLT128_LLONG_CONVERT_OVERFLOW 83 && x <= (__float128) LLONG_MIN - 0.5Q) 84 { 85 /* If truncation produces LLONG_MIN, the cast will not raise 86 the exception, but may raise "inexact". */ 87 feraiseexcept (FE_INVALID); 88 return LLONG_MIN; 89 } 90 #endif 91 return (long long int) x; 92 } 93 94 return sign * result; 95 } 96