mirror of
https://github.com/tcltk/tcl.git
synced 2026-05-29 00:27:49 +08:00
lseq bugfixes: 8d1fc7,999b69,tip-746
Some checks failed
Linux / plan (push) Has been cancelled
macOS / plan (push) Has been cancelled
macOS / xcode (push) Has been cancelled
Build Binaries / Linux (push) Has been cancelled
Build Binaries / macOS (push) Has been cancelled
Build Binaries / Windows (push) Has been cancelled
Windows / plan (push) Has been cancelled
Linux / gcc (push) Has been cancelled
macOS / clang (push) Has been cancelled
Build Binaries / Combine Artifacts (prototype) (push) Has been cancelled
Windows / msvc (push) Has been cancelled
Windows / gcc (push) Has been cancelled
Some checks failed
Linux / plan (push) Has been cancelled
macOS / plan (push) Has been cancelled
macOS / xcode (push) Has been cancelled
Build Binaries / Linux (push) Has been cancelled
Build Binaries / macOS (push) Has been cancelled
Build Binaries / Windows (push) Has been cancelled
Windows / plan (push) Has been cancelled
Linux / gcc (push) Has been cancelled
macOS / clang (push) Has been cancelled
Build Binaries / Combine Artifacts (prototype) (push) Has been cancelled
Windows / msvc (push) Has been cancelled
Windows / gcc (push) Has been cancelled
This commit is contained in:
@@ -14,7 +14,12 @@ to the userbase.
|
||||
- [Check for -municode doesn't work on WSL](https://core.tcl-lang.org/tcl/tktview/632710)
|
||||
- [configure --enable-man-compression error](https://core.tcl-lang.org/tcl/tktview/886549)
|
||||
- [nmake: rmdir and mkdir are picked from cygwin if available](https://core.tcl-lang.org/tcl/tktview/be40b7)
|
||||
|
||||
- [lseq: has incorrect results in edge cases](https://core.tcl-lang.org/tcl/tktview/999b69)
|
||||
- [lseq: "count" error persists across calls](https://core.tcl-lang.org/tcl/tktview/8d1fc7)
|
||||
- [lseq: tip-746 removes the ability to pass expressions as numeric
|
||||
values in the lseq
|
||||
command.](https://core.tcl-lang.org/tips/doc/trunk/tip/746.md)
|
||||
|
||||
# Updated bundled packages, libraries, standards, data
|
||||
- Itcl 4.3.6
|
||||
- sqlite3 3.51.2
|
||||
|
||||
47
doc/lseq.n
47
doc/lseq.n
@@ -31,40 +31,48 @@ The \fBlseq\fR command can produce both increasing and decreasing
|
||||
sequences. When both \fIstart\fR and \fIend\fR are provided without a
|
||||
\fIstep\fR value, then if \fIstart\fR <= \fIend\fR, the sequence will be
|
||||
increasing and if \fIstart\fR > \fIend\fR it will be decreasing. If a
|
||||
\fIstep\fR vale is included, it's sign should agree with the direction of the
|
||||
sequence (descending \(-> negative and ascending \(-> positive), otherwise an
|
||||
empty list is returned. For example:
|
||||
\fIstep\fR value is included, it's sign should agree with the direction of the
|
||||
sequence (descending \(-> negative and ascending \(-> positive), otherwise the
|
||||
list will have a length of 0. For example:
|
||||
.RS
|
||||
.PP
|
||||
.CS \"
|
||||
% \fBlseq\fR 1 to 5 ;# increasing
|
||||
# increasing:
|
||||
.br
|
||||
% \fBlseq\fR 1 to 5
|
||||
\fI\(-> 1 2 3 4 5
|
||||
|
||||
% \fBlseq\fR 5 to 1 ;# decreasing
|
||||
# decreasing:
|
||||
.br
|
||||
% \fBlseq\fR 5 to 1
|
||||
\fI\(-> 5 4 3 2 1
|
||||
|
||||
% \fBlseq\fR 0 0.5 by 0.1 ;# doubles
|
||||
# doubles:
|
||||
.br
|
||||
% \fBlseq\fR 0 0.5 by 0.1
|
||||
\fI\(-> 0.0 0.1 0.2 0.3 0.4 0.5\fR
|
||||
|
||||
% \fBlseq\fR 6 to 1 by 2 ;# decreasing, step wrong sign, empty list
|
||||
# decreasing, step with wrong sign:
|
||||
.br
|
||||
% \fBlseq\fR 6 to 1 by 2
|
||||
\fI\(-> {}
|
||||
|
||||
% \fBlseq\fR 1 to 5 by 0 ;# all step sizes of 0 produce an empty list
|
||||
# step of 0,
|
||||
.br
|
||||
% \fBlseq\fR 3 to 9 by 0
|
||||
\fI\(-> 3
|
||||
.\"
|
||||
.CE
|
||||
.RE
|
||||
.PP
|
||||
The numeric arguments, \fIstart\fR, \fIend\fR, \fIstep\fR, and \fIcount\fR,
|
||||
may also be a valid expression. The expression will be evaluated and the
|
||||
numeric result will be used. An expression that does not evaluate to a number
|
||||
will produce an invalid argument error.
|
||||
.PP
|
||||
\fIStart\fR defines the initial value and \fIend\fR defines the limit, not
|
||||
necessarily the last value. \fBlseq\fR produces a list with \fIcount\fR
|
||||
elements, and if \fIcount\fR is not supplied, it is computed as:
|
||||
elements, always, even if the step value is 0. and if \fIcount\fR is not
|
||||
supplied, it is computed as:
|
||||
.RS
|
||||
.PP
|
||||
.CS
|
||||
\fIcount\fR = int( (\fIend\fR - \fIstart\fR + \fIstep\fR) / \fIstep\fR )
|
||||
\fIcount\fR = int( ( (\fIend\fR - \fIstart\fR) / \fIstep\fR ) + 1 )
|
||||
.CE
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
@@ -82,6 +90,9 @@ elements, and if \fIcount\fR is not supplied, it is computed as:
|
||||
set l [\fBlseq\fR 0 -5]
|
||||
\fI\(-> 0 -1 -2 -3 -4 -5\fR
|
||||
|
||||
\fBlseq\fR 1 count 5 by 0
|
||||
\fI\(-> 1 1 1 1 1\fR
|
||||
|
||||
foreach i [\fBlseq\fR [llength $l]] {
|
||||
puts l($i)=[lindex $l $i]
|
||||
}
|
||||
@@ -103,13 +114,13 @@ foreach i [\fBlseq\fR {[llength $l]-1} 0] {
|
||||
\fI\(-> l(0)=0\fR
|
||||
|
||||
set i 17
|
||||
\fI\(-> 17\fR
|
||||
\fI\(-> 17\fR
|
||||
|
||||
if {$i in [\fBlseq\fR 0 50]} { # equivalent to: (0 <= $i && $i <= 50)
|
||||
puts "Ok"
|
||||
} else {
|
||||
puts "outside :("
|
||||
}
|
||||
\fI\(-> Ok\fR
|
||||
} \fI\(-> Ok\fR
|
||||
|
||||
set sqrs [lmap i [\fBlseq\fR 1 10] { expr {$i*$i} }]
|
||||
\fI\(-> 1 4 9 16 25 36 49 64 81 100\fR
|
||||
|
||||
@@ -289,6 +289,13 @@ maxObjPrecision(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static Tcl_WideInt
|
||||
ArithSeriesLenDbl(
|
||||
double start,
|
||||
double end,
|
||||
double step,
|
||||
unsigned precision);
|
||||
|
||||
static Tcl_WideInt
|
||||
ArithSeriesLenInt(
|
||||
Tcl_WideInt start,
|
||||
Tcl_WideInt end,
|
||||
@@ -296,13 +303,21 @@ ArithSeriesLenInt(
|
||||
{
|
||||
Tcl_WideInt len;
|
||||
|
||||
// Check for opposite sequence directions
|
||||
if ((step < 0 && (end-start) > 0) ||
|
||||
(step > 0 && (end-start) < 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (step == 0) {
|
||||
return 0;
|
||||
// Sequence consists of a single value
|
||||
return 1;
|
||||
}
|
||||
len = (end - start) / step + 1;
|
||||
|
||||
len = ((end - start) / step) + 1;
|
||||
if (len < 0) {
|
||||
return 0;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -320,7 +335,7 @@ ArithSeriesLenDbl(
|
||||
* with and w/o FPU_INLINE_ASM, _CONTROLFP, etc) */
|
||||
|
||||
if (step == 0) {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (precision) {
|
||||
scaleFactor = power10(precision);
|
||||
@@ -330,6 +345,7 @@ ArithSeriesLenDbl(
|
||||
}
|
||||
/* distance */
|
||||
end -= start;
|
||||
|
||||
/*
|
||||
* To improve numerical stability use wide arithmetic instead of IEEE-754
|
||||
* when distance and step do not exceed wide-integers.
|
||||
@@ -339,7 +355,8 @@ ArithSeriesLenDbl(
|
||||
Tcl_WideInt iend = end < 0 ? end - 0.5 : end + 0.5;
|
||||
Tcl_WideInt istep = step < 0 ? step - 0.5 : step + 0.5;
|
||||
if (istep) { /* avoid div by zero, steps like 0.1, precision 0 */
|
||||
return (iend / istep) + 1;
|
||||
Tcl_WideInt ilen = (iend / istep) + 1;
|
||||
return (ilen < 0 ? 0 : ilen);
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -348,10 +365,10 @@ ArithSeriesLenDbl(
|
||||
*/
|
||||
len = (end / step) + 1;
|
||||
if (len >= (double)TCL_SIZE_MAX) {
|
||||
return TCL_SIZE_MAX;
|
||||
len = TCL_SIZE_MAX;
|
||||
}
|
||||
if (len < 0) {
|
||||
return 0;
|
||||
if (len <= 0) {
|
||||
len = 1;
|
||||
}
|
||||
return (Tcl_WideInt)len;
|
||||
}
|
||||
@@ -460,10 +477,13 @@ NewArithSeriesInt(
|
||||
|
||||
TclNewObj(arithSeriesObj);
|
||||
|
||||
if (length <= 0) {
|
||||
/* TODO - should negative lengths be an error? */
|
||||
if (length < 0) {
|
||||
// Negative length implies the step direction is opposite to the
|
||||
// start/end direction. In mathmatical terms, an infinite length.
|
||||
// Map this to an empty list (length of 0). An empty set is a vaild
|
||||
// sequence.
|
||||
return arithSeriesObj;
|
||||
} else if (length > 1) {
|
||||
} else if (length >= 1) {
|
||||
/* Check for numeric overflow. Not needed for single element lists */
|
||||
Tcl_WideUInt absoluteStep;
|
||||
Tcl_WideInt numIntervals = length - 1;
|
||||
@@ -481,9 +501,10 @@ NewArithSeriesInt(
|
||||
absoluteStep = -step;
|
||||
}
|
||||
/* First, step*number of intervals should not overflow */
|
||||
if ((UWIDE_MAX / absoluteStep) < (Tcl_WideUInt) numIntervals) {
|
||||
if (absoluteStep && (UWIDE_MAX / absoluteStep) < (Tcl_WideUInt) numIntervals) {
|
||||
goto invalid_range;
|
||||
}
|
||||
|
||||
if (step > 0) {
|
||||
/*
|
||||
* Because of check above and UWIDE_MAX=2*WIDE_MAX+1,
|
||||
@@ -675,53 +696,61 @@ TclNewArithSeriesObj(
|
||||
{
|
||||
double dstart, dend, dstep = 1.0;
|
||||
Tcl_WideInt start, end, step = 1;
|
||||
Tcl_WideInt len = -1;
|
||||
Tcl_WideInt len;
|
||||
Tcl_Obj *objPtr;
|
||||
unsigned precision = (unsigned)-1; /* unknown precision */
|
||||
|
||||
|
||||
if (lenObj) {
|
||||
if (Tcl_GetWideIntFromObj(interp, lenObj, &len) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// Default
|
||||
len = -1;
|
||||
}
|
||||
|
||||
if (stepObj) {
|
||||
if (assignNumber(interp, useDoubles, &step, &dstep, stepObj) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// Default
|
||||
step = 1;
|
||||
dstep = step;
|
||||
}
|
||||
|
||||
if (startObj) {
|
||||
if (assignNumber(interp, useDoubles, &start, &dstart, startObj) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// Default
|
||||
start = 0;
|
||||
dstart = 0.0;
|
||||
}
|
||||
if (stepObj) {
|
||||
if (assignNumber(interp, useDoubles, &step, &dstep, stepObj) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
if (!useDoubles ? !step : !dstep) {
|
||||
TclNewObj(objPtr);
|
||||
return objPtr;
|
||||
}
|
||||
dstart = start;
|
||||
}
|
||||
|
||||
if (endObj) {
|
||||
if (assignNumber(interp, useDoubles, &end, &dend, endObj) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (lenObj) {
|
||||
if (Tcl_GetWideIntFromObj(interp, lenObj, &len) != TCL_OK) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (endObj) {
|
||||
if (!stepObj) {
|
||||
if (useDoubles) {
|
||||
if (dstart > dend) {
|
||||
dstep = -1.0;
|
||||
step = -1;
|
||||
dstep = step;
|
||||
}
|
||||
} else {
|
||||
if (start > end) {
|
||||
step = -1;
|
||||
dstep = -1.0;
|
||||
dstep = step;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(dstep!=0);
|
||||
|
||||
if (!lenObj) {
|
||||
if (useDoubles) {
|
||||
if (isinf(dstart) || isinf(dend)) {
|
||||
@@ -763,6 +792,13 @@ TclNewArithSeriesObj(
|
||||
* similar to plain lists, otherwise it'd generate an error or panic later
|
||||
* (0x0ffffffffffffffa instead of 0x7fffffffffffffff by 64bit)
|
||||
*/
|
||||
/*
|
||||
* Comment for future reference: The size concern would only be triggered
|
||||
* via a shimmer or getElements of the abstract list. Otherwise, the
|
||||
* abstract list is only limited by the max index value. Even then,
|
||||
* indexing with a bignum is theoretically possible. This is because
|
||||
* individual values are not stored. They are created upon request.
|
||||
*/
|
||||
if (len > TCL_SIZE_MAX) {
|
||||
exceeded:
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(
|
||||
|
||||
@@ -4047,10 +4047,6 @@ SequenceIdentifyArgument(
|
||||
void *internalPtr;
|
||||
|
||||
if (allowedArgs & NumericArg) {
|
||||
/* speed-up a bit (and avoid shimmer for compiled expressions) */
|
||||
if (TclHasInternalRep(argPtr, &tclExprCodeType)) {
|
||||
goto doExpr;
|
||||
}
|
||||
result = Tcl_GetNumberFromObj(NULL, argPtr, &internalPtr, keywordIndexPtr);
|
||||
if (result == TCL_OK) {
|
||||
*numValuePtr = argPtr;
|
||||
@@ -4072,24 +4068,15 @@ SequenceIdentifyArgument(
|
||||
*keywordIndexPtr = opmode;
|
||||
return RangeKeywordArg;
|
||||
} else {
|
||||
Tcl_Obj *exprValueObj;
|
||||
int keyword;
|
||||
if (!(allowedArgs & NumericArg)) {
|
||||
return NoneArg;
|
||||
}
|
||||
doExpr:
|
||||
/* Check for an index expression */
|
||||
if (Tcl_ExprObj(interp, argPtr, &exprValueObj) != TCL_OK) {
|
||||
if (Tcl_GetNumberFromObj(interp, argPtr, &internalPtr, &keyword) != TCL_OK) {
|
||||
return ErrArg;
|
||||
}
|
||||
int keyword;
|
||||
/* Determine if result of expression is double or int */
|
||||
if (Tcl_GetNumberFromObj(interp, exprValueObj, &internalPtr,
|
||||
&keyword) != TCL_OK
|
||||
) {
|
||||
return ErrArg;
|
||||
}
|
||||
*numValuePtr = exprValueObj; /* incremented in Tcl_ExprObj */
|
||||
*keywordIndexPtr = keyword; /* type of expression result */
|
||||
*numValuePtr = argPtr;
|
||||
*keywordIndexPtr = keyword; /* type of result */
|
||||
return NumericArg;
|
||||
}
|
||||
}
|
||||
|
||||
116
tests/lseq.test
116
tests/lseq.test
@@ -19,6 +19,7 @@ testConstraint arithSeriesShimmer 1
|
||||
testConstraint arithSeriesShimmerOk 1
|
||||
testConstraint has64BitLengths [expr {$tcl_platform(pointerSize) == 8}]
|
||||
testConstraint has32BitLengths [expr {$tcl_platform(pointerSize) == 4}]
|
||||
testConstraint TIP746 0 ;# Obsolete expr behavior in lseq on numeric arguments
|
||||
|
||||
proc memusage {} {
|
||||
set fd [open /proc/[pid]/statm]
|
||||
@@ -154,35 +155,30 @@ test lseq-1.24 {consistence, use double (even if representable as integer) in al
|
||||
[lseq 0 count 3 by 1.0] [lseq 0 .. 2.0] [lseq 0 to 2 by 1.0]
|
||||
} [lrepeat 6 {0.0 1.0 2.0}]
|
||||
test lseq-1.25 {consistence, use double (even if representable as integer) in all variants, if contains a double somewhere} {
|
||||
list [lseq double(0) 2] [lseq 0 double(2)] [lseq double(0) count 3] \
|
||||
[lseq 0 count 3 by double(1)] [lseq 0 .. double(2)] [lseq 0 to 2 by double(1)]
|
||||
list [lseq [expr {double(0)}] 2] [lseq 0 [expr {double(2)}]] [lseq [expr {double(0)}] count 3] \
|
||||
[lseq 0 count 3 by [expr {double(1)}]] [lseq 0 .. [expr {double(2)}]] [lseq 0 to 2 by [expr {double(1)}]]
|
||||
} [lrepeat 6 {0.0 1.0 2.0}]
|
||||
test lseq-1.26 {consistence, double always remains double} {
|
||||
list [lseq 1 3.0 ] \
|
||||
[lseq 1 [expr {3.0+0}] ] \
|
||||
[lseq 1 {3.0+0} ] \
|
||||
[lseq 1.0 3.0 1] \
|
||||
[lseq [expr {1.0+0}] [expr {3.0+0}] 1] \
|
||||
[lseq {1.0+0} {3.0+0} 1]
|
||||
} [lrepeat 6 {1.0 2.0 3.0}]
|
||||
[lseq [expr {1.0+0}] [expr {3.0+0}] 1]
|
||||
} [lrepeat 4 {1.0 2.0 3.0}]
|
||||
test lseq-1.27 {consistence, double always remains double} {
|
||||
list [lseq 1e50 [expr {1e50+1}] ] \
|
||||
[lseq 1e50 {1e50+1} ] \
|
||||
[lseq [expr {1e50+0}] [expr {1e50+1}] 1] \
|
||||
[lseq {1e50+0} {1e50+1} 1] \
|
||||
[lseq [expr {1e50+0}] count 1 1] \
|
||||
[lseq {1e50+0} count 1 1]
|
||||
} [lrepeat 6 [expr {1e50}]]
|
||||
[lseq [expr {1e50+0}] count 1 1]
|
||||
} [lrepeat 3 [expr {1e50}]]
|
||||
|
||||
#
|
||||
# Short-hand use cases
|
||||
#
|
||||
test lseq-2.2 {step magnitude} {
|
||||
lseq 10 1 2 ;# this is an empty case since step has wrong sign
|
||||
lseq 10 1 2 ;# An error where step has wrong sign. Not an error, but list has len 1
|
||||
} {}
|
||||
|
||||
test lseq-2.3 {step wrong sign} arithSeriesDouble {
|
||||
lseq 25. 5. 5 ;# ditto - empty list
|
||||
lseq 25. 5. 5 ;# ditto - same as lseq-2.2 above
|
||||
} {}
|
||||
|
||||
test lseq-2.4 {integer decreasing} {
|
||||
@@ -215,7 +211,7 @@ test lseq-2.10 {integer lseq with step} {
|
||||
lseq 1 10 2
|
||||
} {1 3 5 7 9}
|
||||
|
||||
test lseq-2.11 {error case: increasing wrong step direction} {
|
||||
test lseq-2.11 {case: increasing wrong step direction} {
|
||||
lseq 1 10 -2
|
||||
} {}
|
||||
|
||||
@@ -255,20 +251,20 @@ test lseq-2.18 {signs} {
|
||||
|
||||
} {{-10 -8 -6 -4 -2} {} {} {10 6 2} {-10 -7 -4 -1} {10 5}}
|
||||
|
||||
test lseq-2.19 {expressions as indices} {
|
||||
test lseq-2.19 {expressions as indices} -constraints TIP746 -body {
|
||||
list [lseq {1+1}] \
|
||||
[lseq {1+1} {2+2}] \
|
||||
[lseq {1+1} count {2+2}] \
|
||||
[lseq {1+1} {5+5} {2+2}] \
|
||||
[lseq {1+1} count {2+2} by {2+2}]
|
||||
} {{0 1} {2 3 4} {2 3 4 5} {2 6 10} {2 6 10 14}}
|
||||
} -result {{0 1} {2 3 4} {2 3 4 5} {2 6 10} {2 6 10 14}}
|
||||
|
||||
test lseq-2.20 {expressions as indices, no duplicative eval of expr} {
|
||||
test lseq-2.20 {expressions as indices, no duplicative eval of expr} -constraints TIP746 -body {
|
||||
set i 1
|
||||
list [lseq {[incr i]}] $i [lseq {0 + [incr i]}] $i [lseq {0.0 + [incr i]}] $i
|
||||
} {{0 1} 2 {0 1 2} 3 {0 1 2 3} 4}
|
||||
} -result {{0 1} 2 {0 1 2} 3 {0 1 2 3} 4}
|
||||
|
||||
test lseq-3.0 {expr error: don't swalow expr error (here: divide by zero)} -body {
|
||||
test lseq-3.0 {expr error: don't swalow expr error (here: divide by zero)} -constraints TIP746 -body {
|
||||
set i 0; lseq {3/$i}
|
||||
} -returnCodes [catch {expr {3/0}} res] -result $res
|
||||
|
||||
@@ -296,15 +292,15 @@ test lseq-3.1 {experiement} -body {
|
||||
|
||||
test lseq-3.2 {error case} -body {
|
||||
lseq foo
|
||||
} -returnCodes 1 -match glob -result {invalid bareword "foo"*}
|
||||
} -returnCodes 1 -match glob -result {expected number but got "foo"}
|
||||
|
||||
test lseq-3.3 {error case} -body {
|
||||
lseq 10 foo
|
||||
} -returnCodes 1 -match glob -result {invalid bareword "foo"*}
|
||||
} -returnCodes 1 -match glob -result {expected number but got "foo"}
|
||||
|
||||
test lseq-3.4 {error case} -body {
|
||||
lseq 25 or 6
|
||||
} -returnCodes 1 -match glob -result {invalid bareword "or"*}
|
||||
} -returnCodes 1 -match glob -result {expected number but got "or"}
|
||||
|
||||
test lseq-3.5 {simple count and step arguments} -body {
|
||||
set s [lseq 25 by 6]
|
||||
@@ -421,14 +417,24 @@ test lseq-3.18 {error case} -body {
|
||||
|
||||
test lseq-3.19 {edge case} -body {
|
||||
lseq 1 count 5 by 0
|
||||
} -result {}
|
||||
# 1 1 1 1 1
|
||||
} -result {1 1 1 1 1}
|
||||
|
||||
# My thought is that this is likely a user error, since they can always use lrepeat for this.
|
||||
# My thought is that this is likely a user error, since they can
|
||||
# always use lrepeat for this.
|
||||
|
||||
# bsg: Nah. The count defines the required list length, regardless of
|
||||
# the values produced by the equation. Consider scenarios
|
||||
# where arguments are variables that may include 0
|
||||
# intentionally. A reasonable valid answer is better than
|
||||
# always having to safeguard against errors.
|
||||
#
|
||||
# Another way to look at it is that the sequence is an equation
|
||||
# of a straight line. Every sequnce should be representable on a
|
||||
# cartisian plane where X (the index) is always positive.
|
||||
|
||||
test lseq-3.20 {edge case} -body {
|
||||
lseq 1 to 1 by 0
|
||||
} -result {}
|
||||
} -result {1}
|
||||
|
||||
# hmmm, I guess this is right, in a way, so...
|
||||
|
||||
@@ -556,7 +562,7 @@ test lseq-3.34 {"in" operator} -body {
|
||||
} -result {{3012.0 3012.3 3012.6 3012.9} {3012.03 3012.06 3012.09 3012.12 3012.15 3012.18 3012.21 3012.24 3012.27 3012.33 3012.36 3012.39 3012.42 3012.45 3012.48 3012.51 3012.54 3012.57 3012.63 3012.66 3012.69 3012.72 3012.75 3012.78 3012.81 3012.84 3012.87 3012.93 3012.96 3012.99}}
|
||||
|
||||
test lseq-3.35 {"in" operator integer} -body {
|
||||
set seq [lseq 3 int(15e4) 5]
|
||||
set seq [lseq 3 [expr {int(15e4)}] 5]
|
||||
set inlist {}
|
||||
set nilist {}
|
||||
foreach y [lseq 3012 3213 3] {
|
||||
@@ -584,12 +590,12 @@ test lseq-3.36 {"in" non-numeric case} -body {
|
||||
|
||||
test lseq-4.1 {end expressions} -body {
|
||||
set start 7
|
||||
lseq $start $start+11
|
||||
lseq $start [expr {$start+11}]
|
||||
} -cleanup {unset start} -result {7 8 9 10 11 12 13 14 15 16 17 18}
|
||||
|
||||
test lseq-4.2 {start expressions} -body {
|
||||
set base [clock seconds]
|
||||
set tl [lseq $base-60 $base 10]
|
||||
set tl [lseq [expr {$base-60}] $base 10]
|
||||
lmap t $tl {expr {$t - $base + 60}}
|
||||
} -cleanup {unset base tl t} -result {0 10 20 30 40 50 60}
|
||||
|
||||
@@ -620,11 +626,11 @@ test lseq-4.3 {TIP examples} -body {
|
||||
lseq 25. to -25. by -5
|
||||
# -> 25.0 20.0 15.0 10.0 5.0 0.0 -5.0 -10.0 -15.0 -20.0 -25.0
|
||||
lseq 5 5
|
||||
# -> 5
|
||||
# ->
|
||||
lseq 5 5 2
|
||||
# -> 5
|
||||
# ->
|
||||
lseq 5 5 -2
|
||||
# -> 5
|
||||
# ->
|
||||
}
|
||||
set res {}
|
||||
foreach {cmd expect} [split $examples \n] {
|
||||
@@ -852,7 +858,7 @@ test lseq-4.21.1 {Corner cases: overflows by Inf} -body {
|
||||
}]
|
||||
test lseq-4.21.2 {Corner cases: expected Inf} -body {
|
||||
set res {}
|
||||
lappend res [lseq {1e5555+0} count 5]
|
||||
lappend res [lseq [expr {1e5555+0}] count 5]
|
||||
lappend res [lseq Inf count 5]
|
||||
lappend res [lseq Inf count 5 by 100]
|
||||
lappend res [lseq Inf count 5 by Inf]
|
||||
@@ -878,7 +884,7 @@ test lseq-4.21.2 {Corner cases: expected Inf} -body {
|
||||
}]
|
||||
test lseq-4.21.3 {Corner cases: expected -Inf} -body {
|
||||
set res {}
|
||||
lappend res [lseq {-1e5555+0} count 5]
|
||||
lappend res [lseq [expr {-1e5555+0}] count 5]
|
||||
lappend res [lseq -Inf count 5]
|
||||
lappend res [lseq -Inf count 5 by 100]
|
||||
lappend res [lseq -Inf count 5 by -Inf]
|
||||
@@ -906,7 +912,7 @@ test lseq-4.21.4 {Corner cases: unexpected Inf - Inf, result to +/-NaN, unexpect
|
||||
set res {}
|
||||
lappend res [list [catch {lseq Inf count 5 by -Inf} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
lappend res [list [catch {lseq -Inf count 5 by Inf} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
lappend res [list [catch {lseq {Inf - Inf} count 5} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
lappend res [list [catch {lseq [expr {Inf - Inf}] count 5} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
lappend res [list [catch {lseq NaN count 5} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
lappend res [list [catch {lseq NaN count 5 by 100} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
lappend res [list [catch {lseq NaN count 5 by NaN} msg opt] $msg [dict getd $opt -errorcode ""]]
|
||||
@@ -916,6 +922,7 @@ test lseq-4.21.4 {Corner cases: unexpected Inf - Inf, result to +/-NaN, unexpect
|
||||
} -cleanup {
|
||||
unset -nocomplain res msg opt
|
||||
} -result [join [lrepeat 8 {1 {domain error: argument not in valid range} {ARITH DOMAIN {domain error: argument not in valid range}}}] \n]
|
||||
|
||||
test lseq-4.21.5 {Corner cases: unexpected NaN} -body {
|
||||
set res {}
|
||||
lappend res [catch {lseq NaN} msg] $msg
|
||||
@@ -923,6 +930,7 @@ test lseq-4.21.5 {Corner cases: unexpected NaN} -body {
|
||||
} -cleanup {
|
||||
unset -nocomplain res msg
|
||||
} -result {1 {expected integer but got "NaN"} 1 {cannot use non-numeric floating-point value "NaN" to estimate length of arith-series}}
|
||||
|
||||
test lseq-4.21.6 {Corner cases: empty list, reversed step} -body {
|
||||
set res {}
|
||||
lappend res [lseq -5 .. 0 by -1]
|
||||
@@ -932,36 +940,55 @@ test lseq-4.21.6 {Corner cases: empty list, reversed step} -body {
|
||||
} -cleanup {
|
||||
unset -nocomplain res
|
||||
} -result {{} {} {} {}}
|
||||
|
||||
test lseq-4.21.6-lran {Corner cases: lrange empty list, reversed step} -body {
|
||||
set res {}
|
||||
# not shared:
|
||||
lappend res [lrange [lseq -5 .. 0 by -1] 1 end-1]
|
||||
lappend res [lrange [lseq -5 .. 0 by 1] 1 end-1]
|
||||
lappend res [lrange [lseq 5 .. 0 by -1] 1 end-1]
|
||||
lappend res [lrange [lseq 5 .. 0 by 1] 1 end-1]
|
||||
lappend res [lrange [lseq 0 .. 5 by -1] 1 end-1]
|
||||
lappend res [lrange [lseq 0 .. 5 by 1] 1 end-1]
|
||||
lappend res [lrange [lseq 0 .. -5 by -1] 1 end-1]
|
||||
lappend res [lrange [lseq 0 .. -5 by 1] 1 end-1]
|
||||
# shared:
|
||||
lappend res [lrange [set l [lseq -5 .. 0 by -1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq -5 .. 0 by 1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq 5 .. 0 by -1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq 5 .. 0 by 1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq 0 .. 5 by -1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq 0 .. 5 by 1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq 0 .. -5 by -1]] 1 end-1]
|
||||
lappend res [lrange [set l [lseq 0 .. -5 by 1]] 1 end-1]
|
||||
} -cleanup {
|
||||
unset -nocomplain res l
|
||||
} -result {{} {} {} {} {} {} {} {}}
|
||||
} -result {{} {-4 -3 -2 -1} {4 3 2 1} {} {} {1 2 3 4} {-1 -2 -3 -4} {} {} {-4 -3 -2 -1} {4 3 2 1} {} {} {1 2 3 4} {-1 -2 -3 -4} {}}
|
||||
|
||||
test lseq-4.21.6-lrev {Corner cases: lreverse empty list, reversed step} -body {
|
||||
set res {}
|
||||
# not shared:
|
||||
lappend res [lreverse [lseq -5 .. 0 by -1]]
|
||||
lappend res [lreverse [lseq -5 .. 0 by 1]]
|
||||
lappend res [lreverse [lseq 5 .. 0 by -1]]
|
||||
lappend res [lreverse [lseq 5 .. 0 by 1]]
|
||||
lappend res [lreverse [lseq 0 .. 5 by -1]]
|
||||
lappend res [lreverse [lseq 0 .. -5 by -1]]
|
||||
lappend res [lreverse [lseq 0 .. -5 by 1]]
|
||||
lappend res [lreverse [lseq 0 .. 5 by -1]]
|
||||
lappend res [lreverse [lseq 0 .. 5 by 1]]
|
||||
# shared:
|
||||
lappend res [lreverse [set l [lseq -5 .. 0 by -1]]]
|
||||
lappend res [lreverse [set l [lseq -5 .. 0 by 1]]]
|
||||
lappend res [lreverse [set l [lseq 5 .. 0 by -1]]]
|
||||
lappend res [lreverse [set l [lseq 5 .. 0 by 1]]]
|
||||
lappend res [lreverse [set l [lseq 0 .. 5 by -1]]]
|
||||
lappend res [lreverse [set l [lseq 0 .. -5 by 1]]]
|
||||
lappend res [lreverse [set l [lseq 0 .. 5 by 1]]]
|
||||
lappend res [lreverse [set l [lseq 0 .. -5 by -1]]]
|
||||
lappend res [lreverse [set l [lseq 0 .. -5 by -1]]]
|
||||
} -cleanup {
|
||||
unset -nocomplain res l
|
||||
} -result {{} {} {} {} {} {} {} {}}
|
||||
} -result {{} {0 -1 -2 -3 -4 -5} {0 1 2 3 4 5} {} {-5 -4 -3 -2 -1 0} {} {} {5 4 3 2 1 0} {} {0 -1 -2 -3 -4 -5} {0 1 2 3 4 5} {} {} {5 4 3 2 1 0} {-5 -4 -3 -2 -1 0} {-5 -4 -3 -2 -1 0}}
|
||||
|
||||
test lseq-4.21.7 {Corner cases: non-empty list, normal step} -body {
|
||||
set res {}
|
||||
lappend res [lseq -5 .. 0 ]
|
||||
@@ -1116,6 +1143,17 @@ test lseq-bug-0ee626dfb2-1 {Bug 0ee626dfb2 - integer overflow} -body {
|
||||
lseq 0x7fffffffffffffff count 3 by -0x8000000000000000
|
||||
} -result {invalid arithmetic series parameter values} -returnCodes error
|
||||
|
||||
test lseq-bug-8d1fc709957-0 {Bug 8d1fc709957 - lseq "count" error persists across calls} -body {
|
||||
catch {lseq 0 count 5} err0
|
||||
catch {lseq count 5} err1
|
||||
catch {lseq 1 count 5} err2
|
||||
list $err0 $err1 $err2
|
||||
} -result {{0 1 2 3 4} {expected number but got "count"} {1 2 3 4 5}}
|
||||
|
||||
test lseq-bug-999b6966b2-0 {Bug 999b6966b2 - lseq has incorrect results in edge cases} -body {
|
||||
lmap i [lseq -9 9] { lseq 10 10 $i }
|
||||
} -result {10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10}
|
||||
|
||||
# cleanup
|
||||
::tcltest::cleanupTests
|
||||
|
||||
|
||||
Reference in New Issue
Block a user