AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 424715
Accepted
sci9
sci9
Asked: 2018-02-17 19:59:07 +0800 CST2018-02-17 19:59:07 +0800 CST 2018-02-17 19:59:07 +0800 CST

Bash:如何使用 $RANDOM 生成随机浮点数

  • 772

是否可以使用整数随机生成器 $RANDOM 生成具有特定精度和特定范围的实随机数?例如,我们如何生成 0 到 1 之间的 4 精度实数?

0.1234
0.0309
0.9001
0.0000
1.0000

一个简单的解决方法:

printf "%d04.%d04\n" $RANDOM $RANDOM
bash shell
  • 6 6 个回答
  • 15759 Views

6 个回答

  • Voted
  1. Best Answer
    Kusalananda
    2018-02-18T02:51:11+08:002018-02-18T02:51:11+08:00
    awk -v n=10 -v seed="$RANDOM" 'BEGIN { srand(seed); for (i=0; i<n; ++i) printf("%.4f\n", rand()) }'
    

    这将n在 [0,1) 范围内输出四位小数的随机数(示例中为 10)。它使用rand()in 函数awk(不是标准awk的,但由最常见的awk实现实现)返回该范围内的随机值。随机数生成器由 shell 的$RANDOM变量播种。

    当一个awk程序只有BEGIN块(并且没有其他代码块)时,awk不会尝试从其标准输入流中读取输入。

    在任何 OpenBSD 系统(或具有相同jot实用程序的系统,最初在 4.2BSD 中)上,以下将生成指定的 10 个随机数:

    jot -p 4 -r 10 0 1
    
    • 11
  2. A.Ellett
    2018-08-04T22:49:21+08:002018-08-04T22:49:21+08:00

    正如另一个答案中所指出的,您可以使用其他实用程序来生成随机数。在这个答案中,我将资源限制为$RANDOM和一些基本的算术函数。

    对于浮点数,尝试类似

    printf '%s\n' $(echo "scale=8; $RANDOM/32768" | bc )
    

    这将为您提供最佳精度,因为$RANDOM仅生成 0 到 32767 之间的数字。(包括 32767!)但是,我还通过调用bc.

    但在继续之前,我想看看浮点数的精度和范围这两个问题。之后,我将研究如何生成整数范围(如果您可以生成整数,您可以稍后将它们除以得到小数,如果您希望使用您喜欢的任何实用程序来完成此操作。)

    精确

    采用 的方法$RANDOM/32768,由于$RANDOM生成从 0 到 32767 的值,因此 的结果$RANDOM/32768同样将是有限多个值。换句话说,它仍然是一个离散的随机变量(使用计算机,你永远无法摆脱这个事实)。考虑到这一点,您可以使用printf.

    如果您想要更精细地覆盖区间,您可以开始考虑以 32768 为基数。因此,理论上$RANDOM + $RANDOM*32768应该为您提供 0 到 1,073,741,823 之间的均匀分布。但是,我怀疑命令行能否很好地处理这种精度。与此特定案例有关的几点:

    • 两个独立的、均匀分布的随机变量之和,通常不均匀。在这种情况下,至少从理论上讲(见第三点),它们是。
    • 不要以为你可以简化$RANDOM + $RANDOM*32768 = $RANDOM * ( 1 + 32768 )。这两次发生$RANDOM实际上是两个不同的事件。
    • 我不太了解如何$RANDOM生成以知道像这样调用它两次是否会真正生成两个独立的随机事件。

    范围

    让我们考虑一下$RANDOM/32768。如果你想要一个范围内的数字,比如说[a,b),那么

    $RANDOM/32768*(b-a) + a
    

    将使您进入所需的范围。

    整数值的生成

    [0,b)首先,考虑在b小于之间生成随机数32768。考虑乘积q*b,其中q是 的整数部分32768/b。那么你可以做的是生成0到32767之间的随机数,但丢弃那些大于或等于的随机数q*b。呼叫由此产生的号码G。则G落在 0 到 的范围内,q*b分布均匀。现在,应用模运算将该值缩减到所需范围:

    G % b
    

    注意,随机生成一个数字如下

    $RANDOM % b
    

    不会创建均匀分布,除非b恰好是 的除数之一32768。

    为此编写一个 bash 脚本

    q*b如上所述的计算听起来很痛苦。但事实并非如此。您可以按以下方式获取它:

    q*b = 32768 - ( 32768 % b )
    

    在 Bash 中,您可以使用

    $((32768 - $((32768 % b)) ))
    

    以下代码将生成范围内的随机数0..b(不包括b)。 b=$1

    m=$((32768 - $((32768 % $1)) ))
    a=$RANDOM
    while (( $a > $m )); 
    do
        a=$RANDOM
    done
    a=$(($a % $1))
    printf "$a\n"
    

    附录

    从技术上讲,几乎没有理由与之合作

    m=$((32768 - $((32768 % $1)) ))
    

    以下将完成同样的事情

    a=$RANDOM
    while (( $a > $1 )); 
    do
        a=$RANDOM
    done
    printf "$a\n"
    

    这是更多的工作,但计算机速度很快。

    生成更大范围内的整数

    我会让你弄清楚这一点。需要小心,并且在某些时候您必须考虑计算机在处理算术运算时的内存限制。

    最后说明

    接受的答案不会创建一个 0 到 1 的随机数。

    要查看此内容,请尝试以下操作

    $ for i in {1..1000}; do echo .$RANDOM; done | awk '{ a += $1 } END { print a }'
    

    对于真正均匀的分布,[0,1)您应该看到接近0.500.

    但正如您通过运行上面的代码片段所看到的那样,您将得到类似314.432or的东西322.619。由于是 1000 个数字,因此平均值为.322. 这个生成数字序列的真实平均值是.316362

    您可以使用 perl 脚本获得这个真实的平均值

      perl -e '{ $i=0;  
                 $s=0; 
                 while ( $i<=32767 ) 
                   { 
                     $j = sprintf "%.5f", ".$i"; 
                     $j =~ s/^0\.//; 
                     print "$j\n"; 
                     $s += $j; 
                     $i++ 
                   }; 
                 printf "%.5f\n", $s/32767; 
               }' 
    

    我在这里添加整数是为了帮助您了解这种使用方法如何.$RANDOM没有做您最可能希望它做的事情。换句话说,想想哪些整数正在生成,哪些整数被完全遗漏了。跳过了相当多的数字;不少是翻倍的。

    • 10
  3. user232326
    2018-08-05T00:47:25+08:002018-08-05T00:47:25+08:00

    在 shell 的 printf 能够理解%a格式(bash ksh zsh 等)并因此能够执行内部基本更改(十六进制 -> 十进制)的系统上([0,1)范围从 0.00003 到 0.99997):

    printf '%.5f\n' "$(printf '0x0.%04xp1' $RANDOM)"
    

    您甚至可以通过组合更多调用来使用更多数字$RANDOM(从 0.000000001 到 0.999999999)

    printf '%.9f\n'  "$(printf '0x0.%08xp2' $(( ($RANDOM<<15) + $RANDOM )))"
    

    内部(外壳)“$RANDOM”算法基于线性反馈移位寄存器(LFSR)。这些不是加密安全伪随机数生成器 (CSPRNG)。更好的选择是使用/dev/urandom设备中的字节。这将需要调用外部八进制或十六进制转储。

    $ printf '%.19f\n' "0x0.$(od -N 8 -An -tx1 /dev/urandom | tr -d ' ')"
    0.7532810412812978029
    
    $ printf '%.19f\n' "0x0.$(hexdump -n 8 -v -e '"%02x"' /dev/urandom)"
    0.9453460825607180595
    

    获得浮点数的一个非常简单(但不统一)的解决方案是:

    printf '0.%04d\n' $RANDOM
    

    一种使其在范围内统一的方法[0,1)(不包括1):

    while a=$RANDOM; ((a>29999)); do :; done; printf '0.%04d\n' "$((a%10000))"
    
    • 7
  4. αғsнιη
    2018-02-17T20:05:26+08:002018-02-17T20:05:26+08:00

    利用$(( ( RANDOM % N ) + MIN ))

    N用您要生成的最小数字替换MAX 数字和 MIN。(N因为 MAX 是唯一的,N+1所以要同时包含 MAX,MIN)。

    或者,您可以$(shuf -i MIN-MAX -n 1)改用。

    来自man shuf:

    -i, --input-range=LO-HI
        treat each number LO through HI as an input line
    -n, --head-count=COUNT 
        output at most COUNT lines
    

    这里-n 1的shuf意思是只生成一个随机数。

    这将使用前导零生成0~9999之间的随机数printf(结果,数字1是唯一的)。

    printf "0.%04d\n" $(( RANDOM % 1000 ))
    0.0215
    
    • 4
  5. Andrea993
    2019-01-03T13:44:56+08:002019-01-03T13:44:56+08:00

    在 bash

    bc -l <<< "scale=4 ; $((RANDOM % 10000 ))/10000"
    

    1/10000你的随机精度和4数字你的输出精度在哪里

    • 2
  6. Stéphane Chazelas
    2018-08-05T23:51:11+08:002018-08-05T23:51:11+08:00

    zsh在其模块中有一个算术函数(标准函数rand48()的包装器):erand48()zsh/mathfunc

    zmodload zsh/mathfunc
    printf '%.4f\n' $((rand48()))
    

    虽然$RANDOM是 15 位、伪随机且可重现,bash但 5.1+ 具有更安全的 32 位整数$SRANDOM,基于可用的真正随机源。它不支持浮点运算,但至少您可以使用它来播种awk的伪随机生成器(否则默认情况下使用非常可预测的结果time()):

    echo "$SRANDOM" | awk '
      {
        srand($1)
        for (i = 0; i < 20; i++)
          printf "%.4f\n", rand()
      }'
    

    (请记住,它仍然只有 32 位熵,并且awk基于该种子进行确定性伪随机生成)

    • 1

相关问题

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • 如何将带有〜的路径保存到变量中?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve