1 /* Copyright (C) 2007 Free Software Foundation, Inc.
3 This file is part of GCC.
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
7 Software Foundation; either version 2, or (at your option) any later
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file. (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
19 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
20 WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 You should have received a copy of the GNU General Public License
25 along with GCC; see the file COPYING. If not, write to the Free
26 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29 #include "bid_internal.h"
31 /*****************************************************************************
32 * BID64_round_integral_exact
33 ****************************************************************************/
35 #if DECIMAL_CALL_BY_REFERENCE
37 __bid64_from_int32 (UINT64 * pres,
38 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
42 __bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
46 // if integer is negative, put the absolute value
47 // in the lowest 32bits of the result
48 if ((x & SIGNMASK32) == SIGNMASK32) {
50 x = ~x + 1; // 2's complement of x
51 res = (unsigned int)x | 0xb1c0000000000000ull;
52 // (exp << 53)) = biased exp. is 0
53 } else { // positive int32
54 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
59 #if DECIMAL_CALL_BY_REFERENCE
61 __bid64_from_uint32 (UINT64 * pres, unsigned int *px
62 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
66 __bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
70 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0
74 #if DECIMAL_CALL_BY_REFERENCE
76 __bid64_from_int64 (UINT64 * pres, SINT64 * px
77 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
80 #if !DECIMAL_GLOBAL_ROUNDING
81 unsigned int rnd_mode = *prnd_mode;
85 __bid64_from_int64 (SINT64 x
86 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
94 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
95 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
97 x_sign = x & 0x8000000000000000ull;
98 // if the integer is negative, use the absolute value
100 C = ~((UINT64) x) + 1;
103 if (C <= BID64_SIG_MAX) { // |C| <= 10^16-1 and the result is exact
104 if (C < 0x0020000000000000ull) { // C < 2^53
105 res = x_sign | 0x31c0000000000000ull | C;
106 } else { // C >= 2^53
108 x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull);
110 } else { // |C| >= 10^16 and the result may be inexact
111 // the smallest |C| is 10^16 which has 17 decimal digits
112 // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
113 if (C < 0x16345785d8a0000ull) { // x < 10^17
115 ind = 1; // number of digits to remove for q = 17
116 } else if (C < 0xde0b6b3a7640000ull) { // C < 10^18
118 ind = 2; // number of digits to remove for q = 18
119 } else { // C < 10^19
121 ind = 3; // number of digits to remove for q = 19
123 // overflow and underflow are not possible
124 // Note: performace can be improved by inlining this call
125 __bid_round64_2_18 ( // will work for 19 digits too if C fits in 64 bits
126 q, ind, C, &res, &incr_exp,
127 &is_midpoint_lt_even, &is_midpoint_gt_even,
128 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
131 // set the inexact flag
132 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
133 is_midpoint_lt_even || is_midpoint_gt_even)
134 *pfpsf |= INEXACT_EXCEPTION;
135 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
136 if (rnd_mode != ROUNDING_TO_NEAREST) {
137 if ((!x_sign && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) ||
138 ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP) &&
139 is_midpoint_gt_even))) ||
140 (x_sign && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint) ||
141 ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_DOWN) &&
142 is_midpoint_gt_even)))) {
144 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
145 res = 0x00038d7ea4c68000ull; // 10^15
148 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
150 (rnd_mode == ROUNDING_UP || rnd_mode == ROUNDING_TO_ZERO)) ||
152 (rnd_mode == ROUNDING_DOWN || rnd_mode == ROUNDING_TO_ZERO)))) {
154 // check if we crossed into the lower decade
155 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
156 res = 0x002386f26fc0ffffull; // 10^16 - 1
160 ; // exact, the result is already correct
163 if (res < 0x0020000000000000ull) { // res < 2^53
164 res = x_sign | (((UINT64) ind + 398) << 53) | res;
165 } else { // res >= 2^53
167 x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
168 (res & 0x0007ffffffffffffull);
174 #if DECIMAL_CALL_BY_REFERENCE
176 __bid64_from_uint64 (UINT64 * pres, UINT64 * px
177 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
180 #if !DECIMAL_GLOBAL_ROUNDING
181 unsigned int rnd_mode = *prnd_mode;
185 __bid64_from_uint64 (UINT64 x
186 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
191 UINT128 x128, res128;
194 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
195 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
197 if (x <= BID64_SIG_MAX) { // x <= 10^16-1 and the result is exact
198 if (x < 0x0020000000000000ull) { // x < 2^53
199 res = 0x31c0000000000000ull | x;
200 } else { // x >= 2^53
201 res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull);
203 } else { // x >= 10^16 and the result may be inexact
204 // the smallest x is 10^16 which has 17 decimal digits
205 // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
206 if (x < 0x16345785d8a0000ull) { // x < 10^17
208 ind = 1; // number of digits to remove for q = 17
209 } else if (x < 0xde0b6b3a7640000ull) { // x < 10^18
211 ind = 2; // number of digits to remove for q = 18
212 } else if (x < 0x8ac7230489e80000ull) { // x < 10^19
214 ind = 3; // number of digits to remove for q = 19
215 } else { // x < 10^20
217 ind = 4; // number of digits to remove for q = 20
219 // overflow and underflow are not possible
220 // Note: performace can be improved by inlining this call
222 __bid_round64_2_18 ( // will work for 20 digits too if x fits in 64 bits
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);
229 __bid_round128_19_38 (q, ind, x128, &res128, &incr_exp,
230 &is_midpoint_lt_even, &is_midpoint_gt_even,
231 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
232 res = res128.w[0]; // res.w[1] is 0
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) {
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)) {
246 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow
247 res = 0x00038d7ea4c68000ull; // 10^15
250 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
251 (rnd_mode == ROUNDING_DOWN ||
252 rnd_mode == ROUNDING_TO_ZERO)) {
254 // check if we crossed into the lower decade
255 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1
256 res = 0x002386f26fc0ffffull; // 10^16 - 1
260 ; // exact, the result is already correct
263 if (res < 0x0020000000000000ull) { // res < 2^53
264 res = (((UINT64) ind + 398) << 53) | res;
265 } else { // res >= 2^53
266 res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) |
267 (res & 0x0007ffffffffffffull);
273 #if DECIMAL_CALL_BY_REFERENCE
275 __bid128_from_int32 (UINT128 * pres,
276 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
280 __bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
284 // if integer is negative, use the absolute value
285 if ((x & SIGNMASK32) == SIGNMASK32) {
286 res.w[HIGH_128W] = 0xb040000000000000ull;
287 res.w[LOW_128W] = ~((unsigned int)x) + 1; // 2's complement of x
289 res.w[HIGH_128W] = 0x3040000000000000ull;
290 res.w[LOW_128W] = (unsigned int)x;
295 #if DECIMAL_CALL_BY_REFERENCE
297 __bid128_from_uint32 (UINT128 * pres, unsigned int *px
298 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
299 unsigned int x = *px;
302 __bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
306 res.w[HIGH_128W] = 0x3040000000000000ull;
311 #if DECIMAL_CALL_BY_REFERENCE
313 __bid128_from_int64 (UINT128 * pres, SINT64 * px
314 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
318 __bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
323 // if integer is negative, use the absolute value
324 if ((x & SIGNMASK64) == SIGNMASK64) {
325 res.w[HIGH_128W] = 0xb040000000000000ull;
326 res.w[LOW_128W] = ~x + 1; // 2's complement of x
328 res.w[HIGH_128W] = 0x3040000000000000ull;
334 #if DECIMAL_CALL_BY_REFERENCE
336 __bid128_from_uint64 (UINT128 * pres, UINT64 * px
337 _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
341 __bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) {
346 res.w[HIGH_128W] = 0x3040000000000000ull;