Board logo

标题: [数值计算] 批处理生成指定范围内的随机数 [打印本页]

作者: qq362220083    时间: 2009-3-19 06:00     标题: 批处理生成指定范围内的随机数

  1. :rndnum
  2. set lnum=%~1
  3. set unum=%~2
  4. if "%lnum%" == "" (set lnum=1)
  5. if "%unum%" == "" (set unum=9)
  6. if %lnum% GTR %unum% (set lnum=%unum%&set unum=%lnum%)
  7. set /a rnd=(%unum% - %lnum% + 1) * %random% / 32768 + %lnum%
  8. goto :eof
复制代码
其中%random%的范围为0-32767,那么这个随机小数就可以通过除以32768获得,剩下的取整不需要人工干预,批处理就自动解决了。

生成随机数的范围:大于等于最小值,小于等于最大值

为了确定是否稳定,测试了10W次
测试代码如下:
  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. :s
  4. cls
  5. for /l %%a in (1,1,100000) do (
  6. call :rndnum
  7. echo. %%a 中间结果:!rnd!
  8. if 1!rnd! GTR 19 (call :over !rnd!)
  9. if 1!rnd! LSS 11 (call :over !rnd!)
  10. )
  11. echo.
  12. echo.
  13. echo.计算结束!
  14. echo.
  15. echo.
  16. pause
  17. exit
  18. :rndnum
  19. set lnum=%~1
  20. set unum=%~2
  21. if "%lnum%" == "" (set lnum=1)
  22. if "%unum%" == "" (set unum=9)
  23. if %lnum% GTR %unum% (set lnum=%unum%&set unum=%lnum%)
  24. set /a rnd=(%unum% - %lnum% + 1) * %random% / 32768 + %lnum%
  25. goto :eof
  26. :over
  27. cls
  28. echo.
  29. echo.
  30. echo. 调试结果:%~1
  31. echo.
  32. echo.
  33. pause
  34. goto :eof
复制代码

作者: 随风    时间: 2009-3-19 11:24

不用这么复杂吧,比如:15至41之间的随机数
set /a w=%random%%%27+15
作者: Batcher    时间: 2009-3-19 12:14     标题: 回复 2楼 的帖子

可能楼主的意思是要把这个功能给函数化吧。
但我觉得函数里面不必做那么多容错处理,在函数说明里面写清楚如何调用就行了,如果用户不按照正确的方法来调用,那就活该他出错了。
作者: qq362220083    时间: 2009-3-19 18:08

其实关键的就这一句,常做软件开发的应该都知道,这个是生成指定范围内随机数的公式
只不过那个0-1之间的随机小数通过%random%/32768生成。

  1. set /a rnd=(%unum% - %lnum% + 1) * %random% / 32768 + %lnum%
复制代码


这个做成函数了,使用 call :rndnum 最小值 最大  调用,若不传参数,默认生成1-9之间的随机数
作者: Batcher    时间: 2009-3-19 19:10     标题: 回复 4楼 的帖子

批处理中,/表示整除,请问你的“随机小数”是如何生成的呢?我咋没看到小数点呢?
作者: myzwd    时间: 2009-3-20 10:23     标题: 回复 5楼 的帖子

batchar你回答的干吗那么幽默啊。呵呵
作者: qq362220083    时间: 2009-3-31 14:50     标题: 回复 5楼 的帖子

在P中,计算顺序是先算括号,然后按照优先级从左往右计算

这样,上面的
  1. set /a rnd=(%unum% - %lnum% + 1) * %random% / 32768 + %lnum%
复制代码
1。算括号里面的加减
2。然后是乘以随机数
3。再计算除法,这样生成的就是个整数,范围在最大数和0之间

4。此时加上最小数,范围就被定下来了。

这个算法变相取得了随机小数,呵呵。
另外,这个32768个人感觉有点不对劲,貌似应该是32767,这样结果才不会偏小。
看了看随机数的范围,越看越觉得应该是32767。大家再研究吧,呵呵

[ 本帖最后由 qq362220083 于 2009-3-31 14:51 编辑 ]
作者: Batcher    时间: 2009-3-31 22:25     标题: 回复 7楼 的帖子

你说的“随机小数”是指随机的比较小的整数,而不是随机小数,是这样吗?
作者: qq362220083    时间: 2009-4-10 05:11

头大!!!
  1. set /a rnd=(%unum% - %lnum% + 1) * %random% / 32768 + %lnum%
复制代码
中,按照咱们平时的随机数,应该是像下面这样
  1. set /a rnd=(%unum% - %lnum% + 1) * (%random% / 32768) + %lnum%
复制代码
但由于乘法和除法处于同一优先级,因此,先计算除法和先计算乘法的结果一样。这个是理论上的。
但是,在批处理中,无法计算小数,批处理会把结果中的小数直接舍掉。若按照正常的计算顺序,会造成结果永远都是最小值,因为
  1. %random% / 32768
复制代码
永远是0-1之间的小数,批处理总是舍掉小数变成0,任何数乘以0结果不用我重复吧

因此我就按照数学上的四则运算法则,把计算顺序变为先计算乘法,后计算除法,这样的结果同样会被批处理省略掉小数,但这却正好帮了忙,省去了最后取整的过程。

还有,这个随机结果会比正常结果偏小0.5左右,理论上的。我想大家不需要那么精确吧,呵呵

另外,Batcher,你要是还不明白,我就无能为力了,真的怀疑你的小学数学老师。。。

[ 本帖最后由 qq362220083 于 2009-4-10 05:19 编辑 ]
作者: Batcher    时间: 2009-4-10 10:07     标题: 回复 9楼 的帖子

以我的智商,只能做出8楼的理解,无法达到你那样的认知境界,实在是惭愧啊。
9楼的讲解很好,嗯,我在大约两年前也给别人讲过类似的内容。
噢,对了,千万别忘记替我向你的小学数学老师们致以崇高的敬意,他们培养出了这么优秀的学生,真实羡煞旁人呐。
作者: qq362220083    时间: 2010-3-16 17:03

好久没来了,今天来转转,看到这个帖子。呵呵,心里有点感触了。。。


使用%random%取得的随机数范围在0 和 32767之间

%random% / 32767  就是范围在0-1之间的小数

但是批处理中,对于数学运算,若结果是小数,则自动忽略小数,只取结果中的整数部分

因此%random% / 32768在批处理中只会得到0

但四则运算法则中,乘法和除法是同一优先级,同样批处理也遵守。所以,可以乘以一个随机整数,然后除以随机整数的最大值,得到一个随机范围在0与(最大值-最小值)之间的整数。最后加上最小值!

例子:

得到1-10之间的随机数
1:10 - 1 + 1 =10
2:10 * %random%    返回的是0~327670之间的整数
3:(0~327670)/32768    返回的是0~9之间的整数,算术的最小值最大值的获取方法分别是用范围的最小值和最大值除以32768,得到的分别是算术的最小值和最大值
4:加上最小值1,返回的是1~10

[ 本帖最后由 qq362220083 于 2010-3-16 17:25 编辑 ]
作者: 封印    时间: 2010-4-17 12:04

嗯,楼主解释非常清楚了,不过例子的思路让人感到有点复杂。
作者: dosbat    时间: 2011-4-20 11:05

呵呵 看了楼上这么多详细的解释,我说下我的看法
依据那个公式可以将产生确定范围的随机数的方法分解成以下几步:
1.确定范围:max-min+1
2.扩大这个范围max-min+1)*%random%   
3.再缩小范围:(max-min+1)*%random%/32768 这样就产生了0~max-min+1之间的范围
4最后来个平移:(max-min+1)*%random%/32768+min 这样就产生了min~max之间的随机数了
疑问:这种方法跟%random%%%max+min是否存在不同之处?望高手指点下
作者: techon    时间: 2011-4-22 21:30

贴个除法函数吧
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. call :_div %RANDOM% 32768
  4. echo %quo%
  5. call :_div %RANDOM% 32768
  6. echo %quo%
  7. call :_div %RANDOM% 32768
  8. echo %quo%
  9. call :_div %RANDOM% 32768
  10. echo %quo%
  11. call :_div %RANDOM% 32768
  12. echo %quo%
  13. call :_div %RANDOM% 32768
  14. echo %quo%
  15. call :_div 32767 32768
  16. echo %quo%
  17. goto :eof
  18. rem 除法子程序开始
  19. :_div
  20.   if "%1"=="" (echo 请输入被除数(参数 %%^1)&goto :EOF)
  21.   if "%2"=="" (echo 请输入除数(参数 %%^2)&goto :EOF)
  22.   set /a Maxd=2147483647, scp=0, ded=%1, dvr=%2&set quo=
  23.   if %dvr% equ 0 (echo 错误,除数为零!&goto :EOF)
  24.   if %ded% equ 0 (set quo=0&goto :EOF)
  25.   if "%ded%"=="%1" (
  26.     if not "%dvr%"=="%2" echo 参数 %%^2 输入错误或数值超限&goto :EOF
  27.   ) else (
  28.     echo 参数 %%^1 输入错误或数值超限
  29.     if not "%dvr%"=="%2" echo 参数 %%^2 输入错误或数值超限&goto :EOF
  30.   )
  31.   :divbg
  32.   set /a quo=%ded%/%dvr%, rdd=quo*dvr
  33.   if %rdd% neq %ded% (
  34.     if %ded% leq %Maxd:~0,-1% (
  35.       set ded=%ded%0&set /a scp+=1&goto :divbg
  36.     )
  37.   )
  38.   if %quo% equ 0 goto :EOF
  39.   if %scp% neq 0 (
  40.     if "!quo:~-%scp%!"=="!quo!" (
  41.       set quo=00000000%quo%&set quo=0.!quo:~-%scp%!
  42.     ) else (
  43.       set quo=!quo:~0,-%scp%!.!quo:~-%scp%!
  44.     )
  45.   )
  46. goto :EOF
  47. rem End_div
复制代码

作者: applba    时间: 2011-4-28 02:43

这个确实很好用……
set a=(!random!+1)%%(!ramdom!+1)
作者: cjiabing    时间: 2011-5-3 10:57

9# qq362220083
我们不学好数学真是悲哀!
其实,这是一个有名的数学算法,具体作者就不记得了。
虽然我数学非常差,但我小时候接触过比较多的数学游戏,自己还专门买过一本数学游戏的书,玩过好多数学游戏,比如如何推算100天后是星期几,如何知道魔术师手中的筛子数……
向懂数学的人致敬!他们都是聪明的人。




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2