JS更随机的随机数
一.问题背景
一个二维平面上有一群NPC,每一回合可以随机向上/下/左/右任一方向走1步,有单位碰撞体积(NPC位置不能重合)
规则就这么简单,初始情况下这群NPC是被人工均匀分布在二维平面上的,运行N个回合后发现所有NPC都集中在了左下角。。怎么会这样,说好的随机呢?
二.分析
现有的实现是这样的:
根据NPC的当前位置判断得到可以去的位置,把结果存放在一维数组arr里
P.S.上/下/左/右最多4个点(周围空荡荡的),最少0个点(被围起来了)
生成[0, arr.length – 1]内的一个随机数,作为目标位置索引值index
// 生成随机数[min, max]
w.Util.rand = function(min, max) { return Math.round(Math.random() * (max - min) + min);
}控制NPC移动到arr[index]的位置
逻辑应该是没有问题的,可是为什么运行结果是NPC都跑到左下角开会去了呢?等等,为什么是左下而不是其它角角?
因为实现第一步的时候是按照上 -> 下 -> 左 -> 右的顺序判断的,最后都去了左下角,说明向上和向右的概率太小了(生成随机数的函数rand是没问题的,确实能得到[min, max]的数)
问题的根源是Math.random()不给力,生成[0, 1)之间的小数,取到0和靠近1的值概率很小,所以rand()函数生成的随机数取到min和mix的概率也很小,向上/向右的可能性也就小了
三.解决方案
既然取到min和max的概率很小,中间概率比较均匀,那好办,切掉这两个值就好了。具体实现如下:
function randEx(min, max) {
var num;
var maxEx = max + 2; // 扩大范围到[min, max + 2],引入两个多余值替换min/max
do{
num = Math.round(Math.random() * (maxEx - min) + min);
num--;
} while (num < min || num > max); // 范围不对,继续循环
return num;
}
值得一提的是上面的加2减1比较巧妙,能够恰好排除min和max
四.运行结果
JS中Math.random()返回值的概率差异可能比你想象的要大些,在实际应用中是不可接受的
测试代码如下:
// 生成随机数[min, max]
w.Util.rand = function(min, max) { return Math.round(Math.random() * (max - min) + min);
} // 生成更随机的随机数[min, max]
function randEx(min, max) { var num;
var maxEx = max + 2; // 扩大范围到[min, max + 2],引入两个多余值替换min/max do{ num = Math.round(Math.random() * (maxEx - min) + min);
num--;
} while (num < min || num > max); // 范围不对,继续循环 return num;
} function testRand(times, fun) { var arr = [1, 2, 3, 4];
var count = [];
var randVal;
for (var i = 0; i < times; i++) { // 获取[0, 3]的随机数
randVal = fun(0, arr.length - 1);
// 记录次数
if (typeof count[randVal] !== "number") { count[randVal] = 0;
}
count[randVal]++;
} console.log(count);
} console.log("100 times");
testRand(100, w.Util.rand); // 之前的实现
testRand(100, randEx); // 改进过的实现 console.log("1000 times");
testRand(1000, w.Util.rand); // 之前的实现
testRand(1000, randEx); // 改进过的实现 console.log("10000 times");
testRand(10000, w.Util.rand); // 之前的实现
testRand(10000, randEx); // 改进过的实现 console.log("100000 times");
testRand(100000, w.Util.rand); // 之前的实现
testRand(100000, randEx); // 改进过的实现
运行结果如下:

看到了吧,效果还是很不错的
后话
理论上Java的Math.random(),C#的next可能也存在这个问题,这里就没有必要验证了,因为randEx函数的思想(加2减1,嫌效果不好还可以加4减2、加6减3……直到满意为止)是通用的
JS更随机的随机数的更多相关文章
- js 生成随机炫彩背景
在浏览 https://ghost.org/xxxx/ 时. 可以使用 background-size: cover; 加上很小的像素图,放大后实现炫彩背景效果. 使用 js canvas 随机生成小 ...
- JS生成随机字符串的多种方法
这篇文章主要介绍了JS生成随机字符串的方法,需要的朋友可以参考下 下面的一段代码,整理电脑时,记录备查. <script language="javascript"> ...
- JS实现随机颜色的3种方法与颜色格式的转化
JS实现随机颜色的3种方法与颜色格式的转化 随机颜色和颜色格式是我们在开发中经常要用到的一个小功能,网上相关的资料也很多,想着有必要总结一下自己的经验.所以这篇文章主要介绍了JS实现随机颜色的3种 ...
- js 生成32位随机数,可用于微信支付流水号(前端生成)
$(function () { /*生成32位随机流水号*/ /*默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1*/ var $chars = 'ABCDEFGHJKMNPQRSTWXYZ ...
- JS中实现种子随机数
参数: 详谈JS中实现种子随机数及作用 我在Egret里这么写... class NumberTool{ /**种子(任意默认值5)*/ public static seed:number = 5; ...
- js生成随机固定长度字符串的简便方法
概述 碰到一个需求:用js生成固定长度的字符串.在网上查了很多资料,网上的方法都比较麻烦.我自己灵光一现,实现了一个比较简单的方法.记录下来,供以后开发时参考,相信对其他人也有用. js生成随机字符串 ...
- js获取100个随机数存入数组
. //js获取100个随机数存入数组 $(function () { var arr = []; ; var str = ""; ) { , ); ) { arr[num] = ...
- js实现随机选取[10,100)中的10个整数,存入一个数组,并排序。 另考虑(10,100]和[10,100]两种情况。
1.js实现随机选取[10,100)中的10个整数,存入一个数组,并排序. <!DOCTYPE html> <html lang="en"> <hea ...
- js图片随机切换
使用js做到随机切换图片 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...
随机推荐
- centos 6 initctl
在centos6中有initctl 可以启动tty等.此命令在 upstart-0.6.5-10.el6.x86_64 rpm包中 或者 mingetty 命令启动 tty #initctl star ...
- dubbo问题总结
1.dubbo序列化数据丢失问题.dubbo的返回结果是对象,那么必须要实现对象中需要返回的数据的get方法. 2.dubbo序列化问题.
- 使用history.back()出现"警告: 网页已过期的解决办法"
原因: 表单提交页面中使用了 session_start 函数.由于我们后退浏览的是缓存页,而该函数会强制当前页面不被缓存. 解决: PHP: 此提示出现在一个POST提交的页面,点到其它页面后,通过 ...
- 项目支持Servlet3.0的新特性
一.Servlet3.0介绍 Servlet3.0是Java EE6规范的一部分,Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中进行Servlet的部署描述 ...
- Jquery实现简单到计时功能(setTimeout,setInterval)
要实现一个标签或者按钮进行5秒到计时,非常简单,直接上代码: 倒计时:<span id="timeSpan1" style="color:red;font-size ...
- vc++ 如何添加右键弹出菜单
一.创建新工程 二.编辑菜单资源 1.添加菜单 按"Ctrl+R",双击"Menu"图标 2.于菜单编辑器内编辑菜单 四.添加代码(红色部分) void CCM ...
- 写一个ajax程序就是如此简单
写一个ajax程序就是如此简单 ajax介绍: 1:AJAX全称为Asynchronous JavaScript and XML(异步JavaScript和XML),指一种创建交互式网页应用的网页开发 ...
- Python全栈--7模块--random os sys time datetime hashlib pickle json requests xml
模块分为三种: 自定义模块 内置模块 开源模块 一.安装第三方模块 # python 安装第三方模块 # 加入环境变量 : 右键计算机---属性---高级设置---环境变量---path--分号+py ...
- 第三章 springboot + jedisCluster
如果使用的是redis2.x,在项目中使用客户端分片(Shard)机制.(具体使用方式:第九章 企业项目开发--分布式缓存Redis(1) 第十章 企业项目开发--分布式缓存Redis(2)) 如果 ...
- Android测试——adb命令
Adb (Android Debug Bridge)起到调试桥的作用. 通过adb我们可以在Eclipse中方便通过DDMS来调试Android程序.adb采用监听Socket TCP 5554等端口 ...