]>
Commit | Line | Data |
---|---|---|
99dee823 | 1 | /* Copyright (C) 2007-2021 Free Software Foundation, Inc. |
200359e8 L |
2 | |
3 | This file is part of GCC. | |
4 | ||
5 | GCC is free software; you can redistribute it and/or modify it under | |
6 | the terms of the GNU General Public License as published by the Free | |
748086b7 | 7 | Software Foundation; either version 3, or (at your option) any later |
200359e8 L |
8 | version. |
9 | ||
200359e8 L |
10 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | for more details. | |
14 | ||
748086b7 JJ |
15 | Under Section 7 of GPL version 3, you are granted additional |
16 | permissions described in the GCC Runtime Library Exception, version | |
17 | 3.1, as published by the Free Software Foundation. | |
18 | ||
19 | You should have received a copy of the GNU General Public License and | |
20 | a copy of the GCC Runtime Library Exception along with this program; | |
21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
22 | <http://www.gnu.org/licenses/>. */ | |
200359e8 L |
23 | |
24 | #include "bid_internal.h" | |
25 | ||
26 | /***************************************************************************** | |
27 | * BID64_round_integral_exact | |
28 | ****************************************************************************/ | |
29 | ||
30 | #if DECIMAL_CALL_BY_REFERENCE | |
31 | void | |
b2a00c89 | 32 | bid64_from_int32 (UINT64 * pres, |
200359e8 L |
33 | int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
34 | int x = *px; | |
35 | #else | |
36 | UINT64 | |
b2a00c89 | 37 | bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
200359e8 L |
38 | #endif |
39 | UINT64 res; | |
40 | ||
41 | // if integer is negative, put the absolute value | |
42 | // in the lowest 32bits of the result | |
43 | if ((x & SIGNMASK32) == SIGNMASK32) { | |
44 | // negative int32 | |
b2a00c89 L |
45 | x = ~x + 1; // 2's complement of x |
46 | res = (unsigned int) x | 0xb1c0000000000000ull; | |
47 | // (exp << 53)) = biased exp. is 0 | |
48 | } else { // positive int32 | |
49 | res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0 | |
200359e8 L |
50 | } |
51 | BID_RETURN (res); | |
52 | } | |
53 | ||
54 | #if DECIMAL_CALL_BY_REFERENCE | |
55 | void | |
b2a00c89 | 56 | bid64_from_uint32 (UINT64 * pres, unsigned int *px |
200359e8 L |
57 | _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
58 | unsigned int x = *px; | |
59 | #else | |
60 | UINT64 | |
b2a00c89 | 61 | bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
200359e8 L |
62 | #endif |
63 | UINT64 res; | |
64 | ||
b2a00c89 | 65 | res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0 |
200359e8 L |
66 | BID_RETURN (res); |
67 | } | |
68 | ||
69 | #if DECIMAL_CALL_BY_REFERENCE | |
70 | void | |
b2a00c89 | 71 | bid64_from_int64 (UINT64 * pres, SINT64 * px |
200359e8 L |
72 | _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM |
73 | _EXC_INFO_PARAM) { | |
74 | SINT64 x = *px; | |
75 | #if !DECIMAL_GLOBAL_ROUNDING | |
76 | unsigned int rnd_mode = *prnd_mode; | |
77 | #endif | |
78 | #else | |
79 | UINT64 | |
b2a00c89 | 80 | bid64_from_int64 (SINT64 x |
200359e8 L |
81 | _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM |
82 | _EXC_INFO_PARAM) { | |
83 | #endif | |
84 | ||
85 | UINT64 res; | |
86 | UINT64 x_sign, C; | |
87 | unsigned int q, ind; | |
88 | int incr_exp = 0; | |
89 | int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0; | |
90 | int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0; | |
91 | ||
92 | x_sign = x & 0x8000000000000000ull; | |
93 | // if the integer is negative, use the absolute value | |
94 | if (x_sign) | |
95 | C = ~((UINT64) x) + 1; | |
96 | else | |
97 | C = x; | |
b2a00c89 L |
98 | if (C <= BID64_SIG_MAX) { // |C| <= 10^16-1 and the result is exact |
99 | if (C < 0x0020000000000000ull) { // C < 2^53 | |
200359e8 | 100 | res = x_sign | 0x31c0000000000000ull | C; |
b2a00c89 | 101 | } else { // C >= 2^53 |
200359e8 L |
102 | res = |
103 | x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull); | |
104 | } | |
b2a00c89 | 105 | } else { // |C| >= 10^16 and the result may be inexact |
200359e8 L |
106 | // the smallest |C| is 10^16 which has 17 decimal digits |
107 | // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits | |
b2a00c89 | 108 | if (C < 0x16345785d8a0000ull) { // x < 10^17 |
200359e8 | 109 | q = 17; |
b2a00c89 L |
110 | ind = 1; // number of digits to remove for q = 17 |
111 | } else if (C < 0xde0b6b3a7640000ull) { // C < 10^18 | |
200359e8 | 112 | q = 18; |
b2a00c89 L |
113 | ind = 2; // number of digits to remove for q = 18 |
114 | } else { // C < 10^19 | |
200359e8 | 115 | q = 19; |
b2a00c89 | 116 | ind = 3; // number of digits to remove for q = 19 |
200359e8 L |
117 | } |
118 | // overflow and underflow are not possible | |
119 | // Note: performace can be improved by inlining this call | |
b2a00c89 | 120 | round64_2_18 ( // will work for 19 digits too if C fits in 64 bits |
200359e8 L |
121 | q, ind, C, &res, &incr_exp, |
122 | &is_midpoint_lt_even, &is_midpoint_gt_even, | |
123 | &is_inexact_lt_midpoint, &is_inexact_gt_midpoint); | |
124 | if (incr_exp) | |
125 | ind++; | |
126 | // set the inexact flag | |
127 | if (is_inexact_lt_midpoint || is_inexact_gt_midpoint || | |
128 | is_midpoint_lt_even || is_midpoint_gt_even) | |
129 | *pfpsf |= INEXACT_EXCEPTION; | |
130 | // general correction from RN to RA, RM, RP, RZ; result uses ind for exp | |
131 | if (rnd_mode != ROUNDING_TO_NEAREST) { | |
b2a00c89 L |
132 | if ((!x_sign |
133 | && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) | |
134 | || | |
135 | ((rnd_mode == ROUNDING_TIES_AWAY | |
136 | || rnd_mode == ROUNDING_UP) && is_midpoint_gt_even))) | |
137 | || (x_sign | |
138 | && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint) | |
139 | || | |
140 | ((rnd_mode == ROUNDING_TIES_AWAY | |
141 | || rnd_mode == ROUNDING_DOWN) | |
142 | && is_midpoint_gt_even)))) { | |
200359e8 | 143 | res = res + 1; |
b2a00c89 L |
144 | if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow |
145 | res = 0x00038d7ea4c68000ull; // 10^15 | |
200359e8 L |
146 | ind = ind + 1; |
147 | } | |
148 | } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) && | |
b2a00c89 L |
149 | ((x_sign && (rnd_mode == ROUNDING_UP || |
150 | rnd_mode == ROUNDING_TO_ZERO)) || | |
151 | (!x_sign && (rnd_mode == ROUNDING_DOWN || | |
152 | rnd_mode == ROUNDING_TO_ZERO)))) { | |
200359e8 L |
153 | res = res - 1; |
154 | // check if we crossed into the lower decade | |
b2a00c89 L |
155 | if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1 |
156 | res = 0x002386f26fc0ffffull; // 10^16 - 1 | |
200359e8 L |
157 | ind = ind - 1; |
158 | } | |
159 | } else { | |
b2a00c89 | 160 | ; // exact, the result is already correct |
200359e8 L |
161 | } |
162 | } | |
b2a00c89 | 163 | if (res < 0x0020000000000000ull) { // res < 2^53 |
200359e8 | 164 | res = x_sign | (((UINT64) ind + 398) << 53) | res; |
b2a00c89 | 165 | } else { // res >= 2^53 |
200359e8 L |
166 | res = |
167 | x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) | | |
168 | (res & 0x0007ffffffffffffull); | |
169 | } | |
170 | } | |
171 | BID_RETURN (res); | |
172 | } | |
173 | ||
174 | #if DECIMAL_CALL_BY_REFERENCE | |
175 | void | |
b2a00c89 | 176 | bid64_from_uint64 (UINT64 * pres, UINT64 * px |
200359e8 L |
177 | _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM |
178 | _EXC_INFO_PARAM) { | |
179 | UINT64 x = *px; | |
180 | #if !DECIMAL_GLOBAL_ROUNDING | |
181 | unsigned int rnd_mode = *prnd_mode; | |
182 | #endif | |
183 | #else | |
184 | UINT64 | |
b2a00c89 | 185 | bid64_from_uint64 (UINT64 x |
200359e8 L |
186 | _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM |
187 | _EXC_INFO_PARAM) { | |
188 | #endif | |
189 | ||
190 | UINT64 res; | |
191 | UINT128 x128, res128; | |
192 | unsigned int q, ind; | |
193 | int incr_exp = 0; | |
194 | int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0; | |
195 | int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0; | |
196 | ||
b2a00c89 L |
197 | if (x <= BID64_SIG_MAX) { // x <= 10^16-1 and the result is exact |
198 | if (x < 0x0020000000000000ull) { // x < 2^53 | |
200359e8 | 199 | res = 0x31c0000000000000ull | x; |
b2a00c89 | 200 | } else { // x >= 2^53 |
200359e8 L |
201 | res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull); |
202 | } | |
b2a00c89 | 203 | } else { // x >= 10^16 and the result may be inexact |
200359e8 L |
204 | // the smallest x is 10^16 which has 17 decimal digits |
205 | // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits | |
b2a00c89 | 206 | if (x < 0x16345785d8a0000ull) { // x < 10^17 |
200359e8 | 207 | q = 17; |
b2a00c89 L |
208 | ind = 1; // number of digits to remove for q = 17 |
209 | } else if (x < 0xde0b6b3a7640000ull) { // x < 10^18 | |
200359e8 | 210 | q = 18; |
b2a00c89 L |
211 | ind = 2; // number of digits to remove for q = 18 |
212 | } else if (x < 0x8ac7230489e80000ull) { // x < 10^19 | |
200359e8 | 213 | q = 19; |
b2a00c89 L |
214 | ind = 3; // number of digits to remove for q = 19 |
215 | } else { // x < 10^20 | |
200359e8 | 216 | q = 20; |
b2a00c89 | 217 | ind = 4; // number of digits to remove for q = 20 |
200359e8 L |
218 | } |
219 | // overflow and underflow are not possible | |
220 | // Note: performace can be improved by inlining this call | |
221 | if (q <= 19) { | |
b2a00c89 | 222 | round64_2_18 ( // will work for 20 digits too if x fits in 64 bits |
200359e8 L |
223 | q, ind, x, &res, &incr_exp, |
224 | &is_midpoint_lt_even, &is_midpoint_gt_even, | |
225 | &is_inexact_lt_midpoint, &is_inexact_gt_midpoint); | |
b2a00c89 | 226 | } else { // q = 20 |
200359e8 L |
227 | x128.w[1] = 0x0; |
228 | x128.w[0] = x; | |
b2a00c89 | 229 | round128_19_38 (q, ind, x128, &res128, &incr_exp, |
200359e8 L |
230 | &is_midpoint_lt_even, &is_midpoint_gt_even, |
231 | &is_inexact_lt_midpoint, &is_inexact_gt_midpoint); | |
b2a00c89 | 232 | res = res128.w[0]; // res.w[1] is 0 |
200359e8 L |
233 | } |
234 | if (incr_exp) | |
235 | ind++; | |
236 | // set the inexact flag | |
237 | if (is_inexact_lt_midpoint || is_inexact_gt_midpoint || | |
238 | is_midpoint_lt_even || is_midpoint_gt_even) | |
239 | *pfpsf |= INEXACT_EXCEPTION; | |
240 | // general correction from RN to RA, RM, RP, RZ; result uses ind for exp | |
241 | if (rnd_mode != ROUNDING_TO_NEAREST) { | |
b2a00c89 L |
242 | if ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) || |
243 | ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP) | |
244 | && is_midpoint_gt_even)) { | |
200359e8 | 245 | res = res + 1; |
b2a00c89 L |
246 | if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow |
247 | res = 0x00038d7ea4c68000ull; // 10^15 | |
200359e8 L |
248 | ind = ind + 1; |
249 | } | |
250 | } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) && | |
251 | (rnd_mode == ROUNDING_DOWN || | |
252 | rnd_mode == ROUNDING_TO_ZERO)) { | |
253 | res = res - 1; | |
254 | // check if we crossed into the lower decade | |
b2a00c89 L |
255 | if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1 |
256 | res = 0x002386f26fc0ffffull; // 10^16 - 1 | |
200359e8 L |
257 | ind = ind - 1; |
258 | } | |
259 | } else { | |
b2a00c89 | 260 | ; // exact, the result is already correct |
200359e8 L |
261 | } |
262 | } | |
b2a00c89 | 263 | if (res < 0x0020000000000000ull) { // res < 2^53 |
200359e8 | 264 | res = (((UINT64) ind + 398) << 53) | res; |
b2a00c89 | 265 | } else { // res >= 2^53 |
200359e8 L |
266 | res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) | |
267 | (res & 0x0007ffffffffffffull); | |
268 | } | |
269 | } | |
270 | BID_RETURN (res); | |
271 | } | |
272 | ||
273 | #if DECIMAL_CALL_BY_REFERENCE | |
274 | void | |
b2a00c89 | 275 | bid128_from_int32 (UINT128 * pres, |
200359e8 L |
276 | int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
277 | int x = *px; | |
278 | #else | |
279 | UINT128 | |
b2a00c89 | 280 | bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
200359e8 L |
281 | #endif |
282 | UINT128 res; | |
283 | ||
284 | // if integer is negative, use the absolute value | |
285 | if ((x & SIGNMASK32) == SIGNMASK32) { | |
286 | res.w[HIGH_128W] = 0xb040000000000000ull; | |
b2a00c89 | 287 | res.w[LOW_128W] = ~((unsigned int) x) + 1; // 2's complement of x |
200359e8 L |
288 | } else { |
289 | res.w[HIGH_128W] = 0x3040000000000000ull; | |
b2a00c89 | 290 | res.w[LOW_128W] = (unsigned int) x; |
200359e8 L |
291 | } |
292 | BID_RETURN (res); | |
293 | } | |
294 | ||
295 | #if DECIMAL_CALL_BY_REFERENCE | |
296 | void | |
b2a00c89 | 297 | bid128_from_uint32 (UINT128 * pres, unsigned int *px |
200359e8 L |
298 | _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
299 | unsigned int x = *px; | |
300 | #else | |
301 | UINT128 | |
b2a00c89 | 302 | bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
200359e8 L |
303 | #endif |
304 | UINT128 res; | |
305 | ||
306 | res.w[HIGH_128W] = 0x3040000000000000ull; | |
307 | res.w[LOW_128W] = x; | |
308 | BID_RETURN (res); | |
309 | } | |
310 | ||
311 | #if DECIMAL_CALL_BY_REFERENCE | |
312 | void | |
b2a00c89 | 313 | bid128_from_int64 (UINT128 * pres, SINT64 * px |
200359e8 L |
314 | _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
315 | SINT64 x = *px; | |
316 | #else | |
317 | UINT128 | |
b2a00c89 | 318 | bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
200359e8 L |
319 | #endif |
320 | ||
321 | UINT128 res; | |
322 | ||
323 | // if integer is negative, use the absolute value | |
324 | if ((x & SIGNMASK64) == SIGNMASK64) { | |
325 | res.w[HIGH_128W] = 0xb040000000000000ull; | |
b2a00c89 | 326 | res.w[LOW_128W] = ~x + 1; // 2's complement of x |
200359e8 L |
327 | } else { |
328 | res.w[HIGH_128W] = 0x3040000000000000ull; | |
329 | res.w[LOW_128W] = x; | |
330 | } | |
331 | BID_RETURN (res); | |
332 | } | |
333 | ||
334 | #if DECIMAL_CALL_BY_REFERENCE | |
335 | void | |
b2a00c89 | 336 | bid128_from_uint64 (UINT128 * pres, UINT64 * px |
200359e8 L |
337 | _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
338 | UINT64 x = *px; | |
339 | #else | |
340 | UINT128 | |
b2a00c89 | 341 | bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
200359e8 L |
342 | #endif |
343 | ||
344 | UINT128 res; | |
345 | ||
346 | res.w[HIGH_128W] = 0x3040000000000000ull; | |
347 | res.w[LOW_128W] = x; | |
348 | BID_RETURN (res); | |
349 | } |