summaryrefslogtreecommitdiff
path: root/libdecnumber/dpd/decimal32.c
diff options
context:
space:
mode:
authorjanis <janis@138bc75d-0d04-0410-961f-82ee72b054a4>2007-09-10 20:44:08 +0000
committerjanis <janis@138bc75d-0d04-0410-961f-82ee72b054a4>2007-09-10 20:44:08 +0000
commitc8ac5d9a0464767d7091606c4d55aaaf8edc511a (patch)
treedc346951fedce72b616d1e6c4be76685c2e68c3a /libdecnumber/dpd/decimal32.c
parenta7835ede2329ad200c076f75edf493a4cb35e239 (diff)
downloadgcc-c8ac5d9a0464767d7091606c4d55aaaf8edc511a.tar.gz
2007-09-10 Janis Johnson <janis187@us.ibm.com>
Ben Elliston <bje@au.ibm.com> libdecnumber/ * Makefile.in (libdecnumber_a_OBJS): Remove decUtility.o (dependencies): Add Symbols headers. * decContext.c: Upgrade to decNumber 3.53. * decContext.h: Ditto. * decDPD.h: Ditto. * decNumber.c: Ditto. * decNumber.h: Ditto. * decNumberLocal.h: Ditto. * decBasic.c: New file from decNumber 3.53. * decCommon.c: Ditto. * decDouble.c: Ditto. * decDouble.h: Ditto. * decQuad.c: Ditto. * decQuad.h: Ditto. * decSingle.c: Ditto. * decSingle.h: Ditto. * decPacked.c: Ditto. * decPacked.h: Ditto. * dpd/decimal128.c: Upgrade to decNumber 3.53. * dpd/decimal128.h: Ditto. * dpd/decimal32.c: Ditto. * dpd/decimal32.h: Ditto. * dpd/decimal64.c: Ditto. * dpd/decimal64.h: Ditto. * decLibrary.c (__dec_byte_swap): Remove. * decContextSymbols.h: New file. * decDoubleSymbols.h: New file. * decNumberSymbols.h: New file. * decPackedSymbols.h: New file. * decQuadSymbols.h: New file. * decSingleSymbols.h: New file. * decUtility.c: Delete file. * decUtility.h: Delete file. * bid/decimal128Symbols.h: New file. * bid/decimal128Local.h: New file. * bid/decimal32Symbols.h: New file. * bid/decimal64Symbols.h: New file. * bid/host-ieee128.c (__swap128): Remove. (__host_to_ieee_128, __ieee_to_host_128): Don't handle endianness. * bid/host-ieee32.c (__dec_type_swap): Remove. (__host_to_ieee_32, __ieee_to_host_32): Don't handle endianness. * bid/host-ieee64.c (__swap64): Remove. (__host_to_ieee_64, __ieee_to_host_64): Don't handle endianness. * dpd/decimal32Symbols.h: New file. * dpd/decimal64Symbols.h: New file. * dpd/decimal128Symbols.h: New file. * dpd/decimal128Local.h: New file. libgcc/ * Makefile.in (dfp-filenames): Remove decUtility, add decDouble, decPacked, decQuad, decSingle. gcc/ * dfp.c: Include decimal128Local.h; (dfp_byte_swap): Remove. (encode_decimal32, decode_decimal32): Don't handle endianness. (encode_decimal64, decode_decimal64): Ditto. (encode_decimal128, decode_decimal128): Ditto. * config/dfp-bit.c (host_to_ieee32, ieee_to_host_32): Ditto. (__swap64): Remove. (host_to_ieee_64, ieee_to_host_64): Don't handle endianness. (__swap128): Remove (host_to_ieee_128, ieee_to_host_128): Don't handle endianness. * Makefile.in (DECNUM_H): Add decimal128Local.h. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128350 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libdecnumber/dpd/decimal32.c')
-rw-r--r--libdecnumber/dpd/decimal32.c656
1 files changed, 407 insertions, 249 deletions
diff --git a/libdecnumber/dpd/decimal32.c b/libdecnumber/dpd/decimal32.c
index 86912864c9f..692c2f70ecb 100644
--- a/libdecnumber/dpd/decimal32.c
+++ b/libdecnumber/dpd/decimal32.c
@@ -1,5 +1,5 @@
-/* Decimal 32-bit format module for the decNumber C Library
- Copyright (C) 2005 Free Software Foundation, Inc.
+/* Decimal 32-bit format module for the decNumber C Library.
+ Copyright (C) 2005, 2007 Free Software Foundation, Inc.
Contributed by IBM Corporation. Author Mike Cowlishaw.
This file is part of GCC.
@@ -29,26 +29,41 @@
02110-1301, USA. */
/* ------------------------------------------------------------------ */
+/* Decimal 32-bit format module */
+/* ------------------------------------------------------------------ */
/* This module comprises the routines for decimal32 format numbers. */
-/* Conversions are supplied to and from decNumber and String. */
-/* */
-/* No arithmetic routines are included; decNumber provides these. */
-/* */
-/* Error handling is the same as decNumber (qv.). */
+/* Conversions are supplied to and from decNumber and String. */
+/* */
+/* This is used when decNumber provides operations, either for all */
+/* operations or as a proxy between decNumber and decSingle. */
+/* */
+/* Error handling is the same as decNumber (qv.). */
/* ------------------------------------------------------------------ */
-#include <string.h> /* [for memset/memcpy] */
-#include <stdio.h> /* [for printf] */
+#include <string.h> /* [for memset/memcpy] */
+#include <stdio.h> /* [for printf] */
+
+#include "config.h" /* GCC definitions */
+#define DECNUMDIGITS 7 /* make decNumbers with space for 7 */
+#include "decNumber.h" /* base number library */
+#include "decNumberLocal.h" /* decNumber local types, etc. */
+#include "decimal32.h" /* our primary include */
-#define DECNUMDIGITS 7 /* we need decNumbers with space for 7 */
-#include "config.h"
-#include "decNumber.h" /* base number library */
-#include "decNumberLocal.h" /* decNumber local types, etc. */
-#include "decimal32.h" /* our primary include */
-#include "decUtility.h" /* utility routines */
+/* Utility tables and routines [in decimal64.c] */
+/* DPD2BIN and the reverse are renamed to prevent link-time conflict */
+/* if decQuad is also built in the same executable */
+#define DPD2BIN DPD2BINx
+#define BIN2DPD BIN2DPDx
+extern const uInt COMBEXP[32], COMBMSD[32];
+extern const uShort DPD2BIN[1024];
+extern const uShort BIN2DPD[1000];
+extern const uByte BIN2CHAR[4001];
+
+extern void decDigitsToDPD(const decNumber *, uInt *, Int);
+extern void decDigitsFromDPD(decNumber *, const uInt *, Int);
#if DECTRACE || DECCHECK
-void decimal32Show (const decimal32 *); /* for debug */
-void decNumberShow (const decNumber *); /* .. */
+void decimal32Show(const decimal32 *); /* for debug */
+extern void decNumberShow(const decNumber *); /* .. */
#endif
/* Useful macro */
@@ -56,282 +71,425 @@ void decNumberShow (const decNumber *); /* .. */
#define DEC_clear(d) memset(d, 0, sizeof(*d))
/* ------------------------------------------------------------------ */
-/* decimal32FromNumber -- convert decNumber to decimal32 */
-/* */
-/* ds is the target decimal32 */
-/* dn is the source number (assumed valid) */
-/* set is the context, used only for reporting errors */
-/* */
+/* decimal32FromNumber -- convert decNumber to decimal32 */
+/* */
+/* ds is the target decimal32 */
+/* dn is the source number (assumed valid) */
+/* set is the context, used only for reporting errors */
+/* */
/* The set argument is used only for status reporting and for the */
/* rounding mode (used if the coefficient is more than DECIMAL32_Pmax */
-/* digits or an overflow is detected). If the exponent is out of the */
-/* valid range then Overflow or Underflow will be raised. */
-/* After Underflow a subnormal result is possible. */
-/* */
+/* digits or an overflow is detected). If the exponent is out of the */
+/* valid range then Overflow or Underflow will be raised. */
+/* After Underflow a subnormal result is possible. */
+/* */
/* DEC_Clamped is set if the number has to be 'folded down' to fit, */
/* by reducing its exponent and multiplying the coefficient by a */
/* power of ten, or if the exponent on a zero had to be clamped. */
/* ------------------------------------------------------------------ */
-decimal32 *
-decimal32FromNumber (decimal32 * d32, const decNumber * dn, decContext * set)
-{
- uInt status = 0; /* status accumulator */
- Int pad = 0; /* coefficient pad digits */
- decNumber dw; /* work */
- decContext dc; /* .. */
- uByte isneg = dn->bits & DECNEG; /* non-0 if original sign set */
- uInt comb, exp; /* work */
-
- /* If the number is finite, and has too many digits, or the exponent */
- /* could be out of range then we reduce the number under the */
- /* appropriate constraints */
- if (!(dn->bits & DECSPECIAL))
- { /* not a special value */
- Int ae = dn->exponent + dn->digits - 1; /* adjusted exponent */
- if (dn->digits > DECIMAL32_Pmax /* too many digits */
- || ae > DECIMAL32_Emax /* likely overflow */
- || ae < DECIMAL32_Emin)
- { /* likely underflow */
- decContextDefault (&dc, DEC_INIT_DECIMAL32); /* [no traps] */
- dc.round = set->round; /* use supplied rounding */
- decNumberPlus (&dw, dn, &dc); /* (round and check) */
- /* [this changes -0 to 0, but it will be restored below] */
- status |= dc.status; /* save status */
- dn = &dw; /* use the work number */
- }
- /* [this could have pushed number to Infinity or zero, so this */
- /* rounding must be done before we generate the decimal32] */
- }
+decimal32 * decimal32FromNumber(decimal32 *d32, const decNumber *dn,
+ decContext *set) {
+ uInt status=0; /* status accumulator */
+ Int ae; /* adjusted exponent */
+ decNumber dw; /* work */
+ decContext dc; /* .. */
+ uInt *pu; /* .. */
+ uInt comb, exp; /* .. */
+ uInt targ=0; /* target 32-bit */
+
+ /* If the number has too many digits, or the exponent could be */
+ /* out of range then reduce the number under the appropriate */
+ /* constraints. This could push the number to Infinity or zero, */
+ /* so this check and rounding must be done before generating the */
+ /* decimal32] */
+ ae=dn->exponent+dn->digits-1; /* [0 if special] */
+ if (dn->digits>DECIMAL32_Pmax /* too many digits */
+ || ae>DECIMAL32_Emax /* likely overflow */
+ || ae<DECIMAL32_Emin) { /* likely underflow */
+ decContextDefault(&dc, DEC_INIT_DECIMAL32); /* [no traps] */
+ dc.round=set->round; /* use supplied rounding */
+ decNumberPlus(&dw, dn, &dc); /* (round and check) */
+ /* [this changes -0 to 0, so enforce the sign...] */
+ dw.bits|=dn->bits&DECNEG;
+ status=dc.status; /* save status */
+ dn=&dw; /* use the work number */
+ } /* maybe out of range */
- DEC_clear (d32); /* clean the target */
- if (dn->bits & DECSPECIAL)
- { /* a special value */
- uByte top; /* work */
- if (dn->bits & DECINF)
- top = DECIMAL_Inf;
- else
- { /* sNaN or qNaN */
- if ((*dn->lsu != 0 || dn->digits > 1) /* non-zero coefficient */
- && (dn->digits < DECIMAL32_Pmax))
- { /* coefficient fits */
- decDensePackCoeff (dn, d32->bytes, sizeof (d32->bytes), 0);
- }
- if (dn->bits & DECNAN)
- top = DECIMAL_NaN;
- else
- top = DECIMAL_sNaN;
+ if (dn->bits&DECSPECIAL) { /* a special value */
+ if (dn->bits&DECINF) targ=DECIMAL_Inf<<24;
+ else { /* sNaN or qNaN */
+ if ((*dn->lsu!=0 || dn->digits>1) /* non-zero coefficient */
+ && (dn->digits<DECIMAL32_Pmax)) { /* coefficient fits */
+ decDigitsToDPD(dn, &targ, 0);
}
- d32->bytes[0] = top;
- }
- else if (decNumberIsZero (dn))
- { /* a zero */
+ if (dn->bits&DECNAN) targ|=DECIMAL_NaN<<24;
+ else targ|=DECIMAL_sNaN<<24;
+ } /* a NaN */
+ } /* special */
+
+ else { /* is finite */
+ if (decNumberIsZero(dn)) { /* is a zero */
/* set and clamp exponent */
- if (dn->exponent < -DECIMAL32_Bias)
- {
- exp = 0;
- status |= DEC_Clamped;
+ if (dn->exponent<-DECIMAL32_Bias) {
+ exp=0; /* low clamp */
+ status|=DEC_Clamped;
}
- else
- {
- exp = dn->exponent + DECIMAL32_Bias; /* bias exponent */
- if (exp > DECIMAL32_Ehigh)
- { /* top clamp */
- exp = DECIMAL32_Ehigh;
- status |= DEC_Clamped;
- }
+ else {
+ exp=dn->exponent+DECIMAL32_Bias; /* bias exponent */
+ if (exp>DECIMAL32_Ehigh) { /* top clamp */
+ exp=DECIMAL32_Ehigh;
+ status|=DEC_Clamped;
+ }
}
- comb = (exp >> 3) & 0x18; /* combination field */
- d32->bytes[0] = (uByte) (comb << 2);
- exp &= 0x3f; /* remaining exponent bits */
- decimal32SetExpCon (d32, exp);
- }
- else
- { /* non-zero finite number */
- uInt msd; /* work */
-
- /* we have a dn that fits, but it may need to be padded */
- exp = (uInt) (dn->exponent + DECIMAL32_Bias); /* bias exponent */
-
- if (exp > DECIMAL32_Ehigh)
- { /* fold-down case */
- pad = exp - DECIMAL32_Ehigh;
- exp = DECIMAL32_Ehigh; /* [to maximum] */
- status |= DEC_Clamped;
+ comb=(exp>>3) & 0x18; /* msd=0, exp top 2 bits .. */
+ }
+ else { /* non-zero finite number */
+ uInt msd; /* work */
+ Int pad=0; /* coefficient pad digits */
+
+ /* the dn is known to fit, but it may need to be padded */
+ exp=(uInt)(dn->exponent+DECIMAL32_Bias); /* bias exponent */
+ if (exp>DECIMAL32_Ehigh) { /* fold-down case */
+ pad=exp-DECIMAL32_Ehigh;
+ exp=DECIMAL32_Ehigh; /* [to maximum] */
+ status|=DEC_Clamped;
}
- decDensePackCoeff (dn, d32->bytes, sizeof (d32->bytes), pad);
+ /* fastpath common case */
+ if (DECDPUN==3 && pad==0) {
+ targ=BIN2DPD[dn->lsu[0]];
+ if (dn->digits>3) targ|=(uInt)(BIN2DPD[dn->lsu[1]])<<10;
+ msd=(dn->digits==7 ? dn->lsu[2] : 0);
+ }
+ else { /* general case */
+ decDigitsToDPD(dn, &targ, pad);
+ /* save and clear the top digit */
+ msd=targ>>20;
+ targ&=0x000fffff;
+ }
- /* save and clear the top digit */
- msd = ((unsigned) d32->bytes[1] >> 4);
- d32->bytes[1] &= 0x0f;
/* create the combination field */
- if (msd >= 8)
- comb = 0x18 | (msd & 0x01) | ((exp >> 5) & 0x06);
- else
- comb = (msd & 0x07) | ((exp >> 3) & 0x18);
- d32->bytes[0] = (uByte) (comb << 2);
- exp &= 0x3f; /* remaining exponent bits */
- decimal32SetExpCon (d32, exp);
- }
+ if (msd>=8) comb=0x18 | ((exp>>5) & 0x06) | (msd & 0x01);
+ else comb=((exp>>3) & 0x18) | msd;
+ }
+ targ|=comb<<26; /* add combination field .. */
+ targ|=(exp&0x3f)<<20; /* .. and exponent continuation */
+ } /* finite */
+
+ if (dn->bits&DECNEG) targ|=0x80000000; /* add sign bit */
- if (isneg)
- decimal32SetSign (d32, 1);
- if (status != 0)
- decContextSetStatus (set, status); /* pass on status */
+ /* now write to storage; this is endian */
+ pu=(uInt *)d32->bytes; /* overlay */
+ *pu=targ; /* directly store the int */
- /*decimal32Show(d32); */
+ if (status!=0) decContextSetStatus(set, status); /* pass on status */
+ /* decimal32Show(d32); */
return d32;
-}
+ } /* decimal32FromNumber */
/* ------------------------------------------------------------------ */
-/* decimal32ToNumber -- convert decimal32 to decNumber */
-/* d32 is the source decimal32 */
-/* dn is the target number, with appropriate space */
-/* No error is possible. */
+/* decimal32ToNumber -- convert decimal32 to decNumber */
+/* d32 is the source decimal32 */
+/* dn is the target number, with appropriate space */
+/* No error is possible. */
/* ------------------------------------------------------------------ */
-decNumber *
-decimal32ToNumber (const decimal32 * d32, decNumber * dn)
-{
- uInt msd; /* coefficient MSD */
- decimal32 wk; /* working copy, if needed */
- uInt top = d32->bytes[0] & 0x7f; /* top byte, less sign bit */
- decNumberZero (dn); /* clean target */
- /* set the sign if negative */
- if (decimal32Sign (d32))
- dn->bits = DECNEG;
-
- if (top >= 0x78)
- { /* is a special */
- if ((top & 0x7c) == (DECIMAL_Inf & 0x7c))
- dn->bits |= DECINF;
- else if ((top & 0x7e) == (DECIMAL_NaN & 0x7e))
- dn->bits |= DECNAN;
- else
- dn->bits |= DECSNAN;
- msd = 0; /* no top digit */
+decNumber * decimal32ToNumber(const decimal32 *d32, decNumber *dn) {
+ uInt msd; /* coefficient MSD */
+ uInt exp; /* exponent top two bits */
+ uInt comb; /* combination field */
+ uInt sour; /* source 32-bit */
+ const uInt *pu; /* work */
+
+ /* load source from storage; this is endian */
+ pu=(const uInt *)d32->bytes; /* overlay */
+ sour=*pu; /* directly load the int */
+
+ comb=(sour>>26)&0x1f; /* combination field */
+
+ decNumberZero(dn); /* clean number */
+ if (sour&0x80000000) dn->bits=DECNEG; /* set sign if negative */
+
+ msd=COMBMSD[comb]; /* decode the combination field */
+ exp=COMBEXP[comb]; /* .. */
+
+ if (exp==3) { /* is a special */
+ if (msd==0) {
+ dn->bits|=DECINF;
+ return dn; /* no coefficient needed */
+ }
+ else if (sour&0x02000000) dn->bits|=DECSNAN;
+ else dn->bits|=DECNAN;
+ msd=0; /* no top digit */
}
- else
- { /* have a finite number */
- uInt comb = top >> 2; /* combination field */
- uInt exp; /* working exponent */
-
- if (comb >= 0x18)
- {
- msd = 8 + (comb & 0x01);
- exp = (comb & 0x06) << 5; /* MSBs */
- }
- else
- {
- msd = comb & 0x07;
- exp = (comb & 0x18) << 3;
- }
- dn->exponent = exp + decimal32ExpCon (d32) - DECIMAL32_Bias; /* remove bias */
+ else { /* is a finite number */
+ dn->exponent=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
}
- /* get the coefficient, unless infinite */
- if (!(dn->bits & DECINF))
- {
- Int bunches = DECIMAL32_Pmax / 3; /* coefficient full bunches to convert */
- Int odd = 0; /* assume MSD is 0 (no odd bunch) */
- if (msd != 0)
- { /* coefficient has leading non-0 digit */
- /* make a copy of the decimal32, with an extra bunch which has */
- /* the top digit ready for conversion */
- wk = *d32; /* take a copy */
- wk.bytes[0] = 0; /* clear all but coecon */
- wk.bytes[1] &= 0x0f; /* .. */
- wk.bytes[1] |= (msd << 4); /* and prefix MSD */
- odd++; /* indicate the extra */
- d32 = &wk; /* use the work copy */
- }
- decDenseUnpackCoeff (d32->bytes, sizeof (d32->bytes), dn, bunches, odd);
+ /* get the coefficient */
+ sour&=0x000fffff; /* clean coefficient continuation */
+ if (msd) { /* non-zero msd */
+ sour|=msd<<20; /* prefix to coefficient */
+ decDigitsFromDPD(dn, &sour, 3); /* process 3 declets */
+ return dn;
}
+ /* msd=0 */
+ if (!sour) return dn; /* easy: coefficient is 0 */
+ if (sour&0x000ffc00) /* need 2 declets? */
+ decDigitsFromDPD(dn, &sour, 2); /* process 2 declets */
+ else
+ decDigitsFromDPD(dn, &sour, 1); /* process 1 declet */
return dn;
-}
+ } /* decimal32ToNumber */
/* ------------------------------------------------------------------ */
-/* to-scientific-string -- conversion to numeric string */
-/* to-engineering-string -- conversion to numeric string */
-/* */
-/* decimal32ToString(d32, string); */
-/* decimal32ToEngString(d32, string); */
-/* */
-/* d32 is the decimal32 format number to convert */
-/* string is the string where the result will be laid out */
-/* */
-/* string must be at least 24 characters */
-/* */
-/* No error is possible, and no status can be set. */
+/* to-scientific-string -- conversion to numeric string */
+/* to-engineering-string -- conversion to numeric string */
+/* */
+/* decimal32ToString(d32, string); */
+/* decimal32ToEngString(d32, string); */
+/* */
+/* d32 is the decimal32 format number to convert */
+/* string is the string where the result will be laid out */
+/* */
+/* string must be at least 24 characters */
+/* */
+/* No error is possible, and no status can be set. */
/* ------------------------------------------------------------------ */
-char *
-decimal32ToString (const decimal32 * d32, char *string)
-{
- decNumber dn; /* work */
- decimal32ToNumber (d32, &dn);
- decNumberToString (&dn, string);
+char * decimal32ToEngString(const decimal32 *d32, char *string){
+ decNumber dn; /* work */
+ decimal32ToNumber(d32, &dn);
+ decNumberToEngString(&dn, string);
return string;
-}
-
-char *
-decimal32ToEngString (const decimal32 * d32, char *string)
-{
- decNumber dn; /* work */
- decimal32ToNumber (d32, &dn);
- decNumberToEngString (&dn, string);
+ } /* decimal32ToEngString */
+
+char * decimal32ToString(const decimal32 *d32, char *string){
+ uInt msd; /* coefficient MSD */
+ Int exp; /* exponent top two bits or full */
+ uInt comb; /* combination field */
+ char *cstart; /* coefficient start */
+ char *c; /* output pointer in string */
+ const uInt *pu; /* work */
+ const uByte *u; /* .. */
+ char *s, *t; /* .. (source, target) */
+ Int dpd; /* .. */
+ Int pre, e; /* .. */
+ uInt sour; /* source 32-bit */
+
+ /* load source from storage; this is endian */
+ pu=(const uInt *)d32->bytes; /* overlay */
+ sour=*pu; /* directly load the int */
+
+ c=string; /* where result will go */
+ if (((Int)sour)<0) *c++='-'; /* handle sign */
+
+ comb=(sour>>26)&0x1f; /* combination field */
+ msd=COMBMSD[comb]; /* decode the combination field */
+ exp=COMBEXP[comb]; /* .. */
+
+ if (exp==3) {
+ if (msd==0) { /* infinity */
+ strcpy(c, "Inf");
+ strcpy(c+3, "inity");
+ return string; /* easy */
+ }
+ if (sour&0x02000000) *c++='s'; /* sNaN */
+ strcpy(c, "NaN"); /* complete word */
+ c+=3; /* step past */
+ if ((sour&0x000fffff)==0) return string; /* zero payload */
+ /* otherwise drop through to add integer; set correct exp */
+ exp=0; msd=0; /* setup for following code */
+ }
+ else exp=(exp<<6)+((sour>>20)&0x3f)-DECIMAL32_Bias; /* unbiased */
+
+ /* convert 7 digits of significand to characters */
+ cstart=c; /* save start of coefficient */
+ if (msd) *c++='0'+(char)msd; /* non-zero most significant digit */
+
+ /* Now decode the declets. After extracting each one, it is */
+ /* decoded to binary and then to a 4-char sequence by table lookup; */
+ /* the 4-chars are a 1-char length (significant digits, except 000 */
+ /* has length 0). This allows us to left-align the first declet */
+ /* with non-zero content, then remaining ones are full 3-char */
+ /* length. We use fixed-length memcpys because variable-length */
+ /* causes a subroutine call in GCC. (These are length 4 for speed */
+ /* and are safe because the array has an extra terminator byte.) */
+ #define dpd2char u=&BIN2CHAR[DPD2BIN[dpd]*4]; \
+ if (c!=cstart) {memcpy(c, u+1, 4); c+=3;} \
+ else if (*u) {memcpy(c, u+4-*u, 4); c+=*u;}
+
+ dpd=(sour>>10)&0x3ff; /* declet 1 */
+ dpd2char;
+ dpd=(sour)&0x3ff; /* declet 2 */
+ dpd2char;
+
+ if (c==cstart) *c++='0'; /* all zeros -- make 0 */
+
+ if (exp==0) { /* integer or NaN case -- easy */
+ *c='\0'; /* terminate */
+ return string;
+ }
+
+ /* non-0 exponent */
+ e=0; /* assume no E */
+ pre=c-cstart+exp;
+ /* [here, pre-exp is the digits count (==1 for zero)] */
+ if (exp>0 || pre<-5) { /* need exponential form */
+ e=pre-1; /* calculate E value */
+ pre=1; /* assume one digit before '.' */
+ } /* exponential form */
+
+ /* modify the coefficient, adding 0s, '.', and E+nn as needed */
+ s=c-1; /* source (LSD) */
+ if (pre>0) { /* ddd.ddd (plain), perhaps with E */
+ char *dotat=cstart+pre;
+ if (dotat<c) { /* if embedded dot needed... */
+ t=c; /* target */
+ for (; s>=dotat; s--, t--) *t=*s; /* open the gap; leave t at gap */
+ *t='.'; /* insert the dot */
+ c++; /* length increased by one */
+ }
+
+ /* finally add the E-part, if needed; it will never be 0, and has */
+ /* a maximum length of 3 digits (E-101 case) */
+ if (e!=0) {
+ *c++='E'; /* starts with E */
+ *c++='+'; /* assume positive */
+ if (e<0) {
+ *(c-1)='-'; /* oops, need '-' */
+ e=-e; /* uInt, please */
+ }
+ u=&BIN2CHAR[e*4]; /* -> length byte */
+ memcpy(c, u+4-*u, 4); /* copy fixed 4 characters [is safe] */
+ c+=*u; /* bump pointer appropriately */
+ }
+ *c='\0'; /* add terminator */
+ /*printf("res %s\n", string); */
+ return string;
+ } /* pre>0 */
+
+ /* -5<=pre<=0: here for plain 0.ddd or 0.000ddd forms (can never have E) */
+ t=c+1-pre;
+ *(t+1)='\0'; /* can add terminator now */
+ for (; s>=cstart; s--, t--) *t=*s; /* shift whole coefficient right */
+ c=cstart;
+ *c++='0'; /* always starts with 0. */
+ *c++='.';
+ for (; pre<0; pre++) *c++='0'; /* add any 0's after '.' */
+ /*printf("res %s\n", string); */
return string;
-}
+ } /* decimal32ToString */
/* ------------------------------------------------------------------ */
-/* to-number -- conversion from numeric string */
-/* */
-/* decimal32FromString(result, string, set); */
-/* */
+/* to-number -- conversion from numeric string */
+/* */
+/* decimal32FromString(result, string, set); */
+/* */
/* result is the decimal32 format number which gets the result of */
-/* the conversion */
+/* the conversion */
/* *string is the character string which should contain a valid */
-/* number (which may be a special value) */
-/* set is the context */
-/* */
+/* number (which may be a special value) */
+/* set is the context */
+/* */
/* The context is supplied to this routine is used for error handling */
/* (setting of status and traps) and for the rounding mode, only. */
/* If an error occurs, the result will be a valid decimal32 NaN. */
/* ------------------------------------------------------------------ */
-decimal32 *
-decimal32FromString (decimal32 * result, const char *string, decContext * set)
-{
- decContext dc; /* work */
- decNumber dn; /* .. */
-
- decContextDefault (&dc, DEC_INIT_DECIMAL32); /* no traps, please */
- dc.round = set->round; /* use supplied rounding */
-
- decNumberFromString (&dn, string, &dc); /* will round if needed */
- decimal32FromNumber (result, &dn, &dc);
- if (dc.status != 0)
- { /* something happened */
- decContextSetStatus (set, dc.status); /* .. pass it on */
+decimal32 * decimal32FromString(decimal32 *result, const char *string,
+ decContext *set) {
+ decContext dc; /* work */
+ decNumber dn; /* .. */
+
+ decContextDefault(&dc, DEC_INIT_DECIMAL32); /* no traps, please */
+ dc.round=set->round; /* use supplied rounding */
+
+ decNumberFromString(&dn, string, &dc); /* will round if needed */
+ decimal32FromNumber(result, &dn, &dc);
+ if (dc.status!=0) { /* something happened */
+ decContextSetStatus(set, dc.status); /* .. pass it on */
}
return result;
-}
+ } /* decimal32FromString */
+
+/* ------------------------------------------------------------------ */
+/* decimal32IsCanonical -- test whether encoding is canonical */
+/* d32 is the source decimal32 */
+/* returns 1 if the encoding of d32 is canonical, 0 otherwise */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+uint32_t decimal32IsCanonical(const decimal32 *d32) {
+ decNumber dn; /* work */
+ decimal32 canon; /* .. */
+ decContext dc; /* .. */
+ decContextDefault(&dc, DEC_INIT_DECIMAL32);
+ decimal32ToNumber(d32, &dn);
+ decimal32FromNumber(&canon, &dn, &dc);/* canon will now be canonical */
+ return memcmp(d32, &canon, DECIMAL32_Bytes)==0;
+ } /* decimal32IsCanonical */
+
+/* ------------------------------------------------------------------ */
+/* decimal32Canonical -- copy an encoding, ensuring it is canonical */
+/* d32 is the source decimal32 */
+/* result is the target (may be the same decimal32) */
+/* returns result */
+/* No error is possible. */
+/* ------------------------------------------------------------------ */
+decimal32 * decimal32Canonical(decimal32 *result, const decimal32 *d32) {
+ decNumber dn; /* work */
+ decContext dc; /* .. */
+ decContextDefault(&dc, DEC_INIT_DECIMAL32);
+ decimal32ToNumber(d32, &dn);
+ decimal32FromNumber(result, &dn, &dc);/* result will now be canonical */
+ return result;
+ } /* decimal32Canonical */
#if DECTRACE || DECCHECK
+/* Macros for accessing decimal32 fields. These assume the argument
+ is a reference (pointer) to the decimal32 structure, and the
+ decimal32 is in network byte order (big-endian) */
+/* Get sign */
+#define decimal32Sign(d) ((unsigned)(d)->bytes[0]>>7)
+
+/* Get combination field */
+#define decimal32Comb(d) (((d)->bytes[0] & 0x7c)>>2)
+
+/* Get exponent continuation [does not remove bias] */
+#define decimal32ExpCon(d) ((((d)->bytes[0] & 0x03)<<4) \
+ | ((unsigned)(d)->bytes[1]>>4))
+
+/* Set sign [this assumes sign previously 0] */
+#define decimal32SetSign(d, b) { \
+ (d)->bytes[0]|=((unsigned)(b)<<7);}
+
+/* Set exponent continuation [does not apply bias] */
+/* This assumes range has been checked and exponent previously 0; */
+/* type of exponent must be unsigned */
+#define decimal32SetExpCon(d, e) { \
+ (d)->bytes[0]|=(uint8_t)((e)>>4); \
+ (d)->bytes[1]|=(uint8_t)(((e)&0x0F)<<4);}
+
/* ------------------------------------------------------------------ */
-/* decimal32Show -- display a single in hexadecimal [debug aid] */
-/* d32 -- the number to show */
+/* decimal32Show -- display a decimal32 in hexadecimal [debug aid] */
+/* d32 -- the number to show */
/* ------------------------------------------------------------------ */
-/* Also shows sign/cob/expconfields extracted */
-void
-decimal32Show (const decimal32 * d32)
-{
- char buf[DECIMAL32_Bytes * 2 + 1];
- Int i, j;
- j = 0;
- for (i = 0; i < DECIMAL32_Bytes; i++)
- {
- sprintf (&buf[j], "%02x", d32->bytes[i]);
- j = j + 2;
+/* Also shows sign/cob/expconfields extracted - valid bigendian only */
+void decimal32Show(const decimal32 *d32) {
+ char buf[DECIMAL32_Bytes*2+1];
+ Int i, j=0;
+
+ if (DECLITEND) {
+ for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
+ sprintf(&buf[j], "%02x", d32->bytes[3-i]);
+ }
+ printf(" D32> %s [S:%d Cb:%02x Ec:%02x] LittleEndian\n", buf,
+ d32->bytes[3]>>7, (d32->bytes[3]>>2)&0x1f,
+ ((d32->bytes[3]&0x3)<<4)| (d32->bytes[2]>>4));
+ }
+ else {
+ for (i=0; i<DECIMAL32_Bytes; i++, j+=2) {
+ sprintf(&buf[j], "%02x", d32->bytes[i]);
+ }
+ printf(" D32> %s [S:%d Cb:%02x Ec:%02x] BigEndian\n", buf,
+ decimal32Sign(d32), decimal32Comb(d32), decimal32ExpCon(d32));
}
- printf (" D32> %s [S:%d Cb:%02x E:%d]\n", buf,
- decimal32Sign (d32), decimal32Comb (d32), decimal32ExpCon (d32));
-}
+ } /* decimal32Show */
#endif