| decNumber package errata |
|
The current generally available release of the decNumber package is 3.61 (2008.07.09), since when two minor bugs, in the decNumberLogB and decNumberScaleB functions, have been reported and are listed below.
Some users may be using 3.56 (2007.10.12). Since then, two other minor bugs were reported. This page also details those problems and the fixes (which are included in 3.61). Only the decDoubleSubtract, decQuadSubtract, decDoubleQuantize, and decQuadQuantize functions are affected.
Please send any comments, questions, and corrections on these directly to me (Mike Cowlishaw, mfc@uk.ibm.com).
The arithmetic specification indicates that the result can be inexact if the precision set for decNumberLogB is insufficient, however the function required that the result would always have space for 10 digits and so never rounded.
To fix, change the comment lines:
/* C must have space for 10 digits (A might have 10**9 digits and */ /* an exponent of +999999999, or one digit and an exponent of */ /* -1999999999). */to
/* For an unrounded result, digits may need to be 10 (A might have */ /* 10**9 digits and an exponent of +999999999, or one digit and an */ /* exponent of -1999999999). */and change the line:
decNumberFromInt32(res, ae); // lay it out
to
if (set->digits>=10) decNumberFromInt32(res, ae); // lay it out
else {
decNumber buft[D2N(10)]; // temporary number
decNumber *t=buft; // ..
decNumberFromInt32(t, ae); // lay it out
decNumberPlus(res, t, set); // round as necessary
}
Many thanks to Stefan Krah for finding this one.
The exponent calculation in decNumberScaleB can overflow when the exponent of the first operand and the magnitude of the second both have at least nine digits (and the exponent range is similarly large), and in this case the result was not being reported as an Invalid operation (and an incorrect result was returned).
The fix is to replace the lines:
if (!decNumberIsInfinite(res)) { // prepare to scale
res->exponent+=reqexp; // adjust the exponent
residue=0;
decFinalize(res, set, &residue, &status); // .. and check
} // finite LHS
with:
if (!decNumberIsInfinite(res)) { // prepare to scale
Int exp=res->exponent; // save for overflow test
res->exponent+=reqexp; // adjust the exponent
if (((exp^reqexp)>=0) // same sign ...
&& ((exp^res->exponent)<0)) // .. but result had different
status=DEC_Invalid_operation; // overflow must be out of range
else {
residue=0;
decFinalize(res, set, &residue, &status); // final check
}
} // finite LHS
Many thanks to Stefan Krah for finding this one.
The ISCOEFFZERO macro (in decNumberLocal.h) incorrectly used UBTOUI twice in the same expression. This could cause a wrong result when optimized by a compiler that aggressively takes advantage of C99 strict aliasing rules (see Mike Acton’s page for an excellent explanation of this).
The fix is to either turn off strict aliasing optimizations, or to replace the macro (actually the three implementations of the macro) by the following:
/* Macro to test whether a full-length (length DECPMAX) BCD8 */
/* coefficient, starting at uByte u, is all zeros */
/* Test just the LSWord first, then the remainder as a sequence */
/* of tests in order to avoid same-level use of UBTOUI */
#if DECPMAX==7
#define ISCOEFFZERO(u) ( \
UBTOUI((u)+DECPMAX-4)==0 \
&& UBTOUS((u)+DECPMAX-6)==0 \
&& *(u)==0)
#elif DECPMAX==16
#define ISCOEFFZERO(u) ( \
UBTOUI((u)+DECPMAX-4)==0 \
&& UBTOUI((u)+DECPMAX-8)==0 \
&& UBTOUI((u)+DECPMAX-12)==0 \
&& UBTOUI(u)==0)
#elif DECPMAX==34
#define ISCOEFFZERO(u) ( \
UBTOUI((u)+DECPMAX-4)==0 \
&& UBTOUI((u)+DECPMAX-8)==0 \
&& UBTOUI((u)+DECPMAX-12)==0 \
&& UBTOUI((u)+DECPMAX-16)==0 \
&& UBTOUI((u)+DECPMAX-20)==0 \
&& UBTOUI((u)+DECPMAX-24)==0 \
&& UBTOUI((u)+DECPMAX-28)==0 \
&& UBTOUI((u)+DECPMAX-32)==0 \
&& UBTOUS(u)==0)
#endif
Many thanks to John Matzka for finding this one.
A buffer in decFloatQuantize (in decBasic.c) is two bytes too short when the coefficient of the first operand has to be extended with 33 zeros (this only affects decQuadQuantize).
The fix is to replace the line
uByte buf[4+DECPMAX*3]; // + space for zeros to left or rightwith
uByte buf[4+DECPMAX*3+2*QUAD]; // + space for zeros to left or rightMany thanks to Klaus Kretzschmar for finding this one.
|
Copyright © IBM Corporation 2008, 2009. All rights reserved.
|