1 /* Utility functions for decimal floating point support via decNumber.
2 Copyright (C) 2005 Free Software Foundation, Inc.
3 Contributed by IBM Corporation. Author Mike Cowlishaw.
5 This file is part of GCC.
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
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.)
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
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
28 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
32 #include "decNumber.h" /* base number library */
33 #include "decNumberLocal.h" /* decNumber local types, etc. */
34 #include "decUtility.h" /* utility routines */
36 /* ================================================================== */
37 /* Shared utility routines */
38 /* ================================================================== */
40 /* define and include the conversion tables to use */
41 #define DEC_BIN2DPD 1 /* used for all sizes */
47 #include "decDPD.h" /* lookup tables */
49 /* The maximum number of decNumberUnits we need for a working copy of */
50 /* the units array is the ceiling of digits/DECDPUN, where digits is */
51 /* the maximum number of digits in any of the formats for which this */
52 /* is used. We do not want to include decimal128.h, so, as a very */
53 /* special case, that number is defined here. */
55 #define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN)
57 /* ------------------------------------------------------------------ */
58 /* decDensePackCoeff -- densely pack coefficient into DPD form */
60 /* dn is the source number (assumed valid, max DECMAX754 digits) */
61 /* bytes is the target's byte array */
62 /* len is length of target format's byte array */
63 /* shift is the number of 0 digits to add on the right (normally 0) */
65 /* The coefficient must be known small enough to fit, and is filled */
66 /* in from the right (least significant first). Note that the full */
67 /* coefficient is copied, including the leading 'odd' digit. This */
68 /* digit is retrieved and packed into the combination field by the */
71 /* shift is used for 'fold-down' padding. */
73 /* No error is possible. */
74 /* ------------------------------------------------------------------ */
76 decDensePackCoeff (const decNumber
* dn
, uByte
* bytes
, Int len
, Int shift
)
79 Int n
; /* output bunch counter */
80 Int digits
= dn
->digits
; /* digit countdown */
81 uInt dpd
; /* densely packed decimal value */
82 uInt bin
; /* binary value 0-999 */
83 uByte
*bout
; /* -> current output byte */
84 const Unit
*inu
= dn
->lsu
; /* -> current input unit */
85 Unit uar
[DECMAXUNITS
]; /* working copy of units, iff shifted */
86 #if DECDPUN!=3 /* not fast path */
87 Unit in
; /* current input unit */
91 { /* shift towards most significant required */
92 /* shift the units array to the left by pad digits and copy */
93 /* [this code is a special case of decShiftToMost, which could */
94 /* be used instead if exposed and the array were copied first] */
95 Unit
*target
, *first
; /* work */
96 const Unit
*source
; /* work */
97 uInt next
= 0; /* work */
99 source
= dn
->lsu
+ D2U (digits
) - 1; /* where msu comes from */
100 first
= uar
+ D2U (digits
+ shift
) - 1; /* where msu will end up */
101 target
= uar
+ D2U (digits
) - 1 + D2U (shift
); /* where upper part of first cut goes */
103 cut
= (DECDPUN
- shift
% DECDPUN
) % DECDPUN
;
104 for (; source
>= dn
->lsu
; source
--, target
--)
106 /* split the source Unit and accumulate remainder for next */
107 uInt rem
= *source
% powers
[cut
];
108 next
+= *source
/ powers
[cut
];
110 *target
= (Unit
) next
; /* write to target iff valid */
111 next
= rem
* powers
[DECDPUN
- cut
]; /* save remainder for next Unit */
113 /* propagate remainder to one below and clear the rest */
114 for (; target
>= uar
; target
--)
116 *target
= (Unit
) next
;
119 digits
+= shift
; /* add count (shift) of zeros added */
120 inu
= uar
; /* use units in working array */
123 /* densely pack the coefficient into the byte array, starting from
124 the right (optionally padded) */
125 bout
= &bytes
[len
- 1]; /* rightmost result byte for phase */
127 #if DECDPUN!=3 /* not fast path */
128 in
= *inu
; /* prime */
129 cut
= 0; /* at lowest digit */
130 bin
= 0; /* [keep compiler quiet] */
133 for (n
= 0; digits
> 0; n
++)
134 { /* each output bunch */
135 #if DECDPUN==3 /* fast path, 3-at-a-time */
136 bin
= *inu
; /* 3 ready for convert */
137 digits
-= 3; /* [may go negative] */
138 inu
++; /* may need another */
140 #else /* must collect digit-by-digit */
141 Unit dig
; /* current digit */
142 Int j
; /* digit-in-bunch count */
143 for (j
= 0; j
< 3; j
++)
146 Unit temp
= (Unit
) ((uInt
) (in
* 6554) >> 16);
147 dig
= (Unit
) (in
- X10 (temp
));
163 break; /* [also protects *inu below] */
173 /* here we have 3 digits in bin, or have used all input digits */
177 /* write bunch (bcd) to byte array */
181 *bout
= (uByte
) dpd
; /* [top 2 bits truncated] */
183 *bout
= (uByte
) (dpd
>> 8);
186 *bout
|= (uByte
) (dpd
<< 2);
188 *bout
= (uByte
) (dpd
>> 6);
191 *bout
|= (uByte
) (dpd
<< 4);
193 *bout
= (uByte
) (dpd
>> 4);
196 *bout
|= (uByte
) (dpd
<< 6);
198 *bout
= (uByte
) (dpd
>> 2);
206 /* ------------------------------------------------------------------ */
207 /* decDenseUnpackCoeff -- unpack a format's coefficient */
209 /* byte is the source's byte array */
210 /* len is length of the source's byte array */
211 /* dn is the target number, with 7, 16, or 34-digit space. */
212 /* bunches is the count of DPD groups in the decNumber (2, 5, or 11)*/
213 /* odd is 1 if there is a non-zero leading 10-bit group containing */
214 /* a single digit, 0 otherwise */
216 /* (This routine works on a copy of the number, if necessary, where */
217 /* an extra 10-bit group is prefixed to the coefficient continuation */
218 /* to hold the most significant digit if the latter is non-0.) */
220 /* dn->digits is set, but not the sign or exponent. */
221 /* No error is possible [the redundant 888 codes are allowed]. */
222 /* ------------------------------------------------------------------ */
224 decDenseUnpackCoeff (const uByte
* bytes
, Int len
, decNumber
* dn
,
225 Int bunches
, Int odd
)
227 uInt dpd
= 0; /* collector for 10 bits */
229 const uByte
*bin
; /* -> current input byte */
230 Unit
*uout
= dn
->lsu
; /* -> current output unit */
231 Unit out
= 0; /* accumulator */
232 Int cut
= 0; /* power of ten in current unit */
233 Unit
*last
= uout
; /* will be unit containing msd */
235 uInt bcd
; /* BCD result */
236 uInt nibble
; /* work */
239 /* Expand the densely-packed integer, right to left */
240 bin
= &bytes
[len
- 1]; /* next input byte to use */
241 for (n
= 0; n
< bunches
+ odd
; n
++)
242 { /* N bunches of 10 bits */
243 /* assemble the 10 bits */
249 dpd
|= (*bin
& 0x03) << 8;
252 dpd
= (unsigned) *bin
>> 2;
254 dpd
|= (*bin
& 0x0F) << 6;
257 dpd
= (unsigned) *bin
>> 4;
259 dpd
|= (*bin
& 0x3F) << 4;
262 dpd
= (unsigned) *bin
>> 6;
274 *uout
= DPD2BIN
[dpd
]; /* convert 10 bits to binary 0-999 */
275 last
= uout
; /* record most significant unit */
279 #else /* DECDPUN!=3 */
281 { /* fastpath [e.g., leading zeros] */
283 for (; cut
>= DECDPUN
;)
292 bcd
= DPD2BCD
[dpd
]; /* convert 10 bits to 12 bits BCD */
293 /* now split the 3 BCD nibbles into bytes, and accumulate into units */
294 /* If this is the last bunch and it is an odd one, we only have one */
295 /* nibble to handle [extras could overflow a Unit] */
296 nibble
= bcd
& 0x000f;
300 out
= (Unit
) (out
+ nibble
* powers
[cut
]);
312 nibble
= bcd
& 0x00f0;
317 out
= (Unit
) (out
+ nibble
* powers
[cut
]);
327 nibble
= bcd
& 0x0f00;
332 out
= (Unit
) (out
+ nibble
* powers
[cut
]);
346 *uout
= out
; /* write out final unit */
348 /* here, last points to the most significant unit with digits */
349 /* we need to inspect it to get final digits count */
350 dn
->digits
= (last
- dn
->lsu
) * DECDPUN
; /* floor of digits */
351 for (cut
= 0; cut
< DECDPUN
; cut
++)
353 if (*last
< powers
[cut
])
358 dn
->digits
++; /* zero has one digit */