OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [libdecnumber/] [dpd/] [decimal32.c] - Blame information for rev 26

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 jlechner
/* 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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.