summaryrefslogtreecommitdiff
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)
downloadqemu-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 */