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)}]
}
您好,我需要在 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)}]
}