OSDN Git Service

* Makefile.in (libdecnumber_a_SOURCES): List Symbols headers.
[pf3gnuchains/gcc-fork.git] / libdecnumber / dpd / decimal32.c
1 /* Decimal 32-bit format module for the decNumber C Library.
2    Copyright (C) 2005, 2007 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 /* ------------------------------------------------------------------ */
32 /* Decimal 32-bit format module                                       */
33 /* ------------------------------------------------------------------ */
34 /* This module comprises the routines for decimal32 format numbers.   */
35 /* Conversions are supplied to and from decNumber and String.         */
36 /*                                                                    */
37 /* This is used when decNumber provides operations, either for all    */
38 /* operations or as a proxy between decNumber and decSingle.          */
39 /*                                                                    */
40 /* Error handling is the same as decNumber (qv.).                     */
41 /* ------------------------------------------------------------------ */
42 #include <string.h>           /* [for memset/memcpy] */
43 #include <stdio.h>            /* [for printf] */
44
45 #include "config.h"           /* GCC definitions */
46 #define  DECNUMDIGITS  7      /* make decNumbers with space for 7 */
47 #include "decNumber.h"        /* base number library */
48 #include "decNumberLocal.h"   /* decNumber local types, etc. */
49 #include "decimal32.h"        /* our primary include */
50
51 /* Utility tables and routines [in decimal64.c] */
52 extern const uInt   COMBEXP[32], COMBMSD[32];
53 extern const uShort DPD2BIN[1024];
54 extern const uShort BIN2DPD[1000];
55 extern const uByte  BIN2CHAR[4001];
56
57 extern void decDigitsToDPD(const decNumber *, uInt *, Int);
58 extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
59
60 #if DECTRACE || DECCHECK
61 void decimal32Show(const decimal32 *);            /* for debug */
62 extern void decNumberShow(const decNumber *);     /* .. */
63 #endif
64
65 /* Useful macro */
66 /* Clear a structure (e.g., a decNumber) */
67 #define DEC_clear(d) memset(d, 0, sizeof(*d))
68
69 /* ------------------------------------------------------------------ */
70 /* decimal32FromNumber -- convert decNumber to decimal32              */
71 /*                                                                    */
72 /*   ds is the target decimal32                                       */
73 /*   dn is the source number (assumed valid)                          */
74 /*   set is the context, used only for reporting errors               */
75 /*                                                                    */
76 /* The set argument is used only for status reporting and for the     */
77 /* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */
78 /* digits or an overflow is detected).  If the exponent is out of the */
79 /* valid range then Overflow or Underflow will be raised.             */
80 /* After Underflow a subnormal result is possible.                    */
81 /*                                                                    */
82 /* DEC_Clamped is set if the number has to be 'folded down' to fit,   */
83 /* by reducing its exponent and multiplying the coefficient by a      */
84 /* power of ten, or if the exponent on a zero had to be clamped.      */
85 /* ------------------------------------------------------------------ */
86 decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn,
87                               decContext *set) {
88   uInt status=0;                   /* status accumulator */
89   Int ae;                          /* adjusted exponent */
90   decNumber  dw;                   /* work */
91   decContext dc;                   /* .. */
92   uInt *pu;                        /* .. */
93   uInt comb, exp;                  /* .. */
94   uInt targ=0;                     /* target 32-bit */
95
96   /* If the number has too many digits, or the exponent could be */
97   /* out of range then reduce the number under the appropriate */
98   /* constraints.  This could push the number to Infinity or zero, */
99   /* so this check and rounding must be done before generating the */
100   /* decimal32] */
101   ae=dn->exponent+dn->digits-1;              /* [0 if special] */
102   if (dn->digits>DECIMAL32_Pmax              /* too many digits */
103    || ae>DECIMAL32_Emax                      /* likely overflow */
104    || ae<DECIMAL32_Emin) {                   /* likely underflow */
105     decContextDefault(&dc, DEC_INIT_DECIMAL32); /* [no traps] */
106     dc.round=set->round;                     /* use supplied rounding */
107     decNumberPlus(&dw, dn, &dc);             /* (round and check) */
108     /* [this changes -0 to 0, so enforce the sign...] */
109     dw.bits|=dn->bits&DECNEG;
110     status=dc.status;                        /* save status */
111     dn=&dw;                                  /* use the work number */
112     } /* maybe out of range */
113
114   if (dn->bits&DECSPECIAL) {                      /* a special value */
115     if (dn->bits&DECINF) targ=DECIMAL_Inf<<24;
116      else {                                       /* sNaN or qNaN */
117       if ((*dn->lsu!=0 || dn->digits>1)           /* non-zero coefficient */
118        && (dn->digits<DECIMAL32_Pmax)) {          /* coefficient fits */
119         decDigitsToDPD(dn, &targ, 0);
120         }
121       if (dn->bits&DECNAN) targ|=DECIMAL_NaN<<24;
122        else targ|=DECIMAL_sNaN<<24;
123       } /* a NaN */
124     } /* special */
125
126    else { /* is finite */
127     if (decNumberIsZero(dn)) {               /* is a zero */
128       /* set and clamp exponent */
129       if (dn->exponent<-DECIMAL32_Bias) {
130         exp=0;                               /* low clamp */
131         status|=DEC_Clamped;
132         }
133        else {
134         exp=dn->exponent+DECIMAL32_Bias;     /* bias exponent */
135         if (exp>DECIMAL32_Ehigh) {           /* top clamp */
136           exp=DECIMAL32_Ehigh;
137           status|=DEC_Clamped;
138           }
139         }
140       comb=(exp>>3) & 0x18;             /* msd=0, exp top 2 bits .. */
141       }
142      else {                             /* non-zero finite number */
143       uInt msd;                         /* work */
144       Int pad=0;                        /* coefficient pad digits */
145
146       /* the dn is known to fit, but it may need to be padded */
147       exp=(uInt)(dn->exponent+DECIMAL32_Bias);    /* bias exponent */
148       if (exp>DECIMAL32_Ehigh) {                  /* fold-down case */
149         pad=exp-DECIMAL32_Ehigh;
150         exp=DECIMAL32_Ehigh;                      /* [to maximum] */
151         status|=DEC_Clamped;
152         }
153
154       /* fastpath common case */
155       if (DECDPUN==3 && pad==0) {
156         targ=BIN2DPD[dn->lsu[0]];
157         if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10;
158         msd=(dn->digits==7 ? dn->lsu[2] : 0);
159         }
160        else { /* general case */
161         decDigitsToDPD(dn, &targ, pad);
162         /* save and clear the top digit */
163         msd=targ>>20;
164         targ&=0x000fffff;
165         }
166
167       /* create the combination field */
168       if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01);
169              else comb=((exp>>3) & 0x18) | msd;
170       }
171     targ|=comb<<26;                /* add combination field .. */
172     targ|=(exp&0x3f)<<20;          /* .. and exponent continuation */
173     } /* finite */
174
175   if (dn->bits&DECNEG) targ|=0x80000000;  /* add sign bit */
176
177   /* now write to storage; this is endian */
178   pu=(uInt *)d32->bytes;           /* overlay */
179   *pu=targ;                        /* directly store the int */
180
181   if (status!=0) decContextSetStatus(set, status); /* pass on status */
182   /* decimal32Show(d32); */
183   return d32;
184   } /* decimal32FromNumber */
185
186 /* ------------------------------------------------------------------ */
187 /* decimal32ToNumber -- convert decimal32 to decNumber                */
188 /*   d32 is the source decimal32                                      */
189 /*   dn is the target number, with appropriate space                  */
190 /* No error is possible.                                              */
191 /* ------------------------------------------------------------------ */
192 decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) {
193   uInt msd;                        /* coefficient MSD */
194   uInt exp;                        /* exponent top two bits */
195   uInt comb;                       /* combination field */
196   uInt sour;                       /* source 32-bit */
197   const uInt *pu;                  /* work */
198
199   /* load source from storage; this is endian */
200   pu=(const uInt *)d32->bytes;     /* overlay */
201   sour=*pu;                        /* directly load the int */
202
203   comb=(sour>>26)&0x1f;            /* combination field */
204
205   decNumberZero(dn);               /* clean number */
206   if (sour&0x80000000) dn->bits=DECNEG; /* set sign if negative */
207
208   msd=COMBMSD[comb];               /* decode the combination field */
209   exp=COMBEXP[comb];               /* .. */
210
211   if (exp==3) {                    /* is a special */
212     if (msd==0) {
213       dn->bits|=DECINF;
214       return dn;                   /* no coefficient needed */
215       }
216     else if (sour&0x02000000) dn->bits|=DECSNAN;
217     else dn->bits|=DECNAN;
218     msd=0;                         /* no top digit */
219     }
220    else {                          /* is a finite number */
221     dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
222     }
223
224   /* get the coefficient */
225   sour&=0x000fffff;                /* clean coefficient continuation */
226   if (msd) {                       /* non-zero msd */
227     sour|=msd<<20;                 /* prefix to coefficient */
228     decDigitsFromDPD(dn, &sour, 3); /* process 3 declets */
229     return dn;
230     }
231   /* msd=0 */
232   if (!sour) return dn;            /* easy: coefficient is 0 */
233   if (sour&0x000ffc00)             /* need 2 declets? */
234     decDigitsFromDPD(dn, &sour, 2); /* process 2 declets */
235    else
236     decDigitsFromDPD(dn, &sour, 1); /* process 1 declet */
237   return dn;
238   } /* decimal32ToNumber */
239
240 /* ------------------------------------------------------------------ */
241 /* to-scientific-string -- conversion to numeric string               */
242 /* to-engineering-string -- conversion to numeric string              */
243 /*                                                                    */
244 /*   decimal32ToString(d32, string);                                  */
245 /*   decimal32ToEngString(d32, string);                               */
246 /*                                                                    */
247 /*  d32 is the decimal32 format number to convert                     */
248 /*  string is the string where the result will be laid out            */
249 /*                                                                    */
250 /*  string must be at least 24 characters                             */
251 /*                                                                    */
252 /*  No error is possible, and no status can be set.                   */
253 /* ------------------------------------------------------------------ */
254 char * decimal32ToEngString(const decimal32 *d32, char *string){
255   decNumber dn;                         /* work */
256   decimal32ToNumber(d32, &dn);
257   decNumberToEngString(&dn, string);
258   return string;
259   } /* decimal32ToEngString */
260
261 char * decimal32ToString(const decimal32 *d32, char *string){
262   uInt msd;                        /* coefficient MSD */
263   Int  exp;                        /* exponent top two bits or full */
264   uInt comb;                       /* combination field */
265   char *cstart;                    /* coefficient start */
266   char *c;                         /* output pointer in string */
267   const uInt *pu;                  /* work */
268   const uByte *u;                  /* .. */
269   char *s, *t;                     /* .. (source, target) */
270   Int  dpd;                        /* .. */
271   Int  pre, e;                     /* .. */
272   uInt sour;                       /* source 32-bit */
273
274   /* load source from storage; this is endian */
275   pu=(const uInt *)d32->bytes;     /* overlay */
276   sour=*pu;                        /* directly load the int */
277
278   c=string;                        /* where result will go */
279   if (((Int)sour)<0) *c++='-';     /* handle sign */
280
281   comb=(sour>>26)&0x1f;            /* combination field */
282   msd=COMBMSD[comb];               /* decode the combination field */
283   exp=COMBEXP[comb];               /* .. */
284
285   if (exp==3) {
286     if (msd==0) {                  /* infinity */
287       strcpy(c,   "Inf");
288       strcpy(c+3, "inity");
289       return string;               /* easy */
290       }
291     if (sour&0x02000000) *c++='s'; /* sNaN */
292     strcpy(c, "NaN");              /* complete word */
293     c+=3;                          /* step past */
294     if ((sour&0x000fffff)==0) return string; /* zero payload */
295     /* otherwise drop through to add integer; set correct exp */
296     exp=0; msd=0;                  /* setup for following code */
297     }
298    else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
299
300   /* convert 7 digits of significand to characters */
301   cstart=c;                        /* save start of coefficient */
302   if (msd) *c++='0'+(char)msd;     /* non-zero most significant digit */
303
304   /* Now decode the declets.  After extracting each one, it is */
305   /* decoded to binary and then to a 4-char sequence by table lookup; */
306   /* the 4-chars are a 1-char length (significant digits, except 000 */
307   /* has length 0).  This allows us to left-align the first declet */
308   /* with non-zero content, then remaining ones are full 3-char */
309   /* length.  We use fixed-length memcpys because variable-length */
310   /* causes a subroutine call in GCC.  (These are length 4 for speed */
311   /* and are safe because the array has an extra terminator byte.) */
312   #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4];                   \
313                    if (c!=cstart) {memcpy(c, u+1, 4); c+=3;}      \
314                     else if (*u)  {memcpy(c, u+4-*u, 4); c+=*u;}
315
316   dpd=(sour>>10)&0x3ff;            /* declet 1 */
317   dpd2char;
318   dpd=(sour)&0x3ff;                /* declet 2 */
319   dpd2char;
320
321   if (c==cstart) *c++='0';         /* all zeros -- make 0 */
322
323   if (exp==0) {                    /* integer or NaN case -- easy */
324     *c='\0';                       /* terminate */
325     return string;
326     }
327
328   /* non-0 exponent */
329   e=0;                             /* assume no E */
330   pre=c-cstart+exp;
331   /* [here, pre-exp is the digits count (==1 for zero)] */
332   if (exp>0 || pre<-5) {           /* need exponential form */
333     e=pre-1;                       /* calculate E value */
334     pre=1;                         /* assume one digit before '.' */
335     } /* exponential form */
336
337   /* modify the coefficient, adding 0s, '.', and E+nn as needed */
338   s=c-1;                           /* source (LSD) */
339   if (pre>0) {                     /* ddd.ddd (plain), perhaps with E */
340     char *dotat=cstart+pre;
341     if (dotat<c) {                 /* if embedded dot needed... */
342       t=c;                              /* target */
343       for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
344       *t='.';                           /* insert the dot */
345       c++;                              /* length increased by one */
346       }
347
348     /* finally add the E-part, if needed; it will never be 0, and has */
349     /* a maximum length of 3 digits (E-101 case) */
350     if (e!=0) {
351       *c++='E';                    /* starts with E */
352       *c++='+';                    /* assume positive */
353       if (e<0) {
354         *(c-1)='-';                /* oops, need '-' */
355         e=-e;                      /* uInt, please */
356         }
357       u=&BIN2CHAR[e*4];            /* -> length byte */
358       memcpy(c, u+4-*u, 4);        /* copy fixed 4 characters [is safe] */
359       c+=*u;                       /* bump pointer appropriately */
360       }
361     *c='\0';                       /* add terminator */
362     /*printf("res %s\n", string); */
363     return string;
364     } /* pre>0 */
365
366   /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
367   t=c+1-pre;
368   *(t+1)='\0';                          /* can add terminator now */
369   for (; s>=cstart; s--, t--) *t=*s;    /* shift whole coefficient right */
370   c=cstart;
371   *c++='0';                             /* always starts with 0. */
372   *c++='.';
373   for (; pre<0; pre++) *c++='0';        /* add any 0's after '.' */
374   /*printf("res %s\n", string); */
375   return string;
376   } /* decimal32ToString */
377
378 /* ------------------------------------------------------------------ */
379 /* to-number -- conversion from numeric string                        */
380 /*                                                                    */
381 /*   decimal32FromString(result, string, set);                        */
382 /*                                                                    */
383 /*  result  is the decimal32 format number which gets the result of   */
384 /*          the conversion                                            */
385 /*  *string is the character string which should contain a valid      */
386 /*          number (which may be a special value)                     */
387 /*  set     is the context                                            */
388 /*                                                                    */
389 /* The context is supplied to this routine is used for error handling */
390 /* (setting of status and traps) and for the rounding mode, only.     */
391 /* If an error occurs, the result will be a valid decimal32 NaN.      */
392 /* ------------------------------------------------------------------ */
393 decimal32 * decimal32FromString(decimal32 *result, const char *string,
394                                 decContext *set) {
395   decContext dc;                             /* work */
396   decNumber dn;                              /* .. */
397
398   decContextDefault(&dc, DEC_INIT_DECIMAL32); /* no traps, please */
399   dc.round=set->round;                        /* use supplied rounding */
400
401   decNumberFromString(&dn, string, &dc);     /* will round if needed */
402   decimal32FromNumber(result, &dn, &dc);
403   if (dc.status!=0) {                        /* something happened */
404     decContextSetStatus(set, dc.status);     /* .. pass it on */
405     }
406   return result;
407   } /* decimal32FromString */
408
409 /* ------------------------------------------------------------------ */
410 /* decimal32IsCanonical -- test whether encoding is canonical         */
411 /*   d32 is the source decimal32                                      */
412 /*   returns 1 if the encoding of d32 is canonical, 0 otherwise       */
413 /* No error is possible.                                              */
414 /* ------------------------------------------------------------------ */
415 uint32_t decimal32IsCanonical(const decimal32 *d32) {
416   decNumber dn;                         /* work */
417   decimal32 canon;                      /* .. */
418   decContext dc;                        /* .. */
419   decContextDefault(&dc, DEC_INIT_DECIMAL32);
420   decimal32ToNumber(d32, &dn);
421   decimal32FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
422   return memcmp(d32, &canon, DECIMAL32_Bytes)==0;
423   } /* decimal32IsCanonical */
424
425 /* ------------------------------------------------------------------ */
426 /* decimal32Canonical -- copy an encoding, ensuring it is canonical   */
427 /*   d32 is the source decimal32                                      */
428 /*   result is the target (may be the same decimal32)                 */
429 /*   returns result                                                   */
430 /* No error is possible.                                              */
431 /* ------------------------------------------------------------------ */
432 decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) {
433   decNumber dn;                         /* work */
434   decContext dc;                        /* .. */
435   decContextDefault(&dc, DEC_INIT_DECIMAL32);
436   decimal32ToNumber(d32, &dn);
437   decimal32FromNumber(result, &dn, &dc);/* result will now be canonical */
438   return result;
439   } /* decimal32Canonical */
440
441 #if DECTRACE || DECCHECK
442 /* Macros for accessing decimal32 fields.  These assume the argument
443    is a reference (pointer) to the decimal32 structure, and the
444    decimal32 is in network byte order (big-endian) */
445 /* Get sign */
446 #define decimal32Sign(d)       ((unsigned)(d)->bytes[0]>>7)
447
448 /* Get combination field */
449 #define decimal32Comb(d)       (((d)->bytes[0] & 0x7c)>>2)
450
451 /* Get exponent continuation [does not remove bias] */
452 #define decimal32ExpCon(d)     ((((d)->bytes[0] & 0x03)<<4)           \
453                              | ((unsigned)(d)->bytes[1]>>4))
454
455 /* Set sign [this assumes sign previously 0] */
456 #define decimal32SetSign(d, b) {                                      \
457   (d)->bytes[0]|=((unsigned)(b)<<7);}
458
459 /* Set exponent continuation [does not apply bias] */
460 /* This assumes range has been checked and exponent previously 0; */
461 /* type of exponent must be unsigned */
462 #define decimal32SetExpCon(d, e) {                                    \
463   (d)->bytes[0]|=(uint8_t)((e)>>4);                                   \
464   (d)->bytes[1]|=(uint8_t)(((e)&0x0F)<<4);}
465
466 /* ------------------------------------------------------------------ */
467 /* decimal32Show -- display a decimal32 in hexadecimal [debug aid]    */
468 /*   d32 -- the number to show                                        */
469 /* ------------------------------------------------------------------ */
470 /* Also shows sign/cob/expconfields extracted - valid bigendian only */
471 void decimal32Show(const decimal32 *d32) {
472   char buf[DECIMAL32_Bytes*2+1];
473   Int i, j=0;
474
475   if (DECLITEND) {
476     for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
477       sprintf(&buf[j], "%02x", d32->bytes[3-i]);
478       }
479     printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
480            d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f,
481            ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4));
482     }
483    else {
484     for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
485       sprintf(&buf[j], "%02x", d32->bytes[i]);
486       }
487     printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
488            decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32));
489     }
490   } /* decimal32Show */
491 #endif