TCL中生成指定范围内的随机数,无REDUNDANCY

Generate random number within specified range without REDUNDANCY in TCL

您好,我需要在 TCL 中生成 30 个没有任何重复数字的随机数。

这是生成随机数的代码,它工作正常,但会生成冗余数。

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

for {set i 1} {$i < 31} {incr i} {
upvar 0 fnode($i) fnod($i)
set fnod($i) [myRand 1 20] ;# random number is generated between 1 to 20 
}

任何人都请帮忙。

生成唯一随机数序列的代码可以这样写,但除非 $nnums 小于或等于 $rmax

否则它不会工作
set nnums 30
set rmax 20
set nums {}
if {$nnums > $rmax} {
    puts "You can't get $nnums unique values from a range of 1 to $rmax!"
} else {
    while {[llength $nums] < $nnums} {
        set n [myRand 1 $rmax]
        if {$n ni $nums} {lappend nums $n}
    }
    set nums [linsert $nums 0 {}]
    for {set i 1} {$i <= $nnums} {incr i} {
        set fnod($i) [lindex $nums $i]
    }
}

(当我开始写这个答案时,我全神贯注地注意到你试图从 1-20 范围内获得 30 个唯一数字,正如其他人指出的那样,这是不可能的。)

您的代码还有一些其他问题。您不需要对 expr:

进行嵌套调用
 expr [expr $max + 1] - $min
 # is the same as
 expr {$max + 1 - $min}

所以你的随机数生成器可以这样写:

proc myRand {min max} {
    expr {int(rand() * 100) % ($max + 1 - $min) + $min}
}

但这仍然是不必要的计算。这个版本比较好:

proc myRand {min max} {
    expr {int(rand() * ($max + 1 - $min)) + $min}
}

你也可以使用这个:

package require math
::math::random 1 21

(注21,不是20!)

要生成不重复的随机数列表,您必须输入代码以明确阻止它们。一般来说,随机序列肯定可以包含重复,就像你抛硬币一样,它有时会连续两次(或更多次)出现正面。

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 
}

请注意,如果您从 20 个数字的集合中选取 30 个值,您将必然(根据 pigeonhole principle)得到一些重复。但是我们可以防止值连续出现两次。


你的随机数生成器也有点恐怖。这是惯用版本:

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