From 2aed8b1bdf7c0dc11150a3b6943f1243444d82ef Mon Sep 17 00:00:00 2001 From: griffin Date: Sun, 16 Apr 2023 18:36:18 +0000 Subject: Fix bug-fa00fbbbabe - seq / lindex discrepancies Replace macros with static inline functions. Limit ArithSeries list size to LIST_MAX. This way, shimmering less likely to fail if it happens. Speed up UpdateStringOfArithSeries. Fixed issues around indexing into vary large lseq lists. --- generic/tclArithSeries.c | 118 ++++++++++++++++++++++++++++++++--------------- tests/lseq.test | 19 +++++--- 2 files changed, 95 insertions(+), 42 deletions(-) diff --git a/generic/tclArithSeries.c b/generic/tclArithSeries.c index 0232746..d6e7c84 100755 --- a/generic/tclArithSeries.c +++ b/generic/tclArithSeries.c @@ -13,25 +13,46 @@ #include "tclInt.h" #include "tclArithSeries.h" #include +#include /* -------------------------- ArithSeries object ---------------------------- */ -#define ArithSeriesRepPtr(arithSeriesObjPtr) \ - (ArithSeries *) ((arithSeriesObjPtr)->internalRep.twoPtrValue.ptr1) +static inline ArithSeries* ArithSeriesRepPtr(Tcl_Obj *arithSeriesObjPtr) +{ + return (ArithSeries *)arithSeriesObjPtr->internalRep.twoPtrValue.ptr1; +} -#define ArithSeriesIndexM(arithSeriesRepPtr, index) \ - ((arithSeriesRepPtr)->isDouble ? \ - (((ArithSeriesDbl*)(arithSeriesRepPtr))->start+((index) * ((ArithSeriesDbl*)(arithSeriesRepPtr))->step)) \ - : \ - ((arithSeriesRepPtr)->start+((index) * arithSeriesRepPtr->step))) +static inline double ArithSeriesIndexDbl( + ArithSeries *arithSeriesRepPtr, + Tcl_WideInt index) +{ + ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl*)arithSeriesRepPtr; + if (arithSeriesRepPtr->isDouble) { + return (dblRepPtr->start + ((index) * dblRepPtr->step)); + } else { + return (double)(arithSeriesRepPtr->start + (index * arithSeriesRepPtr->step)); + } +} -#define ArithSeriesGetInternalRep(objPtr, arithRepPtr) \ - do { \ - const Tcl_ObjInternalRep *irPtr; \ - irPtr = TclFetchInternalRep((objPtr), &tclArithSeriesType.objType); \ - (arithRepPtr) = irPtr ? (ArithSeries *)irPtr->twoPtrValue.ptr1 : NULL; \ - } while (0) +static inline Tcl_WideInt ArithSeriesIndexInt( + ArithSeries *arithSeriesRepPtr, + Tcl_WideInt index) +{ + ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl*)arithSeriesRepPtr; + if (arithSeriesRepPtr->isDouble) { + return (Tcl_WideInt)(dblRepPtr->start + ((index) * dblRepPtr->step)); + } else { + return (arithSeriesRepPtr->start + (index * arithSeriesRepPtr->step)); + } +} + +static inline ArithSeries *ArithSeriesGetInternalRep(Tcl_Obj *objPtr) +{ + const Tcl_ObjInternalRep *irPtr; + irPtr = TclFetchInternalRep((objPtr), &tclArithSeriesType.objType); + return irPtr ? (ArithSeries *)irPtr->twoPtrValue.ptr1 : NULL; +} /* @@ -354,7 +375,7 @@ TclNewArithSeriesObj( } } - if (TCL_MAJOR_VERSION < 9 && len > ListSizeT_MAX) { + if (TCL_MAJOR_VERSION < 9 && ((len > ListSizeT_MAX) || (len > LIST_MAX))) { Tcl_SetObjResult( interp, Tcl_NewStringObj("max length of a Tcl list exceeded", TCL_INDEX_NONE)); @@ -441,19 +462,13 @@ TclArithSeriesObjIndex( } arithSeriesRepPtr = ArithSeriesRepPtr(arithSeriesObj); if (index < 0 || (Tcl_Size)index >= arithSeriesRepPtr->len) { - if (interp) { - Tcl_SetObjResult(interp, - Tcl_ObjPrintf("index %" TCL_LL_MODIFIER "d is out of bounds 0 to %" - TCL_Z_MODIFIER "d", index, (arithSeriesRepPtr->len-1))); - Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); - } - return NULL; + return Tcl_NewObj(); } /* List[i] = Start + (Step * index) */ if (arithSeriesRepPtr->isDouble) { - return Tcl_NewDoubleObj(ArithSeriesIndexM(arithSeriesRepPtr, index)); + return Tcl_NewDoubleObj(ArithSeriesIndexDbl(arithSeriesRepPtr, index)); } else { - return Tcl_NewWideIntObj(ArithSeriesIndexM(arithSeriesRepPtr, index)); + return Tcl_NewWideIntObj(ArithSeriesIndexInt(arithSeriesRepPtr, index)); } } @@ -591,28 +606,46 @@ UpdateStringOfArithSeries(Tcl_Obj *arithSeriesObj) char *elem, *p; Tcl_Obj *elemObj; Tcl_Size i; - Tcl_WideInt length = 0; + Tcl_Size length = 0; size_t slen; /* * Pass 1: estimate space. */ - for (i = 0; i < arithSeriesRepPtr->len; i++) { - elemObj = TclArithSeriesObjIndex(NULL, arithSeriesObj, i); - elem = Tcl_GetStringFromObj(elemObj, &slen); - Tcl_DecrRefCount(elemObj); - slen += 1; /* + 1 is for the space or the nul-term */ - length += slen; + if (!arithSeriesRepPtr->isDouble) { + for (i = 0; i < arithSeriesRepPtr->len; i++) { + double d = ArithSeriesIndexDbl(arithSeriesRepPtr, i); + slen = d>0 ? log10(d)+1 : d<0 ? log10((0-d))+2 : 1; + length += slen; + } + } else { + for (i = 0; i < arithSeriesRepPtr->len; i++) { + double d = ArithSeriesIndexDbl(arithSeriesRepPtr, i); + char tmp[TCL_DOUBLE_SPACE+2]; + tmp[0] = 0; + Tcl_PrintDouble(NULL,d,tmp); + if ((length + strlen(tmp)) >= TCL_SIZE_SMAX) { + break; // + } + length += strlen(tmp); + } } + length += arithSeriesRepPtr->len; // Space for each separator /* * Pass 2: generate the string repr. */ p = Tcl_InitStringRep(arithSeriesObj, NULL, length); + if (p == NULL) { + Tcl_Panic("Unable to allocate string size %" TCL_Z_MODIFIER "u", length); + } for (i = 0; i < arithSeriesRepPtr->len; i++) { elemObj = TclArithSeriesObjIndex(NULL, arithSeriesObj, i); elem = Tcl_GetStringFromObj(elemObj, &slen); + if (((p - arithSeriesObj->bytes)+slen) > length) { + break; + } strcpy(p, elem); p[slen] = ' '; p += slen+1; @@ -685,7 +718,7 @@ TclArithSeriesObjCopy( Tcl_Obj *copyPtr; ArithSeries *arithSeriesRepPtr; - ArithSeriesGetInternalRep(arithSeriesObj, arithSeriesRepPtr); + arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj); if (NULL == arithSeriesRepPtr) { if (SetArithSeriesFromAny(interp, arithSeriesObj) != TCL_OK) { /* We know this is going to panic, but it's the message we want */ @@ -728,16 +761,29 @@ TclArithSeriesObjRange( ArithSeries *arithSeriesRepPtr; Tcl_Obj *startObj, *endObj, *stepObj; - ArithSeriesGetInternalRep(arithSeriesObj, arithSeriesRepPtr); + arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj); if (fromIdx == TCL_INDEX_NONE) { fromIdx = 0; } - if (fromIdx > toIdx) { + + if (fromIdx > toIdx || + (toIdx > arithSeriesRepPtr->len-1 && + fromIdx > arithSeriesRepPtr->len-1)) { Tcl_Obj *obj; TclNewObj(obj); return obj; } + + if (fromIdx < 0) { + fromIdx = 0; + } + if (toIdx < 0) { + toIdx = 0; + } + if (toIdx > arithSeriesRepPtr->len-1) { + toIdx = arithSeriesRepPtr->len-1; + } startObj = TclArithSeriesObjIndex(interp, arithSeriesObj, fromIdx); if (startObj == NULL) { @@ -778,7 +824,7 @@ TclArithSeriesObjRange( TclInvalidateStringRep(arithSeriesObj); if (arithSeriesRepPtr->isDouble) { - ArithSeriesDbl *arithSeriesDblRepPtr = (ArithSeriesDbl*)arithSeriesObj; + ArithSeriesDbl *arithSeriesDblRepPtr = (ArithSeriesDbl*)arithSeriesRepPtr; double start, end, step; Tcl_GetDoubleFromObj(NULL, startObj, &start); Tcl_GetDoubleFromObj(NULL, endObj, &end); @@ -852,7 +898,7 @@ TclArithSeriesGetElements( Tcl_Obj **objv; int i, objc; - ArithSeriesGetInternalRep(objPtr, arithSeriesRepPtr); + arithSeriesRepPtr = ArithSeriesGetInternalRep(objPtr); objc = arithSeriesRepPtr->len; if (objc > 0) { if (arithSeriesRepPtr->elements) { @@ -927,7 +973,7 @@ TclArithSeriesObjReverse( double dstart, dend, dstep; int isDouble; - ArithSeriesGetInternalRep(arithSeriesObj, arithSeriesRepPtr); + arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj); isDouble = arithSeriesRepPtr->isDouble; len = arithSeriesRepPtr->len; diff --git a/tests/lseq.test b/tests/lseq.test index 1dff72d..403715a 100644 --- a/tests/lseq.test +++ b/tests/lseq.test @@ -538,12 +538,12 @@ test lseq-4.8 {error case lrange} -body { } -returnCodes 1 \ -result {bad index "fred": must be integer?[+-]integer? or end?[+-]integer?} -test lseq-4.9 {error case lrange} -body { - set fred 7 - set ginger 8 - lrange [lseq 1 5] $fred $ginger -} -returnCodes 1 \ - -result {index 7 is out of bounds 0 to 4} +test lseq-4.9 {lrange empty/partial sets} -body { + foreach {fred ginger} {7 8 4 9 0 15 9 9 4 2} { + lappend res [lrange [lseq 1 5] $fred $ginger] + } + set res +} -result {{} 5 {1 2 3 4 5} {} {}} # Panic when using variable value? test lseq-4.10 {panic using variable index} { @@ -551,6 +551,13 @@ test lseq-4.10 {panic using variable index} { lindex [lseq 10] $i } {0} +test lseq-4.11 {bug lseq / lindex discrepancies} { + lindex [lseq 0x7fffffff] 0x80000000 +} {} + +test lseq-4.12 {bug lseq} { + llength [lseq 0x100000000] +} {4294967296} # cleanup ::tcltest::cleanupTests -- cgit v0.12 From da6df4addedb2a495440a76f50733ff7b968cffc Mon Sep 17 00:00:00 2001 From: griffin Date: Tue, 25 Apr 2023 00:36:30 +0000 Subject: Add fix inconsistent rounding (bug-e5f06285de). Compute and use the "precision" for sequences of doubles: determine the number of significant digits in the fractional part of the given arguments, and round the results to that limit. Fix copy bug in DupArithSeriesInternalRep. --- generic/tclArithSeries.c | 132 ++++++++++++++++++++++++++++++++++++----------- generic/tclArithSeries.h | 1 + generic/tclUtil.c | 1 - tests/lseq.test | 22 +++++++- 4 files changed, 124 insertions(+), 32 deletions(-) diff --git a/generic/tclArithSeries.c b/generic/tclArithSeries.c index be53f88..115f4b9 100755 --- a/generic/tclArithSeries.c +++ b/generic/tclArithSeries.c @@ -17,25 +17,42 @@ /* -------------------------- ArithSeries object ---------------------------- */ - -static inline ArithSeries* ArithSeriesRepPtr(Tcl_Obj *arithSeriesObjPtr) -{ - return (ArithSeries *)arithSeriesObjPtr->internalRep.twoPtrValue.ptr1; +/* + * Helper functions + * + * - ArithRound -- Round doubles to the number of significant fractional + * digits + * - ArithSeriesIndexDbl -- base list indexing operation for doubles + * - ArithSeriesIndexInt -- " " " " " integers + * - ArithSeriesGetInternalRep -- Return the internal rep from a Tcl_Obj + * - Precision -- determine the number of factional digits for the given + * double value + * - setPrecision -- Using the value in the given arithSeries, determine and + * set the percision in the arithSeries + */ +static inline double +ArithRound(double d, unsigned int n) { + double scalefactor = pow(10, n); + return round(d*scalefactor)/scalefactor; } -static inline double ArithSeriesIndexDbl( +static inline double +ArithSeriesIndexDbl( ArithSeries *arithSeriesRepPtr, Tcl_WideInt index) { ArithSeriesDbl *dblRepPtr = (ArithSeriesDbl*)arithSeriesRepPtr; if (arithSeriesRepPtr->isDouble) { - return (dblRepPtr->start + ((index) * dblRepPtr->step)); + double d = dblRepPtr->start + (index * dblRepPtr->step); + unsigned n = (dblRepPtr->precision > 0 ? dblRepPtr->precision : 0); + return ArithRound(d, n); } else { return (double)(arithSeriesRepPtr->start + (index * arithSeriesRepPtr->step)); } } -static inline Tcl_WideInt ArithSeriesIndexInt( +static inline Tcl_WideInt +ArithSeriesIndexInt( ArithSeries *arithSeriesRepPtr, Tcl_WideInt index) { @@ -47,23 +64,44 @@ static inline Tcl_WideInt ArithSeriesIndexInt( } } -static inline ArithSeries *ArithSeriesGetInternalRep(Tcl_Obj *objPtr) +static inline ArithSeries* +ArithSeriesGetInternalRep(Tcl_Obj *objPtr) { const Tcl_ObjInternalRep *irPtr; irPtr = TclFetchInternalRep((objPtr), &tclArithSeriesType.objType); return irPtr ? (ArithSeries *)irPtr->twoPtrValue.ptr1 : NULL; } +static inline int +Precision(double d) +{ + char tmp[TCL_DOUBLE_SPACE+2], *off; + tmp[0] = 0; + Tcl_PrintDouble(NULL,d,tmp); + off = strchr(tmp, '.'); + return (off ? strlen(off+1) : 0); +} +static inline void +setPrecision(ArithSeriesDbl *arithSeriesRepPtr) +{ + // Find longest number of digits after the decimal point. + int dp = Precision(arithSeriesRepPtr->step); + int i = Precision(arithSeriesRepPtr->start); + dp = i>dp ? i : dp; + i = Precision(arithSeriesRepPtr->end); + dp = i>dp ? i : dp; + arithSeriesRepPtr->precision = dp; +} /* * Prototypes for procedures defined later in this file: */ -static void DupArithSeriesInternalRep (Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); -static void FreeArithSeriesInternalRep (Tcl_Obj *listPtr); -static int SetArithSeriesFromAny (Tcl_Interp *interp, Tcl_Obj *objPtr); -static void UpdateStringOfArithSeries (Tcl_Obj *arithSeriesObj); -static Tcl_Obj *ArithSeriesObjStep(Tcl_Obj *arithSeriesPtr); +static void DupArithSeriesInternalRep (Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); +static void FreeArithSeriesInternalRep (Tcl_Obj *listPtr); +static int SetArithSeriesFromAny (Tcl_Interp *interp, Tcl_Obj *objPtr); +static void UpdateStringOfArithSeries (Tcl_Obj *arithSeriesObj); +static Tcl_Obj* ArithSeriesObjStep(Tcl_Obj *arithSeriesPtr); static Tcl_Size ArithSeriesObjLength(Tcl_Obj *arithSeriesPtr); /* @@ -128,7 +166,7 @@ const TclObjTypeWithAbstractList tclArithSeriesType = { *---------------------------------------------------------------------- */ static Tcl_WideInt -ArithSeriesLen(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step) +ArithSeriesLenInt(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step) { Tcl_WideInt len; @@ -139,6 +177,18 @@ ArithSeriesLen(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step) return (len < 0) ? -1 : len; } +static Tcl_WideInt +ArithSeriesLenDbl(double start, double end, double step) +{ + Tcl_WideInt len; + + if (step == 0) { + return 0; + } + len = ((end-start+step)/step); + return (len < 0) ? -1 : len; +} + /* *---------------------------------------------------------------------- * @@ -161,10 +211,13 @@ static Tcl_Obj * NewArithSeriesInt(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step, Tcl_WideInt len) { - Tcl_WideInt length = (len>=0 ? len : ArithSeriesLen(start, end, step)); + Tcl_WideInt length; Tcl_Obj *arithSeriesObj; ArithSeries *arithSeriesRepPtr; + length = len>=0 ? len : (step == 0) ? 0 : ArithSeriesLenInt(start, end, step); + if (length < 0) length = -1; + TclNewObj(arithSeriesObj); if (length <= 0) { @@ -205,14 +258,20 @@ NewArithSeriesInt(Tcl_WideInt start, Tcl_WideInt end, Tcl_WideInt step, Tcl_Wide * None. *---------------------------------------------------------------------- */ + static Tcl_Obj * NewArithSeriesDbl(double start, double end, double step, Tcl_WideInt len) { - Tcl_WideInt length = (len>=0 ? len : ArithSeriesLen(start, end, step)); + Tcl_WideInt length; Tcl_Obj *arithSeriesObj; ArithSeriesDbl *arithSeriesRepPtr; + length = len>=0 ? len : ArithSeriesLenDbl(start, end, step); + if (length < 0) { + length = -1; + } + TclNewObj(arithSeriesObj); if (length <= 0) { @@ -226,11 +285,14 @@ NewArithSeriesDbl(double start, double end, double step, Tcl_WideInt len) arithSeriesRepPtr->step = step; arithSeriesRepPtr->len = length; arithSeriesRepPtr->elements = NULL; + setPrecision(arithSeriesRepPtr); arithSeriesObj->internalRep.twoPtrValue.ptr1 = arithSeriesRepPtr; arithSeriesObj->internalRep.twoPtrValue.ptr2 = NULL; arithSeriesObj->typePtr = &tclArithSeriesType.objType; - if (length > 0) + + if (length > 0) { Tcl_InvalidateStringRep(arithSeriesObj); + } return arithSeriesObj; } @@ -420,7 +482,7 @@ ArithSeriesObjStep( if (arithSeriesObj->typePtr != &tclArithSeriesType.objType) { Tcl_Panic("ArithSeriesObjStep called with a not ArithSeries Obj."); } - arithSeriesRepPtr = ArithSeriesRepPtr(arithSeriesObj); + arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj); if (arithSeriesRepPtr->isDouble) { TclNewDoubleObj(stepObj, ((ArithSeriesDbl*)(arithSeriesRepPtr))->step); } else { @@ -461,7 +523,7 @@ TclArithSeriesObjIndex( if (arithSeriesObj->typePtr != &tclArithSeriesType.objType) { Tcl_Panic("TclArithSeriesObjIndex called with a not ArithSeries Obj."); } - arithSeriesRepPtr = ArithSeriesRepPtr(arithSeriesObj); + arithSeriesRepPtr = ArithSeriesGetInternalRep(arithSeriesObj); if (index < 0 || (Tcl_Size)index >= arithSeriesRepPtr->len) { return Tcl_NewObj(); } @@ -557,16 +619,25 @@ DupArithSeriesInternalRep( Tcl_Obj *copyPtr) /* Object with internal rep to set. */ { ArithSeries *srcArithSeriesRepPtr = - (ArithSeries *) srcPtr->internalRep.twoPtrValue.ptr1; - ArithSeries *copyArithSeriesRepPtr; - + (ArithSeries *) srcPtr->internalRep.twoPtrValue.ptr1; /* * Allocate a new ArithSeries structure. */ - copyArithSeriesRepPtr = (ArithSeries*) Tcl_Alloc(sizeof(ArithSeries)); - *copyArithSeriesRepPtr = *srcArithSeriesRepPtr; - copyArithSeriesRepPtr->elements = NULL; - copyPtr->internalRep.twoPtrValue.ptr1 = copyArithSeriesRepPtr; + if (srcArithSeriesRepPtr->isDouble) { + ArithSeriesDbl *srcArithSeriesDblRepPtr = + (ArithSeriesDbl *)srcArithSeriesRepPtr; + ArithSeriesDbl *copyArithSeriesDblRepPtr = + (ArithSeriesDbl *) Tcl_Alloc(sizeof(ArithSeriesDbl)); + *copyArithSeriesDblRepPtr = *srcArithSeriesDblRepPtr; + copyArithSeriesDblRepPtr->elements = NULL; + copyPtr->internalRep.twoPtrValue.ptr1 = copyArithSeriesDblRepPtr; + } else { + ArithSeries *copyArithSeriesRepPtr = + (ArithSeries *) Tcl_Alloc(sizeof(ArithSeries)); + *copyArithSeriesRepPtr = *srcArithSeriesRepPtr; + copyArithSeriesRepPtr->elements = NULL; + copyPtr->internalRep.twoPtrValue.ptr1 = copyArithSeriesRepPtr; + } copyPtr->internalRep.twoPtrValue.ptr2 = NULL; copyPtr->typePtr = &tclArithSeriesType.objType; } @@ -647,7 +718,7 @@ UpdateStringOfArithSeries(Tcl_Obj *arithSeriesObj) if (((p - arithSeriesObj->bytes)+slen) > length) { break; } - strcpy(p, elem); + strncpy(p, elem, slen); p[slen] = ' '; p += slen+1; Tcl_DecrRefCount(elemObj); @@ -827,14 +898,16 @@ TclArithSeriesObjRange( if (arithSeriesRepPtr->isDouble) { ArithSeriesDbl *arithSeriesDblRepPtr = (ArithSeriesDbl*)arithSeriesRepPtr; double start, end, step; + Tcl_GetDoubleFromObj(NULL, startObj, &start); Tcl_GetDoubleFromObj(NULL, endObj, &end); Tcl_GetDoubleFromObj(NULL, stepObj, &step); arithSeriesDblRepPtr->start = start; arithSeriesDblRepPtr->end = end; arithSeriesDblRepPtr->step = step; - arithSeriesDblRepPtr->len = (end-start+step)/step; + arithSeriesDblRepPtr->len = ArithSeriesLenDbl(start, end, step); arithSeriesDblRepPtr->elements = NULL; + setPrecision(arithSeriesDblRepPtr); } else { Tcl_WideInt start, end, step; @@ -844,7 +917,7 @@ TclArithSeriesObjRange( arithSeriesRepPtr->start = start; arithSeriesRepPtr->end = end; arithSeriesRepPtr->step = step; - arithSeriesRepPtr->len = (end-start+step)/step; + arithSeriesRepPtr->len = ArithSeriesLenInt(start, end, step); arithSeriesRepPtr->elements = NULL; } @@ -1023,6 +1096,7 @@ TclArithSeriesObjReverse( arithSeriesDblRepPtr->start = dstart; arithSeriesDblRepPtr->end = dend; arithSeriesDblRepPtr->step = dstep; + setPrecision(arithSeriesDblRepPtr); } else { arithSeriesRepPtr->start = start; arithSeriesRepPtr->end = end; diff --git a/generic/tclArithSeries.h b/generic/tclArithSeries.h index bb8dfa8..61538c4 100644 --- a/generic/tclArithSeries.h +++ b/generic/tclArithSeries.h @@ -30,6 +30,7 @@ typedef struct { double start; double end; double step; + int precision; } ArithSeriesDbl; diff --git a/generic/tclUtil.c b/generic/tclUtil.c index 36ac624..b765a0f 100644 --- a/generic/tclUtil.c +++ b/generic/tclUtil.c @@ -3845,7 +3845,6 @@ TclIndexEncode( * valid indices but are not in the encodable range. Thus an * error is raised. On 32-bit systems, indices in that range indicate * the position after the end and so do not raise an error. - * However, an encoded index is limited to int (4 bytes). */ if ((sizeof(int) != sizeof(size_t)) && (wide > INT_MAX) && (wide < WIDE_MAX-1)) { diff --git a/tests/lseq.test b/tests/lseq.test index 57b92de..7e4c9da 100755 --- a/tests/lseq.test +++ b/tests/lseq.test @@ -19,7 +19,7 @@ testConstraint arithSeriesShimmer 1 testConstraint arithSeriesShimmerOk 1 testConstraint has64BitLengths [expr {$tcl_platform(pointerSize) == 8}] -## Arg errors +# Arg errors test lseq-1.1 {error cases} -body { lseq } \ @@ -418,7 +418,7 @@ arithseries test lseq-3.31 {lreverse inplace with doubles} arithSeriesDouble { lreverse [lseq 1.1 29.9 0.3] -} {29.9 29.599999999999998 29.299999999999997 29.0 28.7 28.4 28.099999999999998 27.799999999999997 27.5 27.2 26.9 26.599999999999998 26.299999999999997 26.0 25.7 25.4 25.099999999999998 24.799999999999997 24.5 24.2 23.9 23.599999999999998 23.299999999999997 23.0 22.7 22.4 22.099999999999998 21.799999999999997 21.5 21.2 20.9 20.6 20.299999999999997 20.0 19.7 19.4 19.1 18.799999999999997 18.5 18.2 17.9 17.6 17.299999999999997 17.0 16.7 16.4 16.1 15.799999999999999 15.5 15.2 14.899999999999999 14.6 14.299999999999999 14.0 13.7 13.399999999999999 13.099999999999998 12.8 12.5 12.2 11.899999999999999 11.599999999999998 11.3 11.0 10.7 10.399999999999999 10.099999999999998 9.8 9.5 9.2 8.899999999999999 8.599999999999998 8.3 8.0 7.699999999999999 7.399999999999999 7.099999999999998 6.800000000000001 6.5 6.199999999999999 5.899999999999999 5.599999999999998 5.300000000000001 5.0 4.699999999999999 4.399999999999999 4.099999999999998 3.8000000000000007 3.5 3.1999999999999993 2.8999999999999986 2.599999999999998 2.3000000000000007 2.0 1.6999999999999993 1.3999999999999986 1.1000000000000014} +} {29.9 29.6 29.3 29.0 28.7 28.4 28.1 27.8 27.5 27.2 26.9 26.6 26.3 26.0 25.7 25.4 25.1 24.8 24.5 24.2 23.9 23.6 23.3 23.0 22.7 22.4 22.1 21.8 21.5 21.2 20.9 20.6 20.3 20.0 19.7 19.4 19.1 18.8 18.5 18.2 17.9 17.6 17.3 17.0 16.7 16.4 16.1 15.8 15.5 15.2 14.9 14.6 14.3 14.0 13.7 13.4 13.1 12.8 12.5 12.2 11.9 11.6 11.3 11.0 10.7 10.4 10.1 9.8 9.5 9.2 8.9 8.6 8.3 8.0 7.7 7.4 7.1 6.8 6.5 6.2 5.9 5.6 5.3 5.0 4.7 4.4 4.1 3.8 3.5 3.2 2.9 2.6 2.3 2.0 1.7 1.4 1.1} test lseq-4.1 {end expressions} { set start 7 @@ -567,6 +567,24 @@ test lseq-4.13 {bug lseq} -constraints has64BitLengths -body { [lindex $l 9223372036854775800] } -result {9223372036854775807 9223372036854775806 9223372036854775800} + +test lseq-4.14 {bug lseq - inconsistent rounding} { + # using a non-integer increment, [lseq] rounding seems to be not consistent: + lseq 4 40 0.1 +} {4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 8.0 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 9.0 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 10.0 10.1 10.2 10.3 10.4 10.5 10.6 10.7 10.8 10.9 11.0 11.1 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9 12.0 12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8 12.9 13.0 13.1 13.2 13.3 13.4 13.5 13.6 13.7 13.8 13.9 14.0 14.1 14.2 14.3 14.4 14.5 14.6 14.7 14.8 14.9 15.0 15.1 15.2 15.3 15.4 15.5 15.6 15.7 15.8 15.9 16.0 16.1 16.2 16.3 16.4 16.5 16.6 16.7 16.8 16.9 17.0 17.1 17.2 17.3 17.4 17.5 17.6 17.7 17.8 17.9 18.0 18.1 18.2 18.3 18.4 18.5 18.6 18.7 18.8 18.9 19.0 19.1 19.2 19.3 19.4 19.5 19.6 19.7 19.8 19.9 20.0 20.1 20.2 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.9 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.9 25.0 25.1 25.2 25.3 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.2 27.3 27.4 27.5 27.6 27.7 27.8 27.9 28.0 28.1 28.2 28.3 28.4 28.5 28.6 28.7 28.8 28.9 29.0 29.1 29.2 29.3 29.4 29.5 29.6 29.7 29.8 29.9 30.0 30.1 30.2 30.3 30.4 30.5 30.6 30.7 30.8 30.9 31.0 31.1 31.2 31.3 31.4 31.5 31.6 31.7 31.8 31.9 32.0 32.1 32.2 32.3 32.4 32.5 32.6 32.7 32.8 32.9 33.0 33.1 33.2 33.3 33.4 33.5 33.6 33.7 33.8 33.9 34.0 34.1 34.2 34.3 34.4 34.5 34.6 34.7 34.8 34.9 35.0 35.1 35.2 35.3 35.4 35.5 35.6 35.7 35.8 35.9 36.0 36.1 36.2 36.3 36.4 36.5 36.6 36.7 36.8 36.9 37.0 37.1 37.2 37.3 37.4 37.5 37.6 37.7 37.8 37.9 38.0 38.1 38.2 38.3 38.4 38.5 38.6 38.7 38.8 38.9 39.0 39.1 39.2 39.3 39.4 39.5 39.6 39.7 39.8 39.9 40.0} + +test lseq-4.15 {bug lseq - inconsistent rounding} { + # using a non-integer increment, [lseq] rounding seems to be not consistent: + lseq 6 40 0.1 +} {6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 8.0 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 9.0 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 10.0 10.1 10.2 10.3 10.4 10.5 10.6 10.7 10.8 10.9 11.0 11.1 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9 12.0 12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8 12.9 13.0 13.1 13.2 13.3 13.4 13.5 13.6 13.7 13.8 13.9 14.0 14.1 14.2 14.3 14.4 14.5 14.6 14.7 14.8 14.9 15.0 15.1 15.2 15.3 15.4 15.5 15.6 15.7 15.8 15.9 16.0 16.1 16.2 16.3 16.4 16.5 16.6 16.7 16.8 16.9 17.0 17.1 17.2 17.3 17.4 17.5 17.6 17.7 17.8 17.9 18.0 18.1 18.2 18.3 18.4 18.5 18.6 18.7 18.8 18.9 19.0 19.1 19.2 19.3 19.4 19.5 19.6 19.7 19.8 19.9 20.0 20.1 20.2 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.9 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.9 25.0 25.1 25.2 25.3 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.2 27.3 27.4 27.5 27.6 27.7 27.8 27.9 28.0 28.1 28.2 28.3 28.4 28.5 28.6 28.7 28.8 28.9 29.0 29.1 29.2 29.3 29.4 29.5 29.6 29.7 29.8 29.9 30.0 30.1 30.2 30.3 30.4 30.5 30.6 30.7 30.8 30.9 31.0 31.1 31.2 31.3 31.4 31.5 31.6 31.7 31.8 31.9 32.0 32.1 32.2 32.3 32.4 32.5 32.6 32.7 32.8 32.9 33.0 33.1 33.2 33.3 33.4 33.5 33.6 33.7 33.8 33.9 34.0 34.1 34.2 34.3 34.4 34.5 34.6 34.7 34.8 34.9 35.0 35.1 35.2 35.3 35.4 35.5 35.6 35.7 35.8 35.9 36.0 36.1 36.2 36.3 36.4 36.5 36.6 36.7 36.8 36.9 37.0 37.1 37.2 37.3 37.4 37.5 37.6 37.7 37.8 37.9 38.0 38.1 38.2 38.3 38.4 38.5 38.6 38.7 38.8 38.9 39.0 39.1 39.2 39.3 39.4 39.5 39.6 39.7 39.8 39.9 40.0} + +test lseq-4.16 {bug lseq - inconsistent rounding} { + # using a non-integer increment, [lseq] rounding seems to be not consistent: + set res {} + lappend res [lseq 4.07 6 0.1] + lappend res [lseq 4.03 4.208 0.013] +} {{4.07 4.17 4.27 4.37 4.47 4.57 4.67 4.77 4.87 4.97 5.07 5.17 5.27 5.37 5.47 5.57 5.67 5.77 5.87 5.97} {4.03 4.043 4.056 4.069 4.082 4.095 4.108 4.121 4.134 4.147 4.16 4.173 4.186 4.199}} + # cleanup ::tcltest::cleanupTests -- cgit v0.12