]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gcclibs/libdecnumber/decUtility.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gcclibs / libdecnumber / decUtility.c
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.
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    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
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
28    Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
29    02110-1301, USA.  */
30
31 #include "config.h"
32 #include "decNumber.h"          /* base number library */
33 #include "decNumberLocal.h"     /* decNumber local types, etc. */
34 #include "decUtility.h"         /* utility routines */
35
36 /* ================================================================== */
37 /* Shared utility routines                                            */
38 /* ================================================================== */
39
40 /* define and include the conversion tables to use */
41 #define DEC_BIN2DPD 1           /* used for all sizes */
42 #if DECDPUN==3
43 #define DEC_DPD2BIN 1
44 #else
45 #define DEC_DPD2BCD 1
46 #endif
47 #include "decDPD.h"             /* lookup tables */
48
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. */
54 #define DECMAX754   34
55 #define DECMAXUNITS ((DECMAX754+DECDPUN-1)/DECDPUN)
56
57 /* ------------------------------------------------------------------ */
58 /* decDensePackCoeff -- densely pack coefficient into DPD form        */
59 /*                                                                    */
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) */
64 /*                                                                    */
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    */
69 /* caller.                                                            */
70 /*                                                                    */
71 /* shift is used for 'fold-down' padding.                             */
72 /*                                                                    */
73 /* No error is possible.                                              */
74 /* ------------------------------------------------------------------ */
75 void
76 decDensePackCoeff (const decNumber * dn, uByte * bytes, Int len, Int shift)
77 {
78   Int cut;                      /* work */
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 */
88 #endif
89
90   if (shift != 0)
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 */
98
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 */
102
103       cut = (DECDPUN - shift % DECDPUN) % DECDPUN;
104       for (; source >= dn->lsu; source--, target--)
105         {
106           /* split the source Unit and accumulate remainder for next */
107           uInt rem = *source % powers[cut];
108           next += *source / powers[cut];
109           if (target <= first)
110             *target = (Unit) next;      /* write to target iff valid */
111           next = rem * powers[DECDPUN - cut];   /* save remainder for next Unit */
112         }
113       /* propagate remainder to one below and clear the rest */
114       for (; target >= uar; target--)
115         {
116           *target = (Unit) next;
117           next = 0;
118         }
119       digits += shift;          /* add count (shift) of zeros added */
120       inu = uar;                /* use units in working array */
121     }
122
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 */
126
127 #if DECDPUN!=3                  /* not fast path */
128   in = *inu;                    /* prime */
129   cut = 0;                      /* at lowest digit */
130   bin = 0;                      /* [keep compiler quiet] */
131 #endif
132
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 */
139
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++)
144         {
145 #if DECDPUN<=4
146           Unit temp = (Unit) ((uInt) (in * 6554) >> 16);
147           dig = (Unit) (in - X10 (temp));
148           in = temp;
149 #else
150           dig = in % 10;
151           in = in / 10;
152 #endif
153
154           if (j == 0)
155             bin = dig;
156           else if (j == 1)
157             bin += X10 (dig);
158           else                  /* j==2 */
159             bin += X100 (dig);
160
161           digits--;
162           if (digits == 0)
163             break;              /* [also protects *inu below] */
164           cut++;
165           if (cut == DECDPUN)
166             {
167               inu++;
168               in = *inu;
169               cut = 0;
170             }
171         }
172 #endif
173       /* here we have 3 digits in bin, or have used all input digits */
174
175       dpd = BIN2DPD[bin];
176
177       /* write bunch (bcd) to byte array */
178       switch (n & 0x03)
179         {                       /* phase 0-3 */
180         case 0:
181           *bout = (uByte) dpd;  /* [top 2 bits truncated] */
182           bout--;
183           *bout = (uByte) (dpd >> 8);
184           break;
185         case 1:
186           *bout |= (uByte) (dpd << 2);
187           bout--;
188           *bout = (uByte) (dpd >> 6);
189           break;
190         case 2:
191           *bout |= (uByte) (dpd << 4);
192           bout--;
193           *bout = (uByte) (dpd >> 4);
194           break;
195         case 3:
196           *bout |= (uByte) (dpd << 6);
197           bout--;
198           *bout = (uByte) (dpd >> 2);
199           bout--;
200           break;
201         }                       /* switch */
202     }                           /* n bunches */
203   return;
204 }
205
206 /* ------------------------------------------------------------------ */
207 /* decDenseUnpackCoeff -- unpack a format's coefficient               */
208 /*                                                                    */
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                                    */
215 /*                                                                    */
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.)        */
219 /*                                                                    */
220 /* dn->digits is set, but not the sign or exponent.                   */
221 /* No error is possible [the redundant 888 codes are allowed].        */
222 /* ------------------------------------------------------------------ */
223 void
224 decDenseUnpackCoeff (const uByte * bytes, Int len, decNumber * dn,
225                      Int bunches, Int odd)
226 {
227   uInt dpd = 0;                 /* collector for 10 bits */
228   Int n;                        /* counter */
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 */
234 #if DECDPUN!=3
235   uInt bcd;                     /* BCD result */
236   uInt nibble;                  /* work */
237 #endif
238
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 */
244       switch (n & 0x03)
245         {                       /* phase 0-3 */
246         case 0:
247           dpd = *bin;
248           bin--;
249           dpd |= (*bin & 0x03) << 8;
250           break;
251         case 1:
252           dpd = (unsigned) *bin >> 2;
253           bin--;
254           dpd |= (*bin & 0x0F) << 6;
255           break;
256         case 2:
257           dpd = (unsigned) *bin >> 4;
258           bin--;
259           dpd |= (*bin & 0x3F) << 4;
260           break;
261         case 3:
262           dpd = (unsigned) *bin >> 6;
263           bin--;
264           dpd |= (*bin) << 2;
265           bin--;
266           break;
267         }                       /*switch */
268
269 #if DECDPUN==3
270       if (dpd == 0)
271         *uout = 0;
272       else
273         {
274           *uout = DPD2BIN[dpd]; /* convert 10 bits to binary 0-999 */
275           last = uout;          /* record most significant unit */
276         }
277       uout++;
278
279 #else /* DECDPUN!=3 */
280       if (dpd == 0)
281         {                       /* fastpath [e.g., leading zeros] */
282           cut += 3;
283           for (; cut >= DECDPUN;)
284             {
285               cut -= DECDPUN;
286               *uout = out;
287               uout++;
288               out = 0;
289             }
290           continue;
291         }
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;
297       if (nibble)
298         {
299           last = uout;
300           out = (Unit) (out + nibble * powers[cut]);
301         }
302       cut++;
303       if (cut == DECDPUN)
304         {
305           *uout = out;
306           uout++;
307           cut = 0;
308           out = 0;
309         }
310       if (n < bunches)
311         {
312           nibble = bcd & 0x00f0;
313           if (nibble)
314             {
315               nibble >>= 4;
316               last = uout;
317               out = (Unit) (out + nibble * powers[cut]);
318             }
319           cut++;
320           if (cut == DECDPUN)
321             {
322               *uout = out;
323               uout++;
324               cut = 0;
325               out = 0;
326             }
327           nibble = bcd & 0x0f00;
328           if (nibble)
329             {
330               nibble >>= 8;
331               last = uout;
332               out = (Unit) (out + nibble * powers[cut]);
333             }
334           cut++;
335           if (cut == DECDPUN)
336             {
337               *uout = out;
338               uout++;
339               cut = 0;
340               out = 0;
341             }
342         }
343 #endif
344     }                           /* n */
345   if (cut != 0)
346     *uout = out;                /* write out final unit */
347
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++)
352     {
353       if (*last < powers[cut])
354         break;
355       dn->digits++;
356     }
357   if (dn->digits == 0)
358     dn->digits++;               /* zero has one digit */
359   return;
360 }