]>
Commit | Line | Data |
---|---|---|
473a74b9 BE |
1 | /* Decimal 64-bit format module for the decNumber C Library |
2 | Copyright (C) 2005 Free Software Foundation, Inc. | |
3 | Contributed by IBM Corporation. Author Mike Cowlishaw. | |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9 | Software Foundation; either version 2, or (at your option) any later | |
10 | version. | |
11 | ||
9d1d1cd4 BE |
12 | In addition to the permissions in the GNU General Public License, |
13 | the Free Software Foundation gives you unlimited permission to link | |
14 | the compiled version of this file into combinations with other | |
15 | programs, and to distribute those combinations without any | |
16 | restriction coming from the use of this file. (The General Public | |
17 | License restrictions do apply in other respects; for example, they | |
18 | cover modification of the file, and distribution when not linked | |
19 | into a combine executable.) | |
20 | ||
473a74b9 BE |
21 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
22 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
23 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
24 | for more details. | |
25 | ||
26 | You should have received a copy of the GNU General Public License | |
27 | along with GCC; see the file COPYING. If not, write to the Free | |
c0173136 BE |
28 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
29 | 02110-1301, USA. */ | |
473a74b9 BE |
30 | |
31 | /* ------------------------------------------------------------------ */ | |
32 | /* This module comprises the routines for decimal64 format numbers. */ | |
33 | /* Conversions are supplied to and from decNumber and String. */ | |
34 | /* */ | |
35 | /* No arithmetic routines are included; decNumber provides these. */ | |
36 | /* */ | |
37 | /* Error handling is the same as decNumber (qv.). */ | |
38 | /* ------------------------------------------------------------------ */ | |
39 | #include <string.h> /* [for memset/memcpy] */ | |
40 | #include <stdio.h> /* [for printf] */ | |
41 | ||
42 | #define DECNUMDIGITS 16 /* we need decNumbers with space for 16 */ | |
da817a2f | 43 | #include "config.h" |
473a74b9 BE |
44 | #include "decNumber.h" /* base number library */ |
45 | #include "decNumberLocal.h" /* decNumber local types, etc. */ | |
46 | #include "decimal64.h" /* our primary include */ | |
47 | #include "decUtility.h" /* utility routines */ | |
48 | ||
49 | #if DECTRACE || DECCHECK | |
aa4f41c1 KG |
50 | void decimal64Show (const decimal64 *); /* for debug */ |
51 | void decNumberShow (const decNumber *); /* .. */ | |
473a74b9 BE |
52 | #endif |
53 | ||
54 | /* Useful macro */ | |
55 | /* Clear a structure (e.g., a decNumber) */ | |
56 | #define DEC_clear(d) memset(d, 0, sizeof(*d)) | |
57 | ||
58 | /* ------------------------------------------------------------------ */ | |
59 | /* decimal64FromNumber -- convert decNumber to decimal64 */ | |
60 | /* */ | |
61 | /* ds is the target decimal64 */ | |
62 | /* dn is the source number (assumed valid) */ | |
63 | /* set is the context, used only for reporting errors */ | |
64 | /* */ | |
65 | /* The set argument is used only for status reporting and for the */ | |
66 | /* rounding mode (used if the coefficient is more than DECIMAL64_Pmax */ | |
67 | /* digits or an overflow is detected). If the exponent is out of the */ | |
68 | /* valid range then Overflow or Underflow will be raised. */ | |
69 | /* After Underflow a subnormal result is possible. */ | |
70 | /* */ | |
71 | /* DEC_Clamped is set if the number has to be 'folded down' to fit, */ | |
72 | /* by reducing its exponent and multiplying the coefficient by a */ | |
73 | /* power of ten, or if the exponent on a zero had to be clamped. */ | |
74 | /* ------------------------------------------------------------------ */ | |
75 | decimal64 * | |
aa4f41c1 | 76 | decimal64FromNumber (decimal64 * d64, const decNumber * dn, decContext * set) |
473a74b9 BE |
77 | { |
78 | uInt status = 0; /* status accumulator */ | |
79 | Int pad = 0; /* coefficient pad digits */ | |
80 | decNumber dw; /* work */ | |
81 | decContext dc; /* .. */ | |
82 | uByte isneg = dn->bits & DECNEG; /* non-0 if original sign set */ | |
83 | uInt comb, exp; /* work */ | |
84 | ||
85 | /* If the number is finite, and has too many digits, or the exponent */ | |
86 | /* could be out of range then we reduce the number under the */ | |
87 | /* appropriate constraints */ | |
88 | if (!(dn->bits & DECSPECIAL)) | |
89 | { /* not a special value */ | |
90 | Int ae = dn->exponent + dn->digits - 1; /* adjusted exponent */ | |
91 | if (dn->digits > DECIMAL64_Pmax /* too many digits */ | |
92 | || ae > DECIMAL64_Emax /* likely overflow */ | |
93 | || ae < DECIMAL64_Emin) | |
94 | { /* likely underflow */ | |
95 | decContextDefault (&dc, DEC_INIT_DECIMAL64); /* [no traps] */ | |
96 | dc.round = set->round; /* use supplied rounding */ | |
97 | decNumberPlus (&dw, dn, &dc); /* (round and check) */ | |
98 | /* [this changes -0 to 0, but it will be restored below] */ | |
99 | status |= dc.status; /* save status */ | |
100 | dn = &dw; /* use the work number */ | |
101 | } | |
102 | /* [this could have pushed number to Infinity or zero, so this */ | |
103 | /* rounding must be done before we generate the decimal64] */ | |
104 | } | |
105 | ||
106 | DEC_clear (d64); /* clean the target */ | |
107 | if (dn->bits & DECSPECIAL) | |
108 | { /* a special value */ | |
109 | uByte top; /* work */ | |
110 | if (dn->bits & DECINF) | |
111 | top = DECIMAL_Inf; | |
112 | else | |
113 | { /* sNaN or qNaN */ | |
114 | if ((*dn->lsu != 0 || dn->digits > 1) /* non-zero coefficient */ | |
115 | && (dn->digits < DECIMAL64_Pmax)) | |
116 | { /* coefficient fits */ | |
117 | decDensePackCoeff (dn, d64->bytes, sizeof (d64->bytes), 0); | |
118 | } | |
119 | if (dn->bits & DECNAN) | |
120 | top = DECIMAL_NaN; | |
121 | else | |
122 | top = DECIMAL_sNaN; | |
123 | } | |
124 | d64->bytes[0] = top; | |
125 | } | |
126 | else if (decNumberIsZero (dn)) | |
127 | { /* a zero */ | |
128 | /* set and clamp exponent */ | |
129 | if (dn->exponent < -DECIMAL64_Bias) | |
130 | { | |
131 | exp = 0; | |
132 | status |= DEC_Clamped; | |
133 | } | |
134 | else | |
135 | { | |
136 | exp = dn->exponent + DECIMAL64_Bias; /* bias exponent */ | |
137 | if (exp > DECIMAL64_Ehigh) | |
138 | { /* top clamp */ | |
139 | exp = DECIMAL64_Ehigh; | |
140 | status |= DEC_Clamped; | |
141 | } | |
142 | } | |
143 | comb = (exp >> 5) & 0x18; /* combination field */ | |
144 | d64->bytes[0] = (uByte) (comb << 2); | |
145 | exp &= 0xff; /* remaining exponent bits */ | |
146 | decimal64SetExpCon (d64, exp); | |
147 | } | |
148 | else | |
149 | { /* non-zero finite number */ | |
150 | uInt msd; /* work */ | |
151 | ||
152 | /* we have a dn that fits, but it may need to be padded */ | |
153 | exp = (uInt) (dn->exponent + DECIMAL64_Bias); /* bias exponent */ | |
154 | if (exp > DECIMAL64_Ehigh) | |
155 | { /* fold-down case */ | |
156 | pad = exp - DECIMAL64_Ehigh; | |
157 | exp = DECIMAL64_Ehigh; /* [to maximum] */ | |
158 | status |= DEC_Clamped; | |
159 | } | |
160 | ||
161 | decDensePackCoeff (dn, d64->bytes, sizeof (d64->bytes), pad); | |
162 | ||
163 | /* save and clear the top digit */ | |
164 | msd = ((unsigned) d64->bytes[1] >> 2) & 0x0f; | |
165 | d64->bytes[1] &= 0x03; | |
166 | /* create the combination field */ | |
167 | if (msd >= 8) | |
168 | comb = 0x18 | (msd & 0x01) | ((exp >> 7) & 0x06); | |
169 | else | |
170 | comb = (msd & 0x07) | ((exp >> 5) & 0x18); | |
171 | d64->bytes[0] = (uByte) (comb << 2); | |
172 | exp &= 0xff; /* remaining exponent bits */ | |
173 | decimal64SetExpCon (d64, exp); | |
174 | } | |
175 | ||
176 | if (isneg) | |
177 | decimal64SetSign (d64, 1); | |
178 | if (status != 0) | |
179 | decContextSetStatus (set, status); /* pass on status */ | |
180 | ||
181 | /*decimal64Show(d64); */ | |
182 | return d64; | |
183 | } | |
184 | ||
185 | /* ------------------------------------------------------------------ */ | |
186 | /* decimal64ToNumber -- convert decimal64 to decNumber */ | |
187 | /* d64 is the source decimal64 */ | |
188 | /* dn is the target number, with appropriate space */ | |
189 | /* No error is possible. */ | |
190 | /* ------------------------------------------------------------------ */ | |
191 | decNumber * | |
aa4f41c1 | 192 | decimal64ToNumber (const decimal64 * d64, decNumber * dn) |
473a74b9 BE |
193 | { |
194 | uInt msd; /* coefficient MSD */ | |
195 | decimal64 wk; /* working copy, if needed */ | |
196 | uInt top = d64->bytes[0] & 0x7f; /* top byte, less sign bit */ | |
197 | decNumberZero (dn); /* clean target */ | |
198 | /* set the sign if negative */ | |
199 | if (decimal64Sign (d64)) | |
200 | dn->bits = DECNEG; | |
201 | ||
202 | if (top >= 0x78) | |
203 | { /* is a special */ | |
204 | if ((top & 0x7c) == (DECIMAL_Inf & 0x7c)) | |
205 | dn->bits |= DECINF; | |
206 | else if ((top & 0x7e) == (DECIMAL_NaN & 0x7e)) | |
207 | dn->bits |= DECNAN; | |
208 | else | |
209 | dn->bits |= DECSNAN; | |
210 | msd = 0; /* no top digit */ | |
211 | } | |
212 | else | |
213 | { /* have a finite number */ | |
214 | uInt comb = top >> 2; /* combination field */ | |
215 | uInt exp; /* exponent */ | |
216 | ||
217 | if (comb >= 0x18) | |
218 | { | |
219 | msd = 8 + (comb & 0x01); | |
220 | exp = (comb & 0x06) << 7; /* MSBs */ | |
221 | } | |
222 | else | |
223 | { | |
224 | msd = comb & 0x07; | |
225 | exp = (comb & 0x18) << 5; | |
226 | } | |
227 | dn->exponent = exp + decimal64ExpCon (d64) - DECIMAL64_Bias; /* remove bias */ | |
228 | } | |
229 | ||
230 | /* get the coefficient, unless infinite */ | |
231 | if (!(dn->bits & DECINF)) | |
232 | { | |
233 | Int bunches = DECIMAL64_Pmax / 3; /* coefficient full bunches to convert */ | |
234 | Int odd = 0; /* assume MSD is 0 (no odd bunch) */ | |
235 | if (msd != 0) | |
236 | { /* coefficient has leading non-0 digit */ | |
237 | /* make a copy of the decimal64, with an extra bunch which has */ | |
238 | /* the top digit ready for conversion */ | |
239 | wk = *d64; /* take a copy */ | |
240 | wk.bytes[0] = 0; /* clear all but coecon */ | |
241 | wk.bytes[1] &= 0x03; /* .. */ | |
242 | wk.bytes[1] |= (msd << 2); /* and prefix MSD */ | |
243 | odd++; /* indicate the extra */ | |
244 | d64 = &wk; /* use the work copy */ | |
245 | } | |
246 | decDenseUnpackCoeff (d64->bytes, sizeof (d64->bytes), dn, bunches, odd); | |
247 | } | |
248 | return dn; | |
249 | } | |
250 | ||
251 | /* ------------------------------------------------------------------ */ | |
252 | /* to-scientific-string -- conversion to numeric string */ | |
253 | /* to-engineering-string -- conversion to numeric string */ | |
254 | /* */ | |
255 | /* decimal64ToString(d64, string); */ | |
256 | /* decimal64ToEngString(d64, string); */ | |
257 | /* */ | |
258 | /* d64 is the decimal64 format number to convert */ | |
259 | /* string is the string where the result will be laid out */ | |
260 | /* */ | |
261 | /* string must be at least 24 characters */ | |
262 | /* */ | |
263 | /* No error is possible, and no status can be set. */ | |
264 | /* ------------------------------------------------------------------ */ | |
265 | char * | |
aa4f41c1 | 266 | decimal64ToString (const decimal64 * d64, char *string) |
473a74b9 BE |
267 | { |
268 | decNumber dn; /* work */ | |
269 | decimal64ToNumber (d64, &dn); | |
270 | decNumberToString (&dn, string); | |
271 | return string; | |
272 | } | |
273 | ||
274 | char * | |
aa4f41c1 | 275 | decimal64ToEngString (const decimal64 * d64, char *string) |
473a74b9 BE |
276 | { |
277 | decNumber dn; /* work */ | |
278 | decimal64ToNumber (d64, &dn); | |
279 | decNumberToEngString (&dn, string); | |
280 | return string; | |
281 | } | |
282 | ||
283 | /* ------------------------------------------------------------------ */ | |
284 | /* to-number -- conversion from numeric string */ | |
285 | /* */ | |
286 | /* decimal64FromString(result, string, set); */ | |
287 | /* */ | |
288 | /* result is the decimal64 format number which gets the result of */ | |
289 | /* the conversion */ | |
290 | /* *string is the character string which should contain a valid */ | |
291 | /* number (which may be a special value) */ | |
292 | /* set is the context */ | |
293 | /* */ | |
294 | /* The context is supplied to this routine is used for error handling */ | |
295 | /* (setting of status and traps) and for the rounding mode, only. */ | |
296 | /* If an error occurs, the result will be a valid decimal64 NaN. */ | |
297 | /* ------------------------------------------------------------------ */ | |
298 | decimal64 * | |
c5d43417 | 299 | decimal64FromString (decimal64 * result, const char *string, decContext * set) |
473a74b9 BE |
300 | { |
301 | decContext dc; /* work */ | |
302 | decNumber dn; /* .. */ | |
303 | ||
304 | decContextDefault (&dc, DEC_INIT_DECIMAL64); /* no traps, please */ | |
305 | dc.round = set->round; /* use supplied rounding */ | |
306 | ||
307 | decNumberFromString (&dn, string, &dc); /* will round if needed */ | |
308 | ||
309 | decimal64FromNumber (result, &dn, &dc); | |
310 | if (dc.status != 0) | |
311 | { /* something happened */ | |
312 | decContextSetStatus (set, dc.status); /* .. pass it on */ | |
313 | } | |
314 | return result; | |
315 | } | |
316 | ||
317 | #if DECTRACE || DECCHECK | |
318 | /* ------------------------------------------------------------------ */ | |
319 | /* decimal64Show -- display a single in hexadecimal [debug aid] */ | |
320 | /* d64 -- the number to show */ | |
321 | /* ------------------------------------------------------------------ */ | |
322 | /* Also shows sign/cob/expconfields extracted */ | |
323 | void | |
aa4f41c1 | 324 | decimal64Show (const decimal64 * d64) |
473a74b9 BE |
325 | { |
326 | char buf[DECIMAL64_Bytes * 2 + 1]; | |
327 | Int i, j; | |
328 | j = 0; | |
329 | for (i = 0; i < DECIMAL64_Bytes; i++) | |
330 | { | |
331 | sprintf (&buf[j], "%02x", d64->bytes[i]); | |
332 | j = j + 2; | |
333 | } | |
334 | printf (" D64> %s [S:%d Cb:%02x E:%d]\n", buf, | |
335 | decimal64Sign (d64), decimal64Comb (d64), decimal64ExpCon (d64)); | |
336 | } | |
337 | #endif |