不那么随机的随机数列

不那么随机的随机数列

曾经看过这样一种赌徒的策略:假设在一场赌大小的赌博游戏中,赔率是 1:1 ,而庄家不会出千,开大和开小的概率均等(皆为 50%)。赌徒一开始压一块钱,如果他压错了,那么下一次就压两块,再错继续加倍。一旦压对,赌徒永远可以保证有一块钱的进帐。并且从 1 块钱重新开始。

看起来,这种策略能保证永远包赚不赔。但实际上为什么没有人用这个方案发财呢?

放到现实中,试图采用这个策略去赌博的人,几乎都会赔的倾家荡产(当然只要是赌博,差不多都是这个结局)。不要怪运气,不要怪庄家出千,因为这个策略从一开始就注定了失败。

让我们把赌博游戏换成等价的扔硬币实验。请问,连续掷出 7 次正面的概率有多少?

稍有概率常识的人都可以心算出答案:1/128 ,也就是略小于 1% 。比 D&D 跑团时投出 20 重击要难多了(拜一下骰子大神)。

那么,谁能凭直觉说出,掷 30 次硬币,至少出现一次“连续 7 次正面”的概率有多少?我写了个小程序计算了一下,答案远大于大多数人的直觉,居然达到了 18.3% 这么高。

好了,现在把掷出正面换成压对大小。也就是说,你参加 30 次赌局,出现连续 7 次压对,或连续 7 次压错的概率并不那么的小。而且这个概率还会随着赌局次数增加,逐渐趋近于 1 。

这意味着什么?

如果你只有 128 块的赌本,在 30 次赌局中,输光的可能性居然有 18.3% 这么高。诚然,你可以运气很好,在一开始赢到一些额外的资金。但促进最初的策略所需要的进一步资金是 256 块,在 30 次赌局中是绝对不可能办到的。

赌徒可以增加自己的赌本,让自己可以承受更多的连续失败。但赌本的增加将是指数级上升的,但对提高不至于输光的概率却很有限(线形增加)。只要他在赌场上玩上一通宵,多少钱都能输干净。

赌博最终就是看谁的本钱多,而不是谁的运气更好(骰子大神啊,请不要跟我绝交。谈谈数学而已,莫要当真)。如果你赌本比不过庄家,乘早收手吧。btw, 这话是写给众多转战 A 股的朋友们的。


我想任何一个具有理性思维的人都不会对赌博有太多兴趣。想必我的 blog 的读者中这样的人居多,其实我今天主要是想谈游戏的 :) 。

我们前段开始内测了一个卡牌游戏 (注:需要内测帐号的朋友请自己去官方论坛 申请,不要找我 :) )

在测试时,同事在50 张的卡组里放了 25 张生物卡。并认为,在游戏中每次摸新的卡,是生物卡的概率是 50% 。可是在实际游戏中,几乎每局都会发生连续 5 次都摸不到生物卡的情况。

一开始,我们认为系统的伪随机函数生成的伪随机数列不够随机。后来换了一个随机数函数,情况并没有得到改善。

今天我计算了一下,如果是掷硬币实验,连续 21 次中,至少出现 5 次连续正面的概率居然达到了 49.9% 。当次数增加到 30 次后,概率有 71.4% 之高。而我们的卡牌游戏,几乎每局都会有 20 多次摸牌机会,出现连续 5 次摸不到生物卡的概率其实够大了。经常出现这种情况,还真是怪不了伪随机数列的生成算法,或是洗牌函数。

写到这里,还有人不信邪。我掏出了我的 20 面骰 。在桌上做起实验。

我们规定,投出 1-10 算小,11-20 算大。一直投下去,直到出现 5 次连续的大、而后游戏结束。最后统计一共投了多少次。在没有进行游戏之前,有人估计可能每玩一局可能会投接近 100 次;可实际结果另他失望(更接近计算结果)。

我们一共做了三组实验,分别在 22 次,24 次,31 次结束了。

如果有朋友想试试,可以用硬币或麻将用的六面骰实验。


所以说,当你在打网络游戏时,如果某天发现某件装备的凋落率,或是合成率远低于官方公布的数字。请不要抱怨自己命不好,也不要怀疑系统作弊。若让程序员们产生一个特定分布的作弊随机数列,又不那么容易被人看出规律(不够随机)出来,难度和成本(CPU 成本)比采用系统的随机数发生器要大的多。比如使用 Niederreiter Sequence

最后附一张图片,我随手用一个 C 程序生成的。程序在图片的下方:

random.png

#include <stdio.h>
#include <stdlib.h>

int
main()
{
    int i,j;
    int map[128][128];
    memset(map,0,sizeof(map));
    for (i=0;i<1000;i++) {
        map[rand()%128][rand()%128]=1;
    }

    printf("P1/n128 128/n");
    for (i=0;i<128;i++) {
        for (j=0;j<128;j++) {
            printf("%d ",map[i][j]);
        }
        printf("/n");
    }
    return 0;
}

用任何 C 编译器编译运行,再用管道输出到一个 .pbm 图片文件中即可。它生成了 2000 个伪随机数,并作为 1000 个点画在画布上。

我们可以发现,很多点都碰在了一起(一致随机分布往往呈现出的这种集束现象)。这并非随机数产生的不好,而是一种常态而已。

反过来,开发人员真的想讨好玩家,可以做一个更“均匀”的随机数列。让游戏中的各种概率发生更符合“大众的直觉”。那么,考虑使用 准随机数列 (quasi-random_sequences)。不过要注意,计算量会增加很多。而且这样的数列并不随机,只是讨好玩家而已,跟物理世界中的随机性相差甚远。

在《科学计算导论》的中译版中,把 quasi-random sequences 也翻译作拟随机数列。这里有一篇介绍性质的 paper 可以参考。

 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值