在TCL中生成指定范围内的随机数而不使用REDUNDANCY

时间:2022-01-01 20:33:50

hi I need to generate 30 random numbers without any repeatations of numbers in TCL.

嗨我需要在TCL中生成30个随机数而不重复数字。

Here is the code to generate random number which works fine, but will generate redundant numbers.

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

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 
}

Anyone please help out.

有人请帮忙。

2 个解决方案

#1


Code to generate a sequence of unique random numbers could be written like this, but it won't work unless $nnums is less than or equal to $rmax.

生成一系列唯一随机数的代码可以这样写,但除非$ 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]
    }
}

(When I started writing this answer, I was to preoccupied to notice that you were trying to get 30 unique numbers from a 1-20 range, which is impossible, as others have pointed out.)

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

There are some other problems with your code. You don't need to do nested calls to expr:

您的代码还存在其他一些问题。您不需要对expr执行嵌套调用:

 expr [expr $max + 1] - $min
 # is the same as
 expr {$max + 1 - $min}

so your random number generator can be written like this:

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

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

but that is still more calculations than necessary. This version is better:

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

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

You can also use this:

你也可以用这个:

package require math
::math::random 1 21

(Note 21, not 20!)

(注21,不是20!)

#2


To generate a list of random numbers without repetitions, you've got to put in code to explicitly prevent them. In general, random sequences most certainly can contain repetitions, just as if you toss a coin, it will sometimes come up heads twice (or more) in a row.

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

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 
}

Note that if you're picking 30 values from a collection of 20 numbers, you'll necessarily (by the pigeonhole principle) get some repetitions. But we can prevent values from occurring twice in a row.

请注意,如果您从20个数字的集合中选择30个值,则必须(通过归类原则)获得一些重复。但是我们可以防止连续两次出现值。


Your random number generator is slightly horrifying too. This is the idiomatic version:

你的随机数发生器也有点可怕。这是惯用版:

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

#1


Code to generate a sequence of unique random numbers could be written like this, but it won't work unless $nnums is less than or equal to $rmax.

生成一系列唯一随机数的代码可以这样写,但除非$ 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]
    }
}

(When I started writing this answer, I was to preoccupied to notice that you were trying to get 30 unique numbers from a 1-20 range, which is impossible, as others have pointed out.)

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

There are some other problems with your code. You don't need to do nested calls to expr:

您的代码还存在其他一些问题。您不需要对expr执行嵌套调用:

 expr [expr $max + 1] - $min
 # is the same as
 expr {$max + 1 - $min}

so your random number generator can be written like this:

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

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

but that is still more calculations than necessary. This version is better:

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

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

You can also use this:

你也可以用这个:

package require math
::math::random 1 21

(Note 21, not 20!)

(注21,不是20!)

#2


To generate a list of random numbers without repetitions, you've got to put in code to explicitly prevent them. In general, random sequences most certainly can contain repetitions, just as if you toss a coin, it will sometimes come up heads twice (or more) in a row.

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

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 
}

Note that if you're picking 30 values from a collection of 20 numbers, you'll necessarily (by the pigeonhole principle) get some repetitions. But we can prevent values from occurring twice in a row.

请注意,如果您从20个数字的集合中选择30个值,则必须(通过归类原则)获得一些重复。但是我们可以防止连续两次出现值。


Your random number generator is slightly horrifying too. This is the idiomatic version:

你的随机数发生器也有点可怕。这是惯用版:

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