Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

抽奖功能修改建议 #70

Closed
wpscott opened this issue Aug 9, 2020 · 8 comments
Closed

抽奖功能修改建议 #70

wpscott opened this issue Aug 9, 2020 · 8 comments

Comments

@wpscott
Copy link

wpscott commented Aug 9, 2020

  1. 改用new Date() % Array.lengthwindow.crypto.getRandomValues获取随机数
  2. 增加继续抽奖功能来排除已中奖用户
@Sokwva
Copy link
Collaborator

Sokwva commented Aug 9, 2020

  1. 改用new Date() % Array.lengthwindow.crypto.getRandomValues获取随机数
  2. 增加继续抽奖功能来排除已中奖用户

收到

@NocKit
Copy link

NocKit commented Aug 9, 2020

随机数用Math.floor会有问题,我觉得用string来截取比较好
parseInt((Math.random() * (max - min) + min).toString().split('.')[0])

当然最好是random.org的api更好了

@Sokwva
Copy link
Collaborator

Sokwva commented Aug 9, 2020

随机数用Math.floor会有问题,我觉得用string来截取比较好
parseInt((Math.random() * (max - min) + min).toString().split('.')[0])

当然最好是random.org的api更好了

问题2我已经提交了pr(>д<)

@SingSky
Copy link

SingSky commented Aug 9, 2020

昨天的抽奖中:

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楼,都出现了连续抽中的情况,也引发了弹幕对抽奖机随机性的质疑,随机数生成方式应当需要修改。

@Sokwva
Copy link
Collaborator

Sokwva commented Aug 12, 2020

先写入计划了,群主和我最近比较忙,有时间了慢慢迁移吧

@wpscott
Copy link
Author

wpscott commented Sep 3, 2020

最近有空摸鱼研究了一下建议一

在线随机数生成器

参考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)) + minMath.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了。

验证

rnd generator

可以看到1出现的次数明显多于0和2。

结论

综上,助手抽奖使用的随机数算法可以认为是没有问题的,只需要增加一个排除已中奖用户的功能即可。

关于Math.floor()

如果担心Math.floor(Math.random() * max)的取值问题,那么可以转变思路,通过打乱待抽奖评论的顺序,然后从头或尾开始一个个移除来保证随机性和公平性。

@Sokwva
Copy link
Collaborator

Sokwva commented Sep 3, 2020

最近有空摸鱼研究了一下建议一

在线随机数生成器

参考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)) + minMath.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了。

验证

rnd generator

可以看到1出现的次数明显多于0和2。

结论

综上,助手抽奖使用的随机数算法可以认为是没有问题的,只需要增加一个排除已中奖用户的功能即可。

关于Math.floor()

如果担心Math.floor(Math.random() * max)的取值问题,那么可以转变思路,通过打乱待抽奖评论的顺序,然后从头或尾开始一个个移除来保证随机性和公平性。

@niuchaobo

@Sokwva
Copy link
Collaborator

Sokwva commented Sep 3, 2020

最近有空摸鱼研究了一下建议一

在线随机数生成器

参考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)) + minMath.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了。

验证

rnd generator

可以看到1出现的次数明显多于0和2。

结论

综上,助手抽奖使用的随机数算法可以认为是没有问题的,只需要增加一个排除已中奖用户的功能即可。

关于Math.floor()

如果担心Math.floor(Math.random() * max)的取值问题,那么可以转变思路,通过打乱待抽奖评论的顺序,然后从头或尾开始一个个移除来保证随机性和公平性。

谢谢铁汁的验证;我们当时加入抽奖功能的理想使用场景是文章区的抽奖,文章区的抽奖当时主要是Up主定一个时间来抽奖,抽奖的次数一般只有一次,所以当时没有考虑到vup们的多次且需要去重的抽奖,代码层面的实现并没有考虑到需要去除上次抽过的Acer;再次感谢铁汁对我们的建议和验证。

@Sokwva Sokwva pinned this issue Jan 25, 2022
@Sokwva Sokwva closed this as completed May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants