diff options
author | Tom Musta | 2014-04-21 22:54:54 +0200 |
---|---|---|
committer | Alexander Graf | 2014-06-16 13:24:29 +0200 |
commit | 79af3572250352c5eeacdd813b57ad5ba748654c (patch) | |
tree | 6131a6ba98cbbcfda6b7a7a9569e32642b0e66fd /libdecnumber | |
parent | libdecnumber: Introduce decNumberFrom[U]Int64 (diff) | |
download | qemu-79af3572250352c5eeacdd813b57ad5ba748654c.tar.gz qemu-79af3572250352c5eeacdd813b57ad5ba748654c.tar.xz 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')
-rw-r--r-- | libdecnumber/decContext.c | 6 | ||||
-rw-r--r-- | libdecnumber/decNumber.c | 46 |
2 files changed, 49 insertions, 3 deletions
diff --git a/libdecnumber/decContext.c b/libdecnumber/decContext.c index 684710626d..8b6ae21be2 100644 --- a/libdecnumber/decContext.c +++ b/libdecnumber/decContext.c @@ -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 */ 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 */ |