Detect overflows converting to long

The code is ugly, but the results are good.
No regressions in existing testsuite, needs a new entry.
This commit is contained in:
Larry Doolittle 2009-03-11 09:14:36 -07:00 committed by Stephen Williams
parent ac4cb1bbe9
commit 932aa49b38
1 changed files with 26 additions and 15 deletions

View File

@ -419,6 +419,7 @@ uint64_t verinum::as_ulong64() const
*/ */
signed long verinum::as_long() const signed long verinum::as_long() const
{ {
#define IVLLBITS (8 * sizeof(long) - 1)
if (nbits_ == 0) if (nbits_ == 0)
return 0; return 0;
@ -426,33 +427,43 @@ signed long verinum::as_long() const
return 0; return 0;
signed long val = 0; signed long val = 0;
unsigned diag_top = 0;
unsigned top = nbits_;
if (top > IVLLBITS) {
diag_top = top;
top = IVLLBITS;
}
int lost_bits=0;
if (has_sign_ && (bits_[nbits_-1] == V1)) { if (has_sign_ && (bits_[nbits_-1] == V1)) {
unsigned top = nbits_;
if (top > (8 * sizeof(long) - 1))
top = 8 * sizeof(long) - 1;
val = -1; val = -1;
signed long mask = ~1L; signed long mask = ~1L;
for (unsigned idx = 0 ; idx < top ; idx += 1) { for (unsigned idx = 0 ; idx < top ; idx += 1) {
if (bits_[idx] == V0) if (bits_[idx] == V0) val &= mask;
val &= mask;
mask = (mask << 1) | 1L; mask = (mask << 1) | 1L;
} }
if (diag_top) {
for (unsigned idx = top; idx < diag_top; idx += 1) {
if (bits_[idx] == V0) lost_bits=1;
}
}
} else { } else {
unsigned top = nbits_;
if (top > (8 * sizeof(long) - 1))
top = 8 * sizeof(long) - 1;
signed long mask = 1; signed long mask = 1;
for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) for (unsigned idx = 0 ; idx < top ; idx += 1, mask <<= 1) {
if (bits_[idx] == V1) if (bits_[idx] == V1) val |= mask;
val |= mask; }
if (diag_top) {
for (unsigned idx = top; idx < diag_top; idx += 1) {
if (bits_[idx] == V1) lost_bits=1;
}
}
} }
if (lost_bits) cerr << "warning: verinum::as_long() truncated " <<
diag_top << " bits to " << IVLLBITS << ", returns " << val << endl;
return val; return val;
#undef IVLLBITS
} }
double verinum::as_double() const double verinum::as_double() const