]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
libdecnumber: Introduce decNumberIntegralToInt64
authorTom Musta <tommusta@gmail.com>
Mon, 21 Apr 2014 20:54:54 +0000 (15:54 -0500)
committerAlexander Graf <agraf@suse.de>
Mon, 16 Jun 2014 11:24:29 +0000 (13:24 +0200)
Introduce a new conversion function to the libdecnumber library.
This function converts a decNumber to a signed 64-bit integer.
In order to support 64-bit integers (which may have up to 19
decimal digits), the existing "powers of 10" array is expanded
from 10 to 19 entries.

Signed-off-by: Tom Musta <tommusta@gmail.com>
[agraf: fix 32bit host compile]
Signed-off-by: Alexander Graf <agraf@suse.de>
include/libdecnumber/decNumber.h
include/libdecnumber/decNumberLocal.h
libdecnumber/decContext.c
libdecnumber/decNumber.c

index f4bf99417cdc2f738a66379f759acf6899959326..9fa4e6a0c9ba9dc9083fc3daef82f3dd03870955 100644 (file)
   char     * decNumberToEngString(const decNumber *, char *);
   uint32_t    decNumberToUInt32(const decNumber *, decContext *);
   int32_t     decNumberToInt32(const decNumber *, decContext *);
+  int64_t     decNumberIntegralToInt64(const decNumber *dn, decContext *set);
   uint8_t   * decNumberGetBCD(const decNumber *, uint8_t *);
   decNumber * decNumberSetBCD(decNumber *, const uint8_t *, uint32_t);
 
index f5f508f2944014f1d15a3186d3bfa9791aa91d0b..cd4eb79e80d2668392fd9b273de0124401a526c0 100644 (file)
@@ -98,7 +98,7 @@
 
   /* Shared lookup tables                                            */
   extern const uByte  DECSTICKYTAB[10]; /* re-round digits if sticky  */
-  extern const uInt   DECPOWERS[10];   /* powers of ten table        */
+  extern const uLong  DECPOWERS[19];    /* powers of ten table        */
   /* The following are included from decDPD.h                        */
   extern const uShort DPD2BIN[1024];   /* DPD -> 0-999               */
   extern const uShort BIN2DPD[1000];   /* 0-999 -> DPD               */
index 684710626d034d300cc416fc68132588382ed364..8b6ae21be217e2e40a249c1fafd60e735bd8ec4c 100644 (file)
@@ -56,8 +56,10 @@ const uByte DECSTICKYTAB[10]={1,1,2,3,4,6,6,7,8,9}; /* used if sticky */
 /* ------------------------------------------------------------------ */
 /* Powers of ten (powers[n]==10**n, 0<=n<=9)                         */
 /* ------------------------------------------------------------------ */
-const uInt DECPOWERS[10]={1, 10, 100, 1000, 10000, 100000, 1000000,
-                         10000000, 100000000, 1000000000};
+const uLong DECPOWERS[19] = {1, 10, 100, 1000, 10000, 100000, 1000000,
+  10000000, 100000000, 1000000000, 10000000000ULL, 100000000000ULL,
+  1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
+  10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, };
 
 /* ------------------------------------------------------------------ */
 /* decContextClearStatus -- clear bits in current status             */
index 6bd7565b34d99c8f36181d89052d4f2645951193..6164a775092fde4ecabf66e3d3e50b2642063691 100644 (file)
@@ -465,6 +465,50 @@ decNumber *decNumberFromUInt64(decNumber *dn, uint64_t uin)
     return dn;
 } /* decNumberFromUInt64 */
 
+/* ------------------------------------------------------------------ */
+/* to-int64 -- conversion to int64                                    */
+/*                                                                    */
+/*  dn is the decNumber to convert.  dn is assumed to have been       */
+/*    rounded to a floating point integer value.                      */
+/*  set is the context for reporting errors                           */
+/*  returns the converted decNumber, or 0 if Invalid is set           */
+/*                                                                    */
+/* Invalid is set if the decNumber is a NaN, Infinite or is out of    */
+/* range for a signed 64 bit integer.                                 */
+/* ------------------------------------------------------------------ */
+
+int64_t decNumberIntegralToInt64(const decNumber *dn, decContext *set)
+{
+    if (decNumberIsSpecial(dn) || (dn->exponent < 0) ||
+       (dn->digits + dn->exponent > 19)) {
+        goto Invalid;
+    } else {
+        int64_t d;        /* work */
+        const Unit *up;   /* .. */
+        uint64_t hi = 0;
+        up = dn->lsu;     /* -> lsu */
+
+        for (d = 1; d <= dn->digits; up++, d += DECDPUN) {
+            uint64_t prev = hi;
+            hi += *up * powers[d-1];
+            if ((hi < prev) || (hi > INT64_MAX)) {
+                goto Invalid;
+            }
+        }
+
+        uint64_t prev = hi;
+        hi *= (uint64_t)powers[dn->exponent];
+        if ((hi < prev) || (hi > INT64_MAX)) {
+            goto Invalid;
+        }
+        return (decNumberIsNegative(dn)) ? -((int64_t)hi) : (int64_t)hi;
+    }
+
+Invalid:
+    decContextSetStatus(set, DEC_Invalid_operation);
+    return 0;
+} /* decNumberIntegralToInt64 */
+
 
 /* ------------------------------------------------------------------ */
 /* to-scientific-string -- conversion to numeric string                      */
@@ -4259,7 +4303,7 @@ static decNumber * decDivideOp(decNumber *res,
   uByte bits;                     /* working sign */
   Unit *target;                   /* work */
   const Unit *source;             /* .. */
-  uInt const *pow;                /* .. */
+  uLong const *pow;                /* .. */
   Int  shift, cut;                /* .. */
   #if DECSUBSET
   Int  dropped;                   /* work */