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