一次生活引发的“Lua随机数生成”问题

本文探讨了在Lua中生成随机数的问题,从最常见的方法开始,通过多次改进,包括优化randomseed的取值,以避免短时间内生成相同的随机序列。经过二次和三次改进,实现了更随机的序列,满足随机选择需求。最后,作者指出尽管还有细微问题,但二次改进已足够满足实际使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Preface

其实是打算写个随机性语言选择器的。我和小伙伴打算每天换一门语言来对话,于是就采用随机函数的方法去帮助我们去选择!这次比较匆忙,脚本就暂且这样,以后优化,文章美化就暂时这样,以后再调整。
这个随机数生成问题目前主要是分成4个部分。最常见的,一次改进的,二次改进的和三次改进。以下主要改进的是randomseed的取值~

程序1:初始的最常见的随机数生成

-- 常见的随机数生成
math.randomseed(os.time())
for i=1, 7 do
    print(math.random())
end  

一次改进

改进的核心:
可以查看这篇文章,里面有说明random()的 seed 很小或者seed 变化很小,产生的随机序列仍然很相似。Lua 随机数生成问题,点我

核心的语句如下:

-- 该语句是作用是:将os.time()的结果反转,然后取高6位,这样seed的变化就大了,
math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 6)))

以下是用来帮助选择语言的实例代码:

-- 全局变量,在这里控制概率的大小
English = 13
Cantonese = 7
Japanese = 8
Korean = 67

-- 随机函数
function rnd()
    local ret = 0
        -- 基于系统时间的随机数种子,用这种方式防止极端时间内造成随机数相同的情况
        -- 事实上,这个还是不行,最多只是减轻症状,后文再细说)
    math.randomseed(tonumber(tostring(os.time()):reverse():sub(1, 6)))
    -- 因为这个随机函数有点不好,所以取第三个信任度比较高
    for i=1, 3 do
        n = math.random(1, 10001)
        ret = n
    end
    return ret
end

-- 对于随机函数粗来的结果进行处理,通过取余来决定哪种语言
while true do
    local number = rnd()
    if number % Cantonese == 0 then
        print("随机数为:"..number)
        print("粤语")
        break
    elseif number % English == 0 then
        print("随机数为:"..number)
        print("English")
        break
    elseif number % Japanese == 0 then
        print("随机数为:"..number)
        print("日本語")
        break
    --[[
    elseif number % Korean == 0 then
        print("随机数为:"..number)
        print("한국어")
        break
    ]]
    end
end

这个程序还是有问题,时间紧迫,先放着!先去洗澡了
其实,这个问题还是没有解决~因为,经过测试发现,在Lua5.3里面(其他版本未经测试),在极其短的时间里面,生成的随机序列仍然相同~还是不能达到根本的要求。


二次改进:

-- 调用sockt库,从而达到毫秒级精度
local socket = require("socket")
math.randomseed(socket.gettime())
while true do
    for i=1, 3 do
        n = math.random()
    end
    -- 依旧取第三个数,输出后发现差别可能随机数会有很多的差别
    -- 说明:因为socket.gettime()得到的结果是0.xxxxxxxxx级别的,无法作为程序中的种子用,所以放大
    print(math.floor(n * 1000001))
end

输出结果样例:(部分)

944548
118388
148720

863934
417030
699109
202577
950752
172985
150584
111708

793783
48523
8192
721530
558812
807733
364529
57704
950531
737050
434112
866802
155902
336599
326696

722702
992281
477198
424833

842600
675044
40556
87856
680879
236654
454290
536366
433633
319076
343280

617953
936876

输出后,发现虽然这次差别度很大,变化相差很大,可以达到随机选择语言的需求了。但是对于,红色的标记的序列来说,差别没有达到理想中的状态(我不是处女座也不是双鱼座的!


三次改进

此次改进是基于第一次改进的理念改进的,将得到的序列进行逆序取高位,这样效果应该会好很多。代码如下:

local socket = require("socket")
math.randomseed(socket.gettime())
while true do
    for i=1, 3 do
        n = math.random()
    end
    print(tonumber(tostring(math.floor(n * 1000001)):reverse()))
end

样例输出:

558083
7541
886742
27599
528329
444804
469048
986654
825257
47004
223707
696051
828321
270441
928724
265446
57508
754028
799111
724897
2945
326045
207465
184182
786509
170548
47116
888255
361378

这样就有个别几个没有连续重复的了~从统计学角度来说,有也是在允许范围的吧~(弄完这个,感觉可能没有必要!是的,感觉!其实,二次改进的蛮好的

最后,改进的实例代码如下:

-- 全局变量,在这里控制概率的大小
English = 11
Cantonese = 7
Japanese = 8
Korean = 67

-- 随机函数
function rnd()
    local socket = require("socket")
    local ret = 0

    -- 用socket.gettime()获取更加精确的时间,math.floor()取其整数部分,省略小数部分
    -- 转换成string,逆序
    -- 再转换成number
    local sockt_number = tonumber(tostring(math.floor(socket.gettime() * 1000001)):reverse())
    math.randomseed(sockt_number)
    -- 因为这个随机函数有点不好,所以取第三个信任度比较高
    for i=1, 3 do
        n = math.random(1, 10001)
        ret = n
    end
    return ret
end

-- 对于随机函数粗来的结果进行处理,通过取余来决定哪种语言
while true do
    local number = rnd()
    print("随机数为:"..number)
    if number % Cantonese == 0 then
        print("粤语")
        break
    elseif number % English == 0 then
        print("English")
        break
    elseif number % Japanese == 0 then
        print("日本語")
        break
    --[[
    elseif number % Korean == 0 then
        print("한국어")
        break
    ]]
    end
end

改进前,因为while的永真循环,程序运行时间极其短暂,所以随机数取的是一样的,取余操作都是在做无用功。改进过后,随机数改进后的程序,就可以超快地得到结果。当然了,也可以对求余操作进行改进,更快地得到求余后的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值