]>
Commit | Line | Data |
---|---|---|
f1717362 | 1 | /* Copyright (C) 2007-2016 Free Software Foundation, Inc. |
9b6b0236 | 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 | |
6bc9506f | 7 | Software Foundation; either version 3, or (at your option) any later |
9b6b0236 | 8 | version. |
9 | ||
9b6b0236 | 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 | ||
6bc9506f | 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/>. */ | |
9b6b0236 | 23 | |
24 | /***************************************************************************** | |
25 | * BID64 remainder | |
26 | ***************************************************************************** | |
27 | * | |
28 | * Algorithm description: | |
29 | * | |
30 | * if(exponent_x < exponent_y) | |
31 | * scale coefficient_y so exponents are aligned | |
32 | * perform coefficient divide (64-bit integer divide), unless | |
33 | * coefficient_y is longer than 64 bits (clearly larger | |
34 | * than coefficient_x) | |
35 | * else // exponent_x > exponent_y | |
36 | * use a loop to scale coefficient_x to 18_digits, divide by | |
37 | * coefficient_y (64-bit integer divide), calculate remainder | |
38 | * as new_coefficient_x and repeat until final remainder is obtained | |
39 | * (when new_exponent_x < exponent_y) | |
40 | * | |
41 | ****************************************************************************/ | |
42 | ||
43 | #include "bid_internal.h" | |
44 | ||
45 | #define MAX_FORMAT_DIGITS 16 | |
46 | #define DECIMAL_EXPONENT_BIAS 398 | |
47 | #define MASK_BINARY_EXPONENT 0x7ff0000000000000ull | |
48 | #define BINARY_EXPONENT_BIAS 0x3ff | |
49 | #define UPPER_EXPON_LIMIT 51 | |
50 | ||
51 | #if DECIMAL_CALL_BY_REFERENCE | |
52 | ||
53 | void | |
84d1fc49 | 54 | bid64_rem (UINT64 * pres, UINT64 * px, |
9b6b0236 | 55 | UINT64 * |
84d1fc49 | 56 | py _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) { |
9b6b0236 | 57 | UINT64 x, y; |
58 | #else | |
59 | ||
60 | UINT64 | |
84d1fc49 | 61 | bid64_rem (UINT64 x, |
62 | UINT64 y _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) { | |
9b6b0236 | 63 | #endif |
64 | UINT128 CY; | |
65 | UINT64 sign_x, sign_y, coefficient_x, coefficient_y, res; | |
84d1fc49 | 66 | UINT64 Q, R, R2, T, valid_y, valid_x; |
9b6b0236 | 67 | int_float tempx; |
84d1fc49 | 68 | int exponent_x, exponent_y, bin_expon, e_scale; |
9b6b0236 | 69 | int digits_x, diff_expon; |
70 | ||
71 | #if DECIMAL_CALL_BY_REFERENCE | |
72 | x = *px; | |
73 | y = *py; | |
74 | #endif | |
75 | ||
84d1fc49 | 76 | valid_y = unpack_BID64 (&sign_y, &exponent_y, &coefficient_y, y); |
77 | valid_x = unpack_BID64 (&sign_x, &exponent_x, &coefficient_x, x); | |
78 | ||
9b6b0236 | 79 | // unpack arguments, check for NaN or Infinity |
84d1fc49 | 80 | if (!valid_x) { |
9b6b0236 | 81 | // x is Inf. or NaN or 0 |
82 | #ifdef SET_STATUS_FLAGS | |
83 | if ((y & SNAN_MASK64) == SNAN_MASK64) // y is sNaN | |
84 | __set_status_flags (pfpsf, INVALID_EXCEPTION); | |
85 | #endif | |
86 | ||
87 | // test if x is NaN | |
88 | if ((x & 0x7c00000000000000ull) == 0x7c00000000000000ull) { | |
89 | #ifdef SET_STATUS_FLAGS | |
90 | if (((x & SNAN_MASK64) == SNAN_MASK64)) | |
91 | __set_status_flags (pfpsf, INVALID_EXCEPTION); | |
92 | #endif | |
84d1fc49 | 93 | res = coefficient_x & QUIET_MASK64;; |
9b6b0236 | 94 | BID_RETURN (res); |
95 | } | |
96 | // x is Infinity? | |
97 | if ((x & 0x7800000000000000ull) == 0x7800000000000000ull) { | |
84d1fc49 | 98 | if (((y & NAN_MASK64) != NAN_MASK64)) { |
9b6b0236 | 99 | #ifdef SET_STATUS_FLAGS |
9b6b0236 | 100 | __set_status_flags (pfpsf, INVALID_EXCEPTION); |
101 | #endif | |
84d1fc49 | 102 | // return NaN |
103 | res = 0x7c00000000000000ull; | |
104 | BID_RETURN (res); | |
105 | } | |
9b6b0236 | 106 | } |
107 | // x is 0 | |
108 | // return x if y != 0 | |
109 | if (((y & 0x7800000000000000ull) < 0x7800000000000000ull) && | |
84d1fc49 | 110 | coefficient_y) { |
9b6b0236 | 111 | if ((y & 0x6000000000000000ull) == 0x6000000000000000ull) |
112 | exponent_y = (y >> 51) & 0x3ff; | |
113 | else | |
114 | exponent_y = (y >> 53) & 0x3ff; | |
115 | ||
116 | if (exponent_y < exponent_x) | |
117 | exponent_x = exponent_y; | |
118 | ||
119 | x = exponent_x; | |
120 | x <<= 53; | |
121 | ||
122 | res = x | sign_x; | |
123 | BID_RETURN (res); | |
124 | } | |
125 | ||
126 | } | |
84d1fc49 | 127 | if (!valid_y) { |
9b6b0236 | 128 | // y is Inf. or NaN |
129 | ||
130 | // test if y is NaN | |
131 | if ((y & 0x7c00000000000000ull) == 0x7c00000000000000ull) { | |
132 | #ifdef SET_STATUS_FLAGS | |
133 | if (((y & SNAN_MASK64) == SNAN_MASK64)) | |
134 | __set_status_flags (pfpsf, INVALID_EXCEPTION); | |
135 | #endif | |
84d1fc49 | 136 | res = coefficient_y & QUIET_MASK64;; |
9b6b0236 | 137 | BID_RETURN (res); |
138 | } | |
139 | // y is Infinity? | |
140 | if ((y & 0x7800000000000000ull) == 0x7800000000000000ull) { | |
84d1fc49 | 141 | res = very_fast_get_BID64 (sign_x, exponent_x, coefficient_x); |
9b6b0236 | 142 | BID_RETURN (res); |
143 | } | |
144 | // y is 0, return NaN | |
145 | { | |
146 | #ifdef SET_STATUS_FLAGS | |
147 | __set_status_flags (pfpsf, INVALID_EXCEPTION); | |
148 | #endif | |
149 | res = 0x7c00000000000000ull; | |
150 | BID_RETURN (res); | |
151 | } | |
152 | } | |
153 | ||
154 | ||
155 | diff_expon = exponent_x - exponent_y; | |
156 | if (diff_expon <= 0) { | |
157 | diff_expon = -diff_expon; | |
158 | ||
159 | if (diff_expon > 16) { | |
160 | // |x|<|y| in this case | |
161 | res = x; | |
162 | BID_RETURN (res); | |
163 | } | |
164 | // set exponent of y to exponent_x, scale coefficient_y | |
84d1fc49 | 165 | T = power10_table_128[diff_expon].w[0]; |
9b6b0236 | 166 | __mul_64x64_to_128 (CY, coefficient_y, T); |
167 | ||
168 | if (CY.w[1] || CY.w[0] > (coefficient_x << 1)) { | |
169 | res = x; | |
170 | BID_RETURN (res); | |
171 | } | |
172 | ||
173 | Q = coefficient_x / CY.w[0]; | |
174 | R = coefficient_x - Q * CY.w[0]; | |
175 | ||
176 | R2 = R + R; | |
177 | if (R2 > CY.w[0] || (R2 == CY.w[0] && (Q & 1))) { | |
178 | R = CY.w[0] - R; | |
179 | sign_x ^= 0x8000000000000000ull; | |
180 | } | |
181 | ||
182 | res = very_fast_get_BID64 (sign_x, exponent_x, R); | |
183 | BID_RETURN (res); | |
184 | } | |
185 | ||
186 | ||
187 | while (diff_expon > 0) { | |
188 | // get number of digits in coeff_x | |
189 | tempx.d = (float) coefficient_x; | |
190 | bin_expon = ((tempx.i >> 23) & 0xff) - 0x7f; | |
84d1fc49 | 191 | digits_x = estimate_decimal_digits[bin_expon]; |
9b6b0236 | 192 | // will not use this test, dividend will have 18 or 19 digits |
84d1fc49 | 193 | //if(coefficient_x >= power10_table_128[digits_x].w[0]) |
9b6b0236 | 194 | // digits_x++; |
195 | ||
196 | e_scale = 18 - digits_x; | |
197 | if (diff_expon >= e_scale) { | |
198 | diff_expon -= e_scale; | |
199 | } else { | |
200 | e_scale = diff_expon; | |
201 | diff_expon = 0; | |
202 | } | |
203 | ||
204 | // scale dividend to 18 or 19 digits | |
84d1fc49 | 205 | coefficient_x *= power10_table_128[e_scale].w[0]; |
9b6b0236 | 206 | |
207 | // quotient | |
208 | Q = coefficient_x / coefficient_y; | |
209 | // remainder | |
210 | coefficient_x -= Q * coefficient_y; | |
211 | ||
212 | // check for remainder == 0 | |
213 | if (!coefficient_x) { | |
214 | res = very_fast_get_BID64_small_mantissa (sign_x, exponent_y, 0); | |
215 | BID_RETURN (res); | |
216 | } | |
217 | } | |
218 | ||
219 | R2 = coefficient_x + coefficient_x; | |
220 | if (R2 > coefficient_y || (R2 == coefficient_y && (Q & 1))) { | |
221 | coefficient_x = coefficient_y - coefficient_x; | |
222 | sign_x ^= 0x8000000000000000ull; | |
223 | } | |
224 | ||
225 | res = very_fast_get_BID64 (sign_x, exponent_y, coefficient_x); | |
226 | BID_RETURN (res); | |
227 | ||
228 | } |