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
30 #include "bid_internal.h"
32 BID128_FUNCTION_ARG2 (bid128_quantize
, x
, y
)
35 UINT128 CX
, CY
, T
, CX2
, CR
, Stemp
, res
, REM_H
, C2N
;
36 UINT64 sign_x
, sign_y
, remainder_h
, carry
, CY64
, valid_x
;
38 int exponent_x
, exponent_y
, digits_x
, extra_digits
, amount
;
39 int expon_diff
, total_digits
, bin_expon_cx
, rmode
, status
;
41 valid_x
= unpack_BID128_value (&sign_x
, &exponent_x
, &CX
, x
);
43 // unpack arguments, check for NaN or Infinity
44 if (!unpack_BID128_value (&sign_y
, &exponent_y
, &CY
, y
)) {
46 #ifdef SET_STATUS_FLAGS
47 if ((x
.w
[1] & SNAN_MASK64
) == SNAN_MASK64
) // y is sNaN
48 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
52 if ((y
.w
[1] & 0x7c00000000000000ull
) == 0x7c00000000000000ull
) {
53 #ifdef SET_STATUS_FLAGS
54 if ((y
.w
[1] & 0x7e00000000000000ull
) == 0x7e00000000000000ull
) {
56 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
59 if ((x
.w
[1] & 0x7c00000000000000ull
) != 0x7c00000000000000ull
) {
60 res
.w
[1] = CY
.w
[1] & QUIET_MASK64
;
63 res
.w
[1] = CX
.w
[1] & QUIET_MASK64
;
69 if ((y
.w
[1] & 0x7800000000000000ull
) == 0x7800000000000000ull
) {
70 // check if x is not Inf.
71 if (((x
.w
[1] & 0x7c00000000000000ull
) < 0x7800000000000000ull
)) {
73 #ifdef SET_STATUS_FLAGS
75 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
77 res
.w
[1] = 0x7c00000000000000ull
;
81 if (((x
.w
[1] & 0x7c00000000000000ull
) <= 0x7800000000000000ull
)) {
82 res
.w
[1] = CX
.w
[1] & QUIET_MASK64
;
91 // test if x is NaN or Inf
92 if ((x
.w
[1] & 0x7c00000000000000ull
) == 0x7800000000000000ull
) {
93 #ifdef SET_STATUS_FLAGS
95 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
97 res
.w
[1] = 0x7c00000000000000ull
;
100 } else if ((x
.w
[1] & 0x7c00000000000000ull
) == 0x7c00000000000000ull
) {
101 if ((x
.w
[1] & 0x7e00000000000000ull
) == 0x7e00000000000000ull
) {
102 #ifdef SET_STATUS_FLAGS
104 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
107 res
.w
[1] = CX
.w
[1] & QUIET_MASK64
;
111 if (!CX
.w
[1] && !CX
.w
[0]) {
112 get_BID128_very_fast (&res
, sign_x
, exponent_y
, CX
);
116 // get number of decimal digits in coefficient_x
118 tempx
.d
= (float) CX
.w
[1];
119 bin_expon_cx
= ((tempx
.i
>> 23) & 0xff) - 0x7f + 64;
121 tempx
.d
= (float) CX
.w
[0];
122 bin_expon_cx
= ((tempx
.i
>> 23) & 0xff) - 0x7f;
125 digits_x
= estimate_decimal_digits
[bin_expon_cx
];
126 if (CX
.w
[1] > power10_table_128
[digits_x
].w
[1]
127 || (CX
.w
[1] == power10_table_128
[digits_x
].w
[1]
128 && CX
.w
[0] >= power10_table_128
[digits_x
].w
[0]))
131 expon_diff
= exponent_x
- exponent_y
;
132 total_digits
= digits_x
+ expon_diff
;
134 if ((UINT32
) total_digits
<= 34) {
135 if (expon_diff
>= 0) {
136 T
= power10_table_128
[expon_diff
];
137 __mul_128x128_low (CX2
, T
, CX
);
138 get_BID128_very_fast (&res
, sign_x
, exponent_y
, CX2
);
141 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
142 #ifndef IEEE_ROUND_NEAREST
144 if (sign_x
&& (unsigned) (rmode
- 1) < 2)
152 // must round off -expon_diff digits
153 extra_digits
= -expon_diff
;
154 __add_128_128 (CX
, CX
, round_const_table_128
[rmode
][extra_digits
]);
156 // get P*(2^M[extra_digits])/10^extra_digits
157 __mul_128x128_to_256 (CT
, CX
, reciprocals10_128
[extra_digits
]);
159 // now get P/10^extra_digits: shift C64 right by M[extra_digits]-128
160 amount
= recip_scale
[extra_digits
];
165 CR
.w
[0] = CX2
.w
[1] >> (amount
- 64);
167 __shr_128 (CR
, CX2
, amount
);
170 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
171 #ifndef IEEE_ROUND_NEAREST
175 // check whether fractional part of initial_P/10^extra_digits is
176 // exactly .5 this is the same as fractional part of
177 // (initial_P + 0.5*10^extra_digits)/10^extra_digits is exactly zero
181 remainder_h
= CX2
.w
[0] | (CX2
.w
[1] << (128 - amount
));
183 remainder_h
= CX2
.w
[0] << (64 - amount
);
185 // test whether fractional part is 0
187 && (CT
.w
[1] < reciprocals10_128
[extra_digits
].w
[1]
188 || (CT
.w
[1] == reciprocals10_128
[extra_digits
].w
[1]
189 && CT
.w
[0] < reciprocals10_128
[extra_digits
].w
[0]))) {
195 #ifdef SET_STATUS_FLAGS
196 status
= INEXACT_EXCEPTION
;
200 REM_H
.w
[1] = (CX2
.w
[1] << (128 - amount
));
201 REM_H
.w
[0] = CX2
.w
[0];
203 REM_H
.w
[1] = CX2
.w
[0] << (64 - amount
);
208 case ROUNDING_TO_NEAREST
:
209 case ROUNDING_TIES_AWAY
:
210 // test whether fractional part is 0
211 if (REM_H
.w
[1] == 0x8000000000000000ull
&& !REM_H
.w
[0]
212 && (CT
.w
[1] < reciprocals10_128
[extra_digits
].w
[1]
213 || (CT
.w
[1] == reciprocals10_128
[extra_digits
].w
[1]
214 && CT
.w
[0] < reciprocals10_128
[extra_digits
].w
[0])))
215 status
= EXACT_STATUS
;
218 case ROUNDING_TO_ZERO
:
219 if (!(REM_H
.w
[1] | REM_H
.w
[0])
220 && (CT
.w
[1] < reciprocals10_128
[extra_digits
].w
[1]
221 || (CT
.w
[1] == reciprocals10_128
[extra_digits
].w
[1]
222 && CT
.w
[0] < reciprocals10_128
[extra_digits
].w
[0])))
223 status
= EXACT_STATUS
;
227 __add_carry_out (Stemp
.w
[0], CY64
, CT
.w
[0],
228 reciprocals10_128
[extra_digits
].w
[0]);
229 __add_carry_in_out (Stemp
.w
[1], carry
, CT
.w
[1],
230 reciprocals10_128
[extra_digits
].w
[1], CY64
);
233 C2N
.w
[0] = ((UINT64
) 1) << amount
;
234 REM_H
.w
[0] = REM_H
.w
[1] >> (64 - amount
);
237 C2N
.w
[1] = ((UINT64
) 1) << (amount
- 64);
239 REM_H
.w
[1] >>= (128 - amount
);
242 if (REM_H
.w
[0] < carry
)
244 if (__unsigned_compare_ge_128 (REM_H
, C2N
))
245 status
= EXACT_STATUS
;
248 __set_status_flags (pfpsf
, status
);
251 get_BID128_very_fast (&res
, sign_x
, exponent_y
, CR
);
254 if (total_digits
< 0) {
255 CR
.w
[1] = CR
.w
[0] = 0;
256 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY
257 #ifndef IEEE_ROUND_NEAREST
259 if (sign_x
&& (unsigned) (rmode
- 1) < 2)
261 if (rmode
== ROUNDING_UP
)
265 #ifdef SET_STATUS_FLAGS
266 __set_status_flags (pfpsf
, INEXACT_EXCEPTION
);
268 get_BID128_very_fast (&res
, sign_x
, exponent_y
, CR
);
271 // else more than 34 digits in coefficient
272 #ifdef SET_STATUS_FLAGS
273 __set_status_flags (pfpsf
, INVALID_EXCEPTION
);
275 res
.w
[1] = 0x7c00000000000000ull
;