在tcl中的给定范围内创建随机正整数的代码



我的问题与我在这里找到的tcl代码有关:

在TCL 中生成指定范围内无冗余的随机数

该代码已被建议作为上述问题的答案,看起来如下:

set r -1;              # Some value that definitely isn't in the sequence
for {set i 1} {$i < 31} {incr i} {
upvar 0 fnode($i) fnod($i)
while {$r == [set r [myRand 1 20]]} {
# Empty body
}
set fnod($i) $r;   # Random number is generated between 1 to 20 
}

我很想理解它,但我很困惑,因为这句话:

upvar 0 fnode($i) fnod($i)

为什么代码中有这一行?第一个数组fnode($i(没有出现在代码的前面。因此,应该不可能将upvar应用于它。而且似乎没有任何理由为它引入别名fnod($i(。

另一个重要的问题是:为什么这个代码保证在30个随机生成的数字中,有20个是不同的?

在上面的代码中,myRand是以下过程(也是同一方和同一作者建议的(:

proc myRand {min max} {
set range [expr {$max - $min + 1}]
return [expr {$min + int(rand() * $range)}]
}

它随机生成一个范围为[min,max]的整数。

我还应该补充一点:这段代码不会在TclTutor 3.0b6中运行。我收到以下错误消息:

--------
bad variable name "fnod(1)": upvar won't create a scalar variable that looks like an array element
while executing
"upvar 0 fnode($i) fnod($i)"

欢迎任何帮助。

提前谢谢!

当你在寻找一组唯一的随机数时,有三种情况需要考虑:

  1. 您要查找的值的数量大于您可以选择的唯一随机值的数量。此必须是错误

  2. 您要查找的值的数量只比您可以选择的唯一随机值的数量小一点。在这种情况下,简单的方法是打乱候选集,并从打乱的序列中取一个前导片。(或者拖尾切片,其实并不重要。引导只是实现起来稍微简单一点。(

    proc randomByShuffle {n lowerInclusive upperExclusive} {
    # Generate
    set values {}
    for {set i $lowerInclusive} {$i < $upperExclusive} {incr i} {
    lappend values $i
    }
    # Shuffle
    for {set i 0} {$i < [llength $values] - 1} {incr i} {
    set idx [expr {int(rand() * ([llength $values] - $i)) + $i}]
    # Swap
    set tmp [lindex $values $idx]
    lset values $idx [lindex $values $i]
    lset values $i $tmp
    }
    # Result slice
    return [lrange $values 0 $n]
    }
    set numbers [randomByShuffle 20 10 35]
    

    虽然这种方法的缺点是生成一个包含所有可以选择的值的列表,但它没有任何需要很长时间才能完成的奇怪问题;生成该工作列表的工作量与生成该长度的简单序列所需的最小值数量的成本相似

  3. 您要查找的值的数量远小于您可以选择的唯一随机值的数量。在这种情况下,您可以跟踪所拾取的值,并重新绘制一个值,否则您将获得重复值。

    proc randomBySelection {n lowerInclusive upperExclusive} {
    set range [expr {$upperExclusive - $lowerInclusive}]
    set result {}
    while {[llength $result] < $n} {
    set x [expr {int(rand() * $range) + $lowerInclusive}]
    # Only append value to result if this is first time we've seen it
    if {[incr count($x)] == 1} {
    lappend result $x
    }
    }
    return $result
    }
    set numbers [randomBySelection 20 258 65432]
    

我还没有测试过成本何时使从一种型号切换到另一种型号成为一个好主意。(如果你使用的是浮点数而不是整数,你可能总是可以使用选择方法,因为随机数几乎永远不会重叠。(

最新更新