summary refs log tree commit diff stats
path: root/libdecnumber/decNumber.c
diff options
context:
space:
mode:
authorTom Musta <tommusta@gmail.com>2014-04-21 15:54:54 -0500
committerAlexander Graf <agraf@suse.de>2014-06-16 13:24:29 +0200
commit79af3572250352c5eeacdd813b57ad5ba748654c (patch)
tree6131a6ba98cbbcfda6b7a7a9569e32642b0e66fd /libdecnumber/decNumber.c
parent8e706db21ecfba75da3f9f843f1fa36276085742 (diff)
downloadfocaccia-qemu-79af3572250352c5eeacdd813b57ad5ba748654c.tar.gz
focaccia-qemu-79af3572250352c5eeacdd813b57ad5ba748654c.zip
libdecnumber: Introduce decNumberIntegralToInt64
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>
Diffstat (limited to 'libdecnumber/decNumber.c')
-rw-r--r--libdecnumber/decNumber.c46
1 files changed, 45 insertions, 1 deletions
diff --git a/libdecnumber/decNumber.c b/libdecnumber/decNumber.c
index 6bd7565b34..6164a77509 100644
--- a/libdecnumber/decNumber.c
+++ b/libdecnumber/decNumber.c
@@ -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 */