1 | /* Round __float128 value to long long int. |
---|---|

2 | Copyright (C) 1997-2017 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, write to the Free |

19 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |

20 | 02111-1307 USA. */ |

21 | |

22 | #include "quadmath-imp.h" |

23 | |

24 | |

25 | long long int |

26 | llroundq (__float128 x) |

27 | { |

28 | int64_t j0; |

29 | uint64_t i1, i0; |

30 | long long int result; |

31 | int sign; |

32 | |

33 | GET_FLT128_WORDS64 (i0, i1, x); |

34 | j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; |

35 | sign = (i0 & 0x8000000000000000ULL) != 0 ? -1 : 1; |

36 | i0 &= 0x0000ffffffffffffLL; |

37 | i0 |= 0x0001000000000000LL; |

38 | |

39 | if (j0 < 48) |

40 | { |

41 | if (j0 < 0) |

42 | return j0 < -1 ? 0 : sign; |

43 | else |

44 | { |

45 | i0 += 0x0000800000000000LL >> j0; |

46 | result = i0 >> (48 - j0); |

47 | } |

48 | } |

49 | else if (j0 < (int32_t) (8 * sizeof (long long int)) - 1) |

50 | { |

51 | if (j0 >= 112) |

52 | result = ((long long int) i0 << (j0 - 48)) | (i1 << (j0 - 112)); |

53 | else |

54 | { |

55 | uint64_t j = i1 + (0x8000000000000000ULL >> (j0 - 48)); |

56 | if (j < i1) |

57 | ++i0; |

58 | |

59 | if (j0 == 48) |

60 | result = (long long int) i0; |

61 | else |

62 | { |

63 | result = ((long long int) i0 << (j0 - 48)) | (j >> (112 - j0)); |

64 | #if defined FE_INVALID && defined USE_FENV_H |

65 | if (sign == 1 && result == LLONG_MIN) |

66 | /* Rounding brought the value out of range. */ |

67 | feraiseexcept (FE_INVALID); |

68 | #endif |

69 | } |

70 | } |

71 | } |

72 | else |

73 | { |

74 | /* The number is too large. Unless it rounds to LLONG_MIN, |

75 | FE_INVALID must be raised and the return value is |

76 | unspecified. */ |

77 | #ifdef FE_INVALID |

78 | if (x <= (__float128) LLONG_MIN - 0.5Q) |

79 | { |

80 | /* If truncation produces LLONG_MIN, the cast will not raise |

81 | the exception, but may raise "inexact". */ |

82 | #ifdef USE_FENV_H |

83 | feraiseexcept (FE_INVALID); |

84 | #endif |

85 | return LLONG_MIN; |

86 | } |

87 | #endif |

88 | return (long long int) x; |

89 | } |

90 | |

91 | return sign * result; |

92 | } |

93 |