decNumber package errata |
The generally available release of the decNumber package is 3.68 (2010.02.10).
As of early 2014 there are known to be errors in this release, of two general types:
In general
these involve edge-case rounding, special value results, and flag
setting (in power, add, subtract, fma, scaleb, quantize, next_plus,
next_minus, squareroot, remainder, and remainder_near).
Further, the rotate, shift, invert, and ln functions can give
unreliable results when given excess-precision operand(s) – the
ln function has been shown to enter an infinite loop.
Many thanks to Stefan Krah for finding these. Stefan has also
developed "beta quality" fixes for these issues, which are
available here.
The documentation indicates that these functions return 1 if the number being tested is signed; however they return DECFLOAT_Sign in this case.
To fix, change the lines in decBasic.c:
uInt decFloatIsSigned(const decFloat *df) { return DFISSIGNED(df); }to
uInt decFloatIsSigned(const decFloat *df) { return DFISSIGNED(df)!=0; }Many thanks to Matthew Hagerty for finding this one, and to Rahul Ruikar for re-reporting it.
The errata below document earlier fixes. These affected the decNumberLogB, decNumberScaleB, decDoubleIsSigned, and decQuadIsSigned functions, and are listed below. There is also a report of a suspected problem in a recent Solaris compiler.
Some users may be using the earlier 3.56 version (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 and later releases). Only the decDoubleSubtract, decQuadSubtract, decDoubleQuantize, and decQuadQuantize functions are affected.
A decNumber user has reported that Visual Studio 2010 (32 bit) has difficulty with compiling the decNumber source files. Here are his workarounds.
Please send any comments, questions, and corrections on these directly to me (Mike Cowlishaw, mfc@speleotrove.com).
When compiling decNumber Solaris/SPARC with Oracle Solaris Studio 12.2, problems have arisen with decimal division – basic calculations return incorrect results (3/3 != 1), and some just hang the thread (e.g., 9/3). The problems occur at optimisation levels −xO3 and −xO4, but not at −xO2. The package is also OK at all 3 optimisation levels on the previous compiler release tried, Sun Studio 11.
The problems seem to be related to endianess of generated code at the higher optimization levels. Many thanks to Simon Stone for this report.
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 in decNumber.c:
/* 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 also in decNumber.c change the line:
decNumberFromInt32(res, ae); // lay it outto
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 and range calculations 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 an Invalid operation was reported (instead of an Overflow or Underflow).
The fix is to replace the line in decNumber.c:
|| abs(reqexp)>(2*(set->digits+set->emax))) // .. or out of rangewith:
|| (abs(reqexp)+1)/2>(set->digits+set->emax)) // .. or out of rangeand also in decNumber.c the lines:
if (!decNumberIsInfinite(res)) { // prepare to scale res->exponent+=reqexp; // adjust the exponent residue=0; decFinalize(res, set, &residue, &status); // .. and check } // finite LHSwith:
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 // the calculation overflowed, so force right treatment if (exp<0) res->exponent=DEC_MIN_EMIN-DEC_MAX_DIGITS; else res->exponent=DEC_MAX_EMAX+1; } residue=0; decFinalize(res, set, &residue, &status); // final check } // finite LHSNote that fix above still applies limits (the range −1999999997 through +999999999) to rhs that are stricter than specified; the limits can be worked around by using the function more than once.
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) #endifMany 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 © Mike Cowlishaw 2008, 2014.
Parts Copyright © IBM Corporation 2008, 2009.
All rights reserved.
|