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 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
) {
138 && ((rnd_mode
== ROUNDING_UP
&& is_inexact_lt_midpoint
)
140 ((rnd_mode
== ROUNDING_TIES_AWAY
141 || rnd_mode
== ROUNDING_UP
) && is_midpoint_gt_even
)))
143 && ((rnd_mode
== ROUNDING_DOWN
&& is_inexact_lt_midpoint
)
145 ((rnd_mode
== ROUNDING_TIES_AWAY
146 || rnd_mode
== ROUNDING_DOWN
)
147 && is_midpoint_gt_even
)))) {
149 if (res
== 0x002386f26fc10000ull
) { // res = 10^16 => rounding overflow
150 res
= 0x00038d7ea4c68000ull
; // 10^15
153 } else if ((is_midpoint_lt_even
|| is_inexact_gt_midpoint
) &&
154 ((x_sign
&& (rnd_mode
== ROUNDING_UP
||
155 rnd_mode
== ROUNDING_TO_ZERO
)) ||
156 (!x_sign
&& (rnd_mode
== ROUNDING_DOWN
||
157 rnd_mode
== ROUNDING_TO_ZERO
)))) {
159 // check if we crossed into the lower decade
160 if (res
== 0x00038d7ea4c67fffull
) { // 10^15 - 1
161 res
= 0x002386f26fc0ffffull
; // 10^16 - 1
165 ; // exact, the result is already correct
168 if (res
< 0x0020000000000000ull
) { // res < 2^53
169 res
= x_sign
| (((UINT64
) ind
+ 398) << 53) | res
;
170 } else { // res >= 2^53
172 x_sign
| 0x6000000000000000ull
| (((UINT64
) ind
+ 398) << 51) |
173 (res
& 0x0007ffffffffffffull
);
179 #if DECIMAL_CALL_BY_REFERENCE
181 bid64_from_uint64 (UINT64
* pres
, UINT64
* px
182 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
185 #if !DECIMAL_GLOBAL_ROUNDING
186 unsigned int rnd_mode
= *prnd_mode
;
190 bid64_from_uint64 (UINT64 x
191 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
196 UINT128 x128
, res128
;
199 int is_midpoint_lt_even
= 0, is_midpoint_gt_even
= 0;
200 int is_inexact_lt_midpoint
= 0, is_inexact_gt_midpoint
= 0;
202 if (x
<= BID64_SIG_MAX
) { // x <= 10^16-1 and the result is exact
203 if (x
< 0x0020000000000000ull
) { // x < 2^53
204 res
= 0x31c0000000000000ull
| x
;
205 } else { // x >= 2^53
206 res
= 0x6c70000000000000ull
| (x
& 0x0007ffffffffffffull
);
208 } else { // x >= 10^16 and the result may be inexact
209 // the smallest x is 10^16 which has 17 decimal digits
210 // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits
211 if (x
< 0x16345785d8a0000ull
) { // x < 10^17
213 ind
= 1; // number of digits to remove for q = 17
214 } else if (x
< 0xde0b6b3a7640000ull
) { // x < 10^18
216 ind
= 2; // number of digits to remove for q = 18
217 } else if (x
< 0x8ac7230489e80000ull
) { // x < 10^19
219 ind
= 3; // number of digits to remove for q = 19
220 } else { // x < 10^20
222 ind
= 4; // number of digits to remove for q = 20
224 // overflow and underflow are not possible
225 // Note: performace can be improved by inlining this call
227 round64_2_18 ( // will work for 20 digits too if x fits in 64 bits
228 q
, ind
, x
, &res
, &incr_exp
,
229 &is_midpoint_lt_even
, &is_midpoint_gt_even
,
230 &is_inexact_lt_midpoint
, &is_inexact_gt_midpoint
);
234 round128_19_38 (q
, ind
, x128
, &res128
, &incr_exp
,
235 &is_midpoint_lt_even
, &is_midpoint_gt_even
,
236 &is_inexact_lt_midpoint
, &is_inexact_gt_midpoint
);
237 res
= res128
.w
[0]; // res.w[1] is 0
241 // set the inexact flag
242 if (is_inexact_lt_midpoint
|| is_inexact_gt_midpoint
||
243 is_midpoint_lt_even
|| is_midpoint_gt_even
)
244 *pfpsf
|= INEXACT_EXCEPTION
;
245 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
246 if (rnd_mode
!= ROUNDING_TO_NEAREST
) {
247 if ((rnd_mode
== ROUNDING_UP
&& is_inexact_lt_midpoint
) ||
248 ((rnd_mode
== ROUNDING_TIES_AWAY
|| rnd_mode
== ROUNDING_UP
)
249 && is_midpoint_gt_even
)) {
251 if (res
== 0x002386f26fc10000ull
) { // res = 10^16 => rounding overflow
252 res
= 0x00038d7ea4c68000ull
; // 10^15
255 } else if ((is_midpoint_lt_even
|| is_inexact_gt_midpoint
) &&
256 (rnd_mode
== ROUNDING_DOWN
||
257 rnd_mode
== ROUNDING_TO_ZERO
)) {
259 // check if we crossed into the lower decade
260 if (res
== 0x00038d7ea4c67fffull
) { // 10^15 - 1
261 res
= 0x002386f26fc0ffffull
; // 10^16 - 1
265 ; // exact, the result is already correct
268 if (res
< 0x0020000000000000ull
) { // res < 2^53
269 res
= (((UINT64
) ind
+ 398) << 53) | res
;
270 } else { // res >= 2^53
271 res
= 0x6000000000000000ull
| (((UINT64
) ind
+ 398) << 51) |
272 (res
& 0x0007ffffffffffffull
);
278 #if DECIMAL_CALL_BY_REFERENCE
280 bid128_from_int32 (UINT128
* pres
,
281 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
285 bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
289 // if integer is negative, use the absolute value
290 if ((x
& SIGNMASK32
) == SIGNMASK32
) {
291 res
.w
[HIGH_128W
] = 0xb040000000000000ull
;
292 res
.w
[LOW_128W
] = ~((unsigned int) x
) + 1; // 2's complement of x
294 res
.w
[HIGH_128W
] = 0x3040000000000000ull
;
295 res
.w
[LOW_128W
] = (unsigned int) x
;
300 #if DECIMAL_CALL_BY_REFERENCE
302 bid128_from_uint32 (UINT128
* pres
, unsigned int *px
303 _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
304 unsigned int x
= *px
;
307 bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
311 res
.w
[HIGH_128W
] = 0x3040000000000000ull
;
316 #if DECIMAL_CALL_BY_REFERENCE
318 bid128_from_int64 (UINT128
* pres
, SINT64
* px
319 _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
323 bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
328 // if integer is negative, use the absolute value
329 if ((x
& SIGNMASK64
) == SIGNMASK64
) {
330 res
.w
[HIGH_128W
] = 0xb040000000000000ull
;
331 res
.w
[LOW_128W
] = ~x
+ 1; // 2's complement of x
333 res
.w
[HIGH_128W
] = 0x3040000000000000ull
;
339 #if DECIMAL_CALL_BY_REFERENCE
341 bid128_from_uint64 (UINT128
* pres
, UINT64
* px
342 _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
346 bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
351 res
.w
[HIGH_128W
] = 0x3040000000000000ull
;