1. 主页 > 好文章

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
}

这方法在数据量大的时候,手机分分钟卡死给你看!

??推荐这三个靠谱方案:??

  1. ??洗牌算法??(就像打扑克牌)
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]]
}

// 使用时按顺序取
  1. ??位运算去重??
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个数字,适合少量需求
  1. ??时间戳+随机数??
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被用户骂?毕竟,多写多试才是编程的真谛啊!

本文由嘻道妙招独家原创,未经允许,严禁转载