acfun-helper
acfun-helper copied to clipboard
抽奖功能修改建议
- 改用
new Date() % Array.length
或window.crypto.getRandomValues
获取随机数 - 增加继续抽奖功能来排除已中奖用户
- 改用
new Date() % Array.length
或window.crypto.getRandomValues
获取随机数- 增加继续抽奖功能来排除已中奖用户
收到
随机数用Math.floor会有问题,我觉得用string来截取比较好 parseInt((Math.random() * (max - min) + min).toString().split('.')[0])
当然最好是random.org的api更好了
随机数用Math.floor会有问题,我觉得用string来截取比较好 parseInt((Math.random() * (max - min) + min).toString().split('.')[0])
当然最好是random.org的api更好了
问题2我已经提交了pr(>д<)
昨天的抽奖中:
55:41 抽中 damands#353
58:21 抽中 来自非洲的猴子#245、Graven`L#43
01:21:23 抽中 lics#509 、嘚忒#59 、来自非洲的猴子#245 、深巷少女和狗#296 、C137兵库北#646 、AC娘的表弟#345
01:24:22 抽中 这个扳手#291、司马相柳#327、小爷就爱笑#578、糟糕姬#188
01:26:04 抽中 lics#509、本娘天生36D#46
01:27:03 抽中 司马相柳#327
01:27:18 抽中 一根会思考的芦苇#539
01:28:11 抽中 damands#353
01:28:25 抽中 C137兵库北#646
353,245,509,327,646楼,都出现了连续抽中的情况,也引发了弹幕对抽奖机随机性的质疑,随机数生成方式应当需要修改。
先写入计划了,群主和我最近比较忙,有时间了慢慢迁移吧
最近有空摸鱼研究了一下建议一
在线随机数生成器
参考AVUP用过的在线随机数生成器使用的random.js,采用了MersenneTwister伪随机数算法,随机数生成算法大致为
var mTwister = new MersenneTwister();
var number = Math.round( mTwister.random() * max) - min ) ) + min;
Math.random()
根据V8的博客There’s Math.random()
, and then there’s Math.random()
,Math.random()
使用的是xorshift128+,一个比MersenneTwister效率高的伪随机数算法。
比较
从代码上看助手的Math.floor(Math.random() * (max - min)) + min
和Math.round( mTwister.random() * max) - min ) ) + min
的
主要差别在于使用Math.floor()
还是Math.round()
。
因为在抽奖时min通常为0,代码可以简化为Math.floor(Math.random() * max)
和Math.round(mTwister.random() * max)
。
从概率论来看,Math.floor()
比Math.round()
要好,因为Math.round(mTwister.random() * max)
的取值范围为[0, max]
,可能导致数组越界。
测试代码
const array = Array(114);
array.fill(0);
for(let i = 0; i < 114514; i++) {
array[Math.round(Math.random() * array.length)]++;
}
可以看到array
的长度改变了,而且array[0]
的次数只有其他的一半,因为另外一半四舍五入成1了。
验证

可以看到1出现的次数明显多于0和2。
结论
综上,助手抽奖使用的随机数算法可以认为是没有问题的,只需要增加一个排除已中奖用户的功能即可。
关于Math.floor()
如果担心Math.floor(Math.random() * max)
的取值问题,那么可以转变思路,通过打乱待抽奖评论的顺序,然后从头或尾开始一个个移除来保证随机性和公平性。
最近有空摸鱼研究了一下建议一
在线随机数生成器
参考AVUP用过的在线随机数生成器使用的random.js,采用了MersenneTwister伪随机数算法,随机数生成算法大致为
var mTwister = new MersenneTwister(); var number = Math.round( mTwister.random() * max) - min ) ) + min;
Math.random()
根据V8的博客There’s
Math.random()
, and then there’sMath.random()
,Math.random()
使用的是xorshift128+,一个比MersenneTwister效率高的伪随机数算法。比较
从代码上看助手的
Math.floor(Math.random() * (max - min)) + min
和Math.round( mTwister.random() * max) - min ) ) + min
的 主要差别在于使用Math.floor()
还是Math.round()
。 因为在抽奖时min通常为0,代码可以简化为Math.floor(Math.random() * max)
和Math.round(mTwister.random() * max)
。 从概率论来看,Math.floor()
比Math.round()
要好,因为Math.round(mTwister.random() * max)
的取值范围为[0, max]
,可能导致数组越界。测试代码
const array = Array(114); array.fill(0); for(let i = 0; i < 114514; i++) { array[Math.round(Math.random() * array.length)]++; }
可以看到
array
的长度改变了,而且array[0]
的次数只有其他的一半,因为另外一半四舍五入成1了。验证
![]()
可以看到1出现的次数明显多于0和2。
结论
综上,助手抽奖使用的随机数算法可以认为是没有问题的,只需要增加一个排除已中奖用户的功能即可。
关于Math.floor()
如果担心
Math.floor(Math.random() * max)
的取值问题,那么可以转变思路,通过打乱待抽奖评论的顺序,然后从头或尾开始一个个移除来保证随机性和公平性。
@niuchaobo
最近有空摸鱼研究了一下建议一
在线随机数生成器
参考AVUP用过的在线随机数生成器使用的random.js,采用了MersenneTwister伪随机数算法,随机数生成算法大致为
var mTwister = new MersenneTwister(); var number = Math.round( mTwister.random() * max) - min ) ) + min;
Math.random()
根据V8的博客There’s
Math.random()
, and then there’sMath.random()
,Math.random()
使用的是xorshift128+,一个比MersenneTwister效率高的伪随机数算法。比较
从代码上看助手的
Math.floor(Math.random() * (max - min)) + min
和Math.round( mTwister.random() * max) - min ) ) + min
的 主要差别在于使用Math.floor()
还是Math.round()
。 因为在抽奖时min通常为0,代码可以简化为Math.floor(Math.random() * max)
和Math.round(mTwister.random() * max)
。 从概率论来看,Math.floor()
比Math.round()
要好,因为Math.round(mTwister.random() * max)
的取值范围为[0, max]
,可能导致数组越界。测试代码
const array = Array(114); array.fill(0); for(let i = 0; i < 114514; i++) { array[Math.round(Math.random() * array.length)]++; }
可以看到
array
的长度改变了,而且array[0]
的次数只有其他的一半,因为另外一半四舍五入成1了。验证
![]()
可以看到1出现的次数明显多于0和2。
结论
综上,助手抽奖使用的随机数算法可以认为是没有问题的,只需要增加一个排除已中奖用户的功能即可。
关于Math.floor()
如果担心
Math.floor(Math.random() * max)
的取值问题,那么可以转变思路,通过打乱待抽奖评论的顺序,然后从头或尾开始一个个移除来保证随机性和公平性。
谢谢铁汁的验证;我们当时加入抽奖功能的理想使用场景是文章区的抽奖,文章区的抽奖当时主要是Up主定一个时间来抽奖,抽奖的次数一般只有一次,所以当时没有考虑到vup们的多次且需要去重的抽奖,代码层面的实现并没有考虑到需要去除上次抽过的Acer;再次感谢铁汁对我们的建议和验证。