List 如何在Tcl中生成数字序列

List 如何在Tcl中生成数字序列,list,numbers,tcl,generator,sequence,List,Numbers,Tcl,Generator,Sequence,我正在寻找一种根据输入的from、to和步骤参数生成数字列表的方法 使用incr是不好的,因为我也想支持float和double数字 例如,如果from=-0.3,to=0.25和step=0.1,我想生成列表-0.3-0.2-0.1 0.2。我在格式化和舍入方面遇到问题。如果您可以自己删除字符串前缀: proc genNums {{from 0} {to 1} {step .1} {prec 1}} { if {$step < 0} { set op ::tcl:

我正在寻找一种根据输入的
from
to
步骤
参数生成数字列表的方法

使用
incr
是不好的,因为我也想支持
float
double
数字


例如,如果
from=-0.3
to=0.25
step=0.1
,我想生成列表
-0.3-0.2-0.1 0.2
。我在格式化和舍入方面遇到问题。

如果您可以自己删除字符串前缀:

proc genNums {{from 0} {to 1} {step .1} {prec 1}} {
    if {$step < 0} {
        set op ::tcl::mathop::>
    } else {
        set op ::tcl::mathop::<
    }
    for {set n $from} {[$op $n $to]} {set n [expr {$n + $step}]} {
        lappend res [format %.*f $prec $n]
    }
    return $res 
}

% genNums -0.3 0.25 0.1
# => -0.3 -0.2 -0.1 0.0 0.1 0.2
% genNums -0.3 0.25 0.1 2
# => -0.30 -0.20 -0.10 0.00 0.10 0.20
proc genNums{{from 0}{to 1}{step.1}{prec 1}}{
如果{$step<0}{
set op::tcl::mathop::>
}否则{
set op::tcl::mathop::<
}
对于{set n$from}{[$op$n$to]}{set n[expr{$n+$step}]}{
lappend res[格式%.*f$prec$n]
}
返回$res
}
%genNums-0.30.25 0.1
# => -0.3 -0.2 -0.1 0.0 0.1 0.2
%genNums-0.30.25 0.1 2
# => -0.30 -0.20 -0.10 0.00 0.10 0.20
但如果需要,可以对其进行设置,以便将字符串传递给命令:

proc genNums args {
    array set params {from 0 to 1 step .1 prec 1}
    array set params [split [string map {= { }} $args]]
    if {$params(step) < 0} {
        set op ::tcl::mathop::>
    } else {
        set op ::tcl::mathop::<
    }
    for {set n $params(from)} {[$op $n $params(to)]} {set n [expr {$n + $params(step)}]} {
        lappend res [format %.*f $params(prec) $n]
    }
    return $res 
}

genNums from=-0.3 to=0.25 step=0.1
# => -0.3 -0.2 -0.1 0.0 0.1 0.2
% genNums from=-0.3 to=0.25 step=0.1 prec=2
# => -0.30 -0.20 -0.10 0.00 0.10 0.20
proc genNums args{
数组集参数{从0到1步骤.1 prec 1}
数组集参数[split[string map{={}}$args]]
如果{$params(步骤)<0}{
set op::tcl::mathop::>
}否则{
set op::tcl::mathop::<
}
对于{set n$params(from)}{[$op$n$params(to)]}{set n[expr{$n+$params(step)}]}{
lappend res[格式%.*f$params(prec)$n]
}
返回$res
}
genNums from=-0.3到=0.25步=0.1
# => -0.3 -0.2 -0.1 0.0 0.1 0.2
%genNums from=-0.3至=0.25步数=0.1 prec=2
# => -0.30 -0.20 -0.10 0.00 0.10 0.20
文件: , , , , , , , , , , , ,

这是一个很好的例子。真的

您需要做的是使用整数迭代,然后按步长缩放。这样可以最大限度地减少错误。您还需要小心地使用
格式

set from -0.3
set to 0.25
set step 0.1
for {set i 0} true {incr i} {
    set x [expr {$i*$step + $from}]
    if {$x > $to} break
    set printable [format "%.1f" $x]
    puts "$i => $printable"
}

您如何看待以下解决方案:

proc ::General::Range {Start Stop {Step 1}} {
    if {$Step eq 0} {return Error-'ZeroStep'}
    if {$Start eq $Stop} {return $Start}
    set Range {}
    if {![string in integer $Step]} {
        # Double
        regexp {^\d+\.(\d+)$} $Step FullMatch ToFormat
        while {$Start <= $Stop} {
            lappend Range [string trimright $Start 0]
            set Start [format "%.${ToFormat}f" [expr {$Start + $Step}]]
        }
    } else {
        # Integer
        while {[expr {$Stop > 0 ? [expr {$Start <= $Stop}] : [expr {$Start >= $Stop}]}]} {lappend Range $Start; incr Start $Step}
    }
    return $Range
}
proc::General::Range{Start-Stop{Step 1}{
如果{$Step eq 0}{返回错误-'ZeroStep'}
如果{$Start eq$Stop}{return$Start}
设置范围{}
如果{![string in integer$Step]}{
#双重的
regexp{^\d+\(\d+$}$步骤完全匹配到格式
而{$Start 0?[expr{$Start=$Stop}]}{lappend Range$Start;incr Start$Step}
}
返回$Range
}

下面是一个示例,使用Tcl的协同程序按需生成范围内的下一个值

% proc range {from to step} {
    yield
    set value $from
    while {$value <= $to} {
        yield $value
        set value [expr {$value + $step}]
    }
}
% coroutine generator range -0.35 0.25 0.1
% puts [generator]
-0.35
% puts [generator]
-0.24999999999999997
% puts [generator]
-0.14999999999999997
% puts [generator]
-0.04999999999999996
% puts [generator]
0.050000000000000044
% puts [generator]
0.15000000000000005
% puts [generator]

% puts [generator]
invalid command name "generator"
我们得到了序列

-0.35
-0.24999999999999997
-0.14999999999999997
-0.04999999999999993
0.050000000000000044
0.15000000000000002
0.2500000000000001

这假设
步骤
为正;如果
step
为负值,测试的意义将需要改变。我不应该根据step分辨率推导小数点位置吗?严格来说是的,但通常只需硬编码就可以了。(
set decimalPlaces 1;format%.*f$decimalPlaces$x
)此函数不执行此任务,例如,使用
from=-0.35
to=0.75
step=0.1
。它产生
-0.3-0.2-0.1-0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
@HardwareEng.:您期望的序列是什么?请注意,这是一个小数点:将格式设置为
%.2f
可能更好。@peter,可以添加一个
scale=2
参数,您可以在format命令中使用它。如果要与0进行比较,请使用
=
;0.0不是
eq
到0。在
命令中没有
字符串,您可能的意思是
字符串是
。非整数步长不能为负<代码>字符串trimright$Start 0
意味着您将得到以小数点结尾的数字。从步长值获取格式精度将导致一些奇怪的格式设置。您不必根据
Stop
的值来决定计数是向上还是向下。此外,您过度使用了
expr
,使代码更难阅读。这样做并没有实际的好处。@PeterLewerin:谢谢你的见解@谢谢你的见解!
-0.35
-0.24999999999999997
-0.14999999999999997
-0.04999999999999993
0.050000000000000044
0.15000000000000002
0.2500000000000001