linux: Extend internal clone3 documentation
[glibc.git] / sysdeps / ieee754 / ldbl-128ibm / s_fromfpl_main.c
blob11ef9bb5d380227fa70c848c32779c80be49fce5
1 /* Round to integer type. ldbl-128ibm version.
2 Copyright (C) 2016-2023 Free Software Foundation, Inc.
3 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.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <errno.h>
20 #include <fenv.h>
21 #include <math.h>
22 #include <math_private.h>
23 #include <stdbool.h>
24 #include <stdint.h>
26 #define BIAS 0x3ff
27 #define MANT_DIG 53
29 #if UNSIGNED
30 # define RET_TYPE uintmax_t
31 #else
32 # define RET_TYPE intmax_t
33 #endif
35 #include <fromfp.h>
37 RET_TYPE
38 FUNC (long double x, int round, unsigned int width)
40 double hi, lo;
41 if (width > INTMAX_WIDTH)
42 width = INTMAX_WIDTH;
43 uint64_t hx, lx;
44 ldbl_unpack (x, &hi, &lo);
45 EXTRACT_WORDS64 (hx, hi);
46 EXTRACT_WORDS64 (lx, lo);
47 bool negative = (hx & 0x8000000000000000ULL) != 0;
48 bool lo_negative = (lx & 0x8000000000000000ULL) != 0;
49 if (width == 0)
50 return fromfp_domain_error (negative, width);
51 hx &= 0x7fffffffffffffffULL;
52 lx &= 0x7fffffffffffffffULL;
53 if ((hx | lx) == 0)
54 return 0;
55 int hi_exponent = hx >> (MANT_DIG - 1);
56 hi_exponent -= BIAS;
57 int exponent = hi_exponent;
58 hx &= ((1ULL << (MANT_DIG - 1)) - 1);
59 if (hx == 0 && lx != 0 && lo_negative != negative)
60 exponent--;
61 int max_exponent = fromfp_max_exponent (negative, width);
62 if (exponent > max_exponent)
63 return fromfp_domain_error (negative, width);
64 int lo_exponent = lx >> (MANT_DIG - 1);
65 lo_exponent -= BIAS;
67 /* Convert the high part to integer. */
68 hx |= 1ULL << (MANT_DIG - 1);
69 uintmax_t uret;
70 bool half_bit, more_bits;
71 if (hi_exponent >= MANT_DIG - 1)
73 uret = hx;
74 uret <<= hi_exponent - (MANT_DIG - 1);
75 half_bit = false;
76 more_bits = false;
78 else if (hi_exponent >= -1)
80 uint64_t h = 1ULL << (MANT_DIG - 2 - hi_exponent);
81 half_bit = (hx & h) != 0;
82 more_bits = (hx & (h - 1)) != 0;
83 uret = hx >> (MANT_DIG - 1 - hi_exponent);
85 else
87 uret = 0;
88 half_bit = false;
89 more_bits = true;
92 /* Likewise, the low part. */
93 if (lx != 0)
95 uintmax_t lo_uret;
96 bool lo_half_bit, lo_more_bits;
97 lx &= ((1ULL << (MANT_DIG - 1)) - 1);
98 lx |= 1ULL << (MANT_DIG - 1);
99 /* The high part exponent is at most 64, so the low part
100 exponent is at most 11. */
101 if (lo_exponent >= -1)
103 uint64_t h = 1ULL << (MANT_DIG - 2 - lo_exponent);
104 lo_half_bit = (lx & h) != 0;
105 lo_more_bits = (lx & (h - 1)) != 0;
106 lo_uret = lx >> (MANT_DIG - 1 - lo_exponent);
108 else
110 lo_uret = 0;
111 lo_half_bit = false;
112 lo_more_bits = true;
114 if (lo_negative == negative)
116 uret += lo_uret;
117 half_bit |= lo_half_bit;
118 more_bits |= lo_more_bits;
120 else
122 uret -= lo_uret;
123 if (lo_half_bit)
125 uret--;
126 half_bit = true;
128 if (lo_more_bits && !more_bits)
130 if (half_bit)
132 half_bit = false;
133 more_bits = true;
135 else
137 uret--;
138 half_bit = true;
139 more_bits = true;
145 return fromfp_round_and_return (negative, uret, half_bit, more_bits, round,
146 exponent, max_exponent, width);