【Lua】自由小数精度的随机数

  • Post author:
  • Post category:其他




一、需求

目前存在一个需求,提供一个随机数的函数,这个函数的最小和最大值之间的精度是不等的,取他们中间的一个随机数,使用Lua自带的方法是做不到的,需要自己封装一个函数来使用。



二、解决



Lua本身的限制

Lua取随机数目前只有三种方式。

local result = math.random() -- 返回一个0 ~ 1之间的随机小数
local result = math.random(100) -- 返回1 ~ 100之间的随机整数
local result = math.random(10,100) -- 返回10 ~ 100之间的随机整数



解决思路

我先寻找了一下Lua有没有取数字精度的api,发现没有。那么就要首先搞到一个取精度的方式

本意并不想使用字符串来处理,但是想来想去也没有想到更加简便的处理方式了。如果有更加优雅的实现方式,也可以在评论区告诉我。

先搞了一个分割字符串的函数,然后把数字转化成字符串用字符’.’(小数点)来分割。这样取到的表[2]一定是小数部分。没有取到[2]就说明这是一个整数。

接下来要以精度最高的数作为基准数字来处理。因为Lua取随机小数只有math.random(),并且范围是0~1,所以可以使用max和min之间的差值乘上这个值即可取得随机值,这个值再加上min就是想要获得的随机值。

但是这时候会出现一个问题,就是精度问题。math.random()取到的数精度很高,我在代码里对精度进行了取余然后四舍五入的运算,这样可以保证小数点精度一致性。

最终获得的值,经过一定测试后简单的认为分布比较均匀。



测试结果

(这水印也太挡视野了)





缺陷

性能问题

字符串处理性能应该是不好的,如果有更好的方式可以告诉我。



最终代码

-- 分割字符串
local function split(input, delimiter)
    input = tostring(input)
    delimiter = tostring(delimiter)
    if delimiter == '' then 
        return false 
    end
    local pos,arr = 0, {}
    for st,sp in 
        function() 
            return string.find(input, delimiter, pos, true) 
        end 
    do
        table.insert(arr, string.sub(input, pos, st - 1))
        pos = sp + 1
    end
    table.insert(arr, string.sub(input, pos))
    return arr
end

-- 搞这个split有点耗费性能 但是暂时想不到更好的办法了……
local function any_random(min,max)
    if max <= min then
        return min
    end
    local tb_min = split(min,'.')
    local tb_max = split(max,'.')
    local accuracy_min,accuracy_max = 0,0
    if tb_min[2] then
        accuracy_min = string.len(tb_min[2])
    end
    if tb_max[2] then
        accuracy_max = string.len(tb_max[2])
    end
    local final_accuracy = math.max(accuracy_min,accuracy_max)
    -- 说明都是整数
    if final_accuracy == 0 then
        return math.random(min,max)
    end
    local rate = math.random()
    local final_random = (max - min) * rate + min
    -- 四舍五入,这个值必定等于 传入参数的最高精度的1/0 例如 1.1,1.334 那么他一定是0.001/0.000
    local round = math.floor(((final_random % (0.1 ^ final_accuracy)) * (10 ^ final_accuracy) + 0.5)) * (0.1 ^ final_accuracy)
    local result = final_random - final_random % (0.1 ^ final_accuracy) + round
    local temp = 10 ^ final_accuracy
    result = math.floor(result * temp) / temp
    
    return result
end



版权声明:本文为OvejeJ1原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。