【问题标题】:How to improve the uniformly distributed of a given random function to generate uniformly distributed numbers? [closed]如何提高给定随机函数的均匀分布以生成均匀分布的数? [关闭]
【发布时间】:2021-05-26 17:45:47
【问题描述】:

这个问题与 Debian 或 Ubuntu 等 Linux、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。

【问题讨论】:

  • RANDOM=$(date +%s) ?
  • 当您将 statement 评估为$(statement) 时,它会在具有自己的随机种子和相应的伪随机序列的子shell 中进行评估。所以我建议你在主shell中获取随机值并将其传递给函数进行规范化。
  • 您的问题反映了关于 PRNG 和种子的概念错误。所有 PRNG 都是从一个状态前进到下一个状态的算法,并且由于所涉及的位数是有限的,最终你会重复一个状态,然后它一直都是重复的。换句话说,所有 PRNG 序列都可以被视为大循环。种子用于设置初始状态,即它所做的只是选择循环的入口点。没有种子使 PRNG 比任何其他种子“更随机”。随机性的模仿内置于状态转换算法中,它不依赖于种子。
  • no Terminal 5.1 -> 没有 bash 5.1
  • 请不要破坏您自己的帖子。当您在此处发布时,即表示您授予 SO 在 CC-by SA 4.0 下分发内容的权利。任何破坏行为都将被撤销。

标签: linux bash function random random-seed


【解决方案1】:

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

因此到目前为止还没有 SRANDOM 可以使用。

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

Sooo 用自己的语义编写自己的 SRANDOM。例如:

srandom() {
   # take random number from /dev/urandom
   # we take only just 4 bytes - one 2^32 number
   printf "%d\n" "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 中做到这一点,同时将随机性保持在正常水平。我怀疑输入会很快耗尽。
    • 您可以从 urandom 读取一个字节。您必须忽略 read 退出状态,因为该字节可能是零字节或换行符。
    • 然后检查该字节是否为数字。如果不是,请重复上一步。
    • 将此类算法视为 0-9 范围内的随机数生成器。根据这些数字构建更大的数字。
  • 然后开发自己的大数库,使用算术扩展作为“后端”,用 bash 编写。
    • 似乎毫无意义,因为bc 很常见。
    • 这将像往常的大型库一样工作。
    • 我建议将数字存储为最大 2^16 的数字数组。为了获得灵感,请研究用 C 和 C++ 语言编写的类似库,并将其转换为 bash。

【讨论】:

【解决方案2】:

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

所以你需要播种和使用主 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

【讨论】:

    【解决方案3】:

    当问题中的代码和 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的范围内使用

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 2021-12-28
      • 2014-03-02
      • 2013-07-22
      相关资源
      最近更新 更多