1 /* Copyright (C) 2007-2018 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 3, or (at your option) any later
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
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.
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/>. */
24 #include "bid_internal.h"
26 /*****************************************************************************
27 * BID64_round_integral_exact
28 ****************************************************************************/
30 #if DECIMAL_CALL_BY_REFERENCE
32 bid64_from_int32 (UINT64
* pres
,
33 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
37 bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
41 // if integer is negative, put the absolute value
42 // in the lowest 32bits of the result
43 if ((x
& SIGNMASK32
) == SIGNMASK32
) {
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
54 #if DECIMAL_CALL_BY_REFERENCE
56 bid64_from_uint32 (UINT64
* pres
, unsigned int *px
57 _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
61 bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM
) {
65 res
= x
| 0x31c0000000000000ull
; // (exp << 53)) = biased exp. is 0
69 #if DECIMAL_CALL_BY_REFERENCE
71 bid64_from_int64 (UINT64
* pres
, SINT64
* px
72 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
75 #if !DECIMAL_GLOBAL_ROUNDING
76 unsigned int rnd_mode
= *prnd_mode
;
80 bid64_from_int64 (SINT64 x
81 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
89 int is_midpoint_lt_even
= 0, is_midpoint_gt_even
= 0;
90 int is_inexact_lt_midpoint
= 0, is_inexact_gt_midpoint
= 0;
92 x_sign
= x
& 0x8000000000000000ull
;
93 // if the integer is negative, use the absolute value
95 C
= ~((UINT64
) x
) + 1;
98 if (C
<= BID64_SIG_MAX
) { // |C| <= 10^16-1 and the result is exact
99 if (C
< 0x0020000000000000ull
) { // C < 2^53
100 res
= x_sign
| 0x31c0000000000000ull
| C
;
101 } else { // C >= 2^53
103 x_sign
| 0x6c70000000000000ull
| (C
& 0x0007ffffffffffffull
);
105 } else { // |C| >= 10^16 and the result may be inexact
106 // the smallest |C| is 10^16 which has 17 decimal digits
107 // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
108 if (C
< 0x16345785d8a0000ull
) { // x < 10^17
110 ind
= 1; // number of digits to remove for q = 17
111 } else if (C
< 0xde0b6b3a7640000ull
) { // C < 10^18
113 ind
= 2; // number of digits to remove for q = 18
114 } else { // C < 10^19
116 ind
= 3; // number of digits to remove for q = 19
118 // overflow and underflow are not possible
119 // Note: performace can be improved by inlining this call
120 round64_2_18 ( // will work for 19 digits too if C fits in 64 bits
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
);
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
) {
133 && ((rnd_mode
== ROUNDING_UP
&& is_inexact_lt_midpoint
)
135 ((rnd_mode
== ROUNDING_TIES_AWAY
136 || rnd_mode
== ROUNDING_UP
) && is_midpoint_gt_even
)))
138 && ((rnd_mode
== ROUNDING_DOWN
&& is_inexact_lt_midpoint
)
140 ((rnd_mode
== ROUNDING_TIES_AWAY
141 || 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
) &&
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
)))) {
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 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 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
;