如何改进给定随机函数的均匀分布,生成均匀分布的数?



这个问题是关于Linux,如Debian或Ubuntu, bash和一个给定的函数使用RANDOM。

每个改进应该只使用bash。

给出如下函数:

getRND(){
min="${1:-1}"   ## min is the first parameter, or 1 if no parameter is given           
max="${2:-100}" ## max is the second parameter, or 100 if no parameter is given
rnd_count=$((RANDOM%(max-min+1)+min));
echo "$rnd_count"
}
var=$(getRND -10 10) # Call the function
echo $var # output

如何:

  • 提高随机性

解决方案是为尚未安装bash 5.1的Linux系统寻求的,因此到目前为止还不能使用SRANDOM。

在给定的随机函数上可以改进什么以使其更随机或范围更大或其他什么?

,因此没有SRANDOM可以使用到现在。

如果可能,如何提高上述函数的随机性?

所以用你自己的语义写你自己的SRANDOM。例:
srandom() {
# take random number from /dev/urandom
# we take only just 4 bytes - one 2^32 number
printf "%dn" "0x$(
dd if=/dev/urandom of=/dev/stdout bs=4 count=1 status=none |
xxd -p)"
}

然后:

normalize_value(){
...
rnd=$(srandom)
rnd_count=$((rnd / ...))
}

接受更大范围的数字

如果你对shell的算术展开方式不满意,那么…使用不同的工具。bc计算器具有无限量程

rnd_count=$(echo "
# see https://superuser.com/questions/31445/gnu-bc-modulo-with-scale-other-than-0
scale=0; 
# super big random number from three 2^32 numbers
rnd = $(srandom) * 2^(32*2) +  $(srandom) * 2^32 + $(srandom)
rnd % ($max - $min + 1) + $min
" | bc)

你可以用getrandom()编写你自己的C程序,并在运行中编译它,echo "int main() { stuff(); }" | gcc -xc - && ./a.out; rm ./a.out基本上授予你任何你想要的语义。还有其他脚本语言,如perl、python、ruby,它们都很可能有自己的大数字库和随机数生成实现。突破极限

每个改进都应该只使用bash。

从我的角度来看,这是一个毫无意义的限制——总的来说,我是根据结果得到报酬的,而不是真正的"如何"。我解决问题。无论如何,你可以,给你一堆如何进行的想法:
  • 首先编写一个函数,该函数将从/dev/urandom读取并将字节转换为数字。
    • 我不知道如何在纯bash中做到这一点,同时保持随机性在相同的水平。我怀疑输入会很快耗尽。
    • 你可以从随机中读取一个字节。你必须忽略read退出状态,因为字节可能是零字节或换行符。
    • 然后检查该字节是否是数字。如果不是,重复上一步。
    • 将此算法视为0-9范围内随机数的生成器。从这些数字构建更大的数字。
  • 然后使用算术展开作为"后端",用bash编写自己的大数库。
    • 似乎毫无意义,因为bc是普遍可用的。
    • 这将像通常的大型库一样工作。
    • 我建议将数字存储为最大2^16的数字数组。为了获得灵感,研究用C和c++语言编写的类似库,并将其转换为bash。

在主shell中为RANDOM创建seed并期望它在子shell中受到青睐是没有意义的,因为新shell会自己初始化seed。

所以你需要种子和使用主shell的RANDOM,并将值传递给另一个函数进行转换。

下面是一个如何让你的种子工作的例子:

#!/bin/bash

normalize_value(){
value_to_normalize=$1
min="${2:-1}"   ## min is the first parameter, or 1 if no parameter is given           
max="${3:-100}" ## max is the second parameter, or 100 if no parameter is given
rnd_count=$((value_to_normalize % (max-min+1)+min));
echo "$rnd_count"
}
RANDOM=$(date +%s%N | cut -b10-19)
rnd=$RANDOM # get random value in a context of main shell and your seed
var=$(normalize_value $rnd -10 10) # pass random value into normalizer function
echo $var # output
###### following example will NOT WORK because statement refers to subshell's random generator
RANDOM=1
var=$(normalize_value $RANDOM -10 10) # wrong random sequence is used (not seeded by you)
echo $var # output
var=$(normalize_value $RANDOM -10 10) # wrong
echo $var # output

当问题中的代码和KamilCuk的答案中的代码组合在一个函数中进行随机更均匀分布时,它是这样的:

#!/bin/bash
get_rnd_num_eq_dis(){
min="${1:-1}"   # min is the first parameter, or 1 if no parameter is given           
max="${2:-100}" # max is the second parameter, or 100 if no parameter is given
#   rnd=$(srandom)
srnd="$((0x$(dd if=/dev/urandom of=/dev/stdout bs=4 count=1 status=none | xxd -p)))"
rnd_count=$((srnd%(max-min+1)+min));
echo "$rnd_count"
}
var=$(get_rnd_num_eq_dis -100 100) # Call the function
echo "$var" # output
sleep 2

备注:它看起来可以在大于+-32000的范围内使用

最新更新