JS随机数实战指南:小数生成与防重复方法
哎,你有没有遇到过这种情况?明明用JS写了个抽奖程序,用户总说"黑幕!我点了20次都没中奖!" 说实话,这可能不是用户运气差,而是你的随机数生成出了问题!今天就带你从零开始搞懂这个看似简单实则暗藏玄机的基础功能。
(偷偷告诉你,很多号称"新手如何快速涨粉"的营销活动,最后翻车都是栽在随机数逻辑上)
一、随机数到底怎么来的?
咱们先来点最基础的。JS里有个叫??Math.random()?? 的家伙,它就像个魔术师,每次都能给你变出个0到1之间的小数。比如说:
javascript复制console.log(Math.random()) // 可能输出0.123456
不过啊,这个数字永远不包括1。就像你去超市买鸡蛋,货架上摆着0到1的鸡蛋,但最后一个鸡蛋永远摸不到,气不气人?
二、想要带小数点的随机数?
举个真实案例:有个做电商的朋友要搞"满100减X元"的活动,X得是5.5、8.8这种吉利数。这时候就需要??定制范围的小数随机数??了。
??核心公式:最小值 + (最大值 - 最小值) * Math.random()??
举个栗子,想要5到10之间的随机数:
javascript复制let randomNum = 5 + (10 -5)*Math.random() console.log(randomNum) // 可能是7.3321
不过这里有个坑!如果你想保留两位小数,直接四舍五入可能会出问题:
javascript复制// 错误示范(会导致末尾小数不均匀) let num = (5 + 5*Math.random()).toFixed(2) // 正确姿势(先乘后除) let num = Math.floor(500 + 500*Math.random())/100
三、生成整数的三种姿势
搞过抽奖的都知道,整数随机数才是重灾区。这里给你三个常用方法对比:
方法 | 代码示例 | 适用场景 | 坑点提醒 |
---|---|---|---|
向下取整 | Math.floor(Math.random()*10) | 普通抽奖 | 最低值可能被遗漏 |
四舍五入 | Math.round(Math.random()*9) | 评分系统 | 边界值概率翻倍 |
向上取整 | Math.ceil(Math.random()*10) | 随机序号生成 | 可能包含0值 |
举个真实翻车案例:某App的"转盘抽奖"用round方法,导致头奖概率是其他奖项的两倍,被用户告上法庭!
四、防重复的三大绝招
这才是今天的重头戏!我见过太多人用下面这种笨办法:
javascript复制let usedNumbers = [] function getUniqueRandom(){ let num = 生成随机数 while(usedNumbers.includes(num)){ num = 生成随机数 } return num }
这方法在数据量大的时候,手机分分钟卡死给你看!
??推荐这三个靠谱方案:??
- ??洗牌算法??(就像打扑克牌)
javascript复制// 生成1-100的数组 let pool = [...Array(100).keys()].map(x=>x+1) // 洗牌操作 for(let i=pool.length-1; i>0; i--){ let j = Math.floor(Math.random()*(i+1)); [pool[i], pool[j]] = [pool[j], pool[i]] } // 使用时按顺序取
- ??位运算去重??
javascript复制let used = 0 function getUnique(){ let num do { num = 1 + Math.floor(Math.random()*31) } while((used & (1 << num)) !== 0) used |= (1 << num) return num } // 注意:这方法最多存31个数字,适合少量需求
- ??时间戳+随机数??
javascript复制function getUnique(){ return Date.now() % 1000 + Math.random() } // 注意:高并发时可能重复,要加锁机制
五、实战中的高频问题
??Q:我生成的验证码为什么老重复???
A:你可能在用Math.round!试试这个方法:
javascript复制// 生成4位不重复数字验证码 let arr = [] while(arr.length <4){ let num = Math.floor(Math.random()*10) if(!arr.includes(num)) arr.push(num) } console.log(arr.join('')) // 比如"3728"
??Q:为什么我的抽奖程序在安卓机上特别卡???
A:大概率是用了递归检测重复!改用预生成池+洗牌算法,性能能提升80%
??Q:随机小数总是0.123这样的规律数字???
A:Math.random()本身是伪随机,需要更安全的方案:
javascript复制// 浏览器安全随机数(适合抽奖等敏感场景) let array = new Uint32Array(1) window.crypto.getRandomValues(array) console.log(array[0]/4294967295)
最后说句大实话,很多教程只会教你写代码,但??真正重要的是理解背后的数学原理??。就像你知道1+1=2还不够,得明白为什么不能等于3。下次看到别人代码里的随机数逻辑,别急着复制粘贴,先想想——这个写法会不会导致我家App被用户骂?毕竟,多写多试才是编程的真谛啊!
本文由嘻道妙招独家原创,未经允许,严禁转载