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