全站通知:
模块:Utils/Float32
刷
历
编
< 模块:Utils
跳到导航
跳到搜索
-- Float32Utils 模块
-- 提供 IEEE 754 单精度浮点数处理功能
--
-- IEEE 754 单精度浮点数格式:
-- - 1位符号位 (S)
-- - 8位指数位 (E),偏移量为127
-- - 23位尾数位 (M)
--
-- 总共32位,按大端序排列:SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
local p = {}
-- 将数字打包为 Float32 格式的4字节字符串
-- @param number 要转换的数字
-- @return 4字节的字符串,表示IEEE 754单精度浮点数
function p.PackFloat32(number)
-- 处理零值:返回全零字节
if number == 0 then
return string.char(0x00, 0x00, 0x00, 0x00)
-- 处理NaN:返回特殊的NaN表示
elseif number ~= number then
return string.char(0xFF, 0xFF, 0xFF, 0xFF)
else
-- 提取符号位
local sign = 0x00
if number < 0 then
sign = 0x80 -- 设置符号位为1
number = -number -- 转为正数处理
end
-- 使用math.frexp分解数字为尾数和指数
-- frexp返回 (mantissa, exponent),其中 number = mantissa * 2^exponent
-- mantissa在[0.5, 1)范围内
local mantissa, exponent = math.frexp(number)
-- 调整指数:加上IEEE 754的偏移量127
exponent = exponent + 0x7F
-- 处理非规格化数(指数<=0)
if exponent <= 0 then
-- 调整尾数以适应非规格化表示
mantissa = math.ldexp(mantissa, exponent - 1)
exponent = 0
elseif exponent > 0 then
-- 检查指数溢出
if exponent >= 0xFF then
-- 返回无穷大
return string.char(sign + 0x7F, 0x80, 0x00, 0x00)
elseif exponent == 1 then
-- 边界情况处理
exponent = 0
else
-- 规格化数:调整尾数去掉隐含的1
mantissa = mantissa * 2 - 1
exponent = exponent - 1
end
end
-- 将尾数转换为23位整数(四舍五入)
mantissa = math.floor(math.ldexp(mantissa, 23) + 0.5)
-- 组装4个字节
-- 字节1:符号位 + 指数高7位
-- 字节2:指数低1位 + 尾数高7位
-- 字节3:尾数中间8位
-- 字节4:尾数低8位
return string.char(
sign + math.floor(exponent / 2),
(exponent % 2) * 0x80 + math.floor(mantissa / 0x10000),
math.floor(mantissa / 0x100) % 0x100,
mantissa % 0x100)
end
end
-- 从 Float32 格式的4字节字符串解包为数字
-- @param packed 4字节的字符串,表示IEEE 754单精度浮点数
-- @return 解包后的数字值
function p.UnpackFloat32(packed)
-- 提取4个字节
local b1, b2, b3, b4 = string.byte(packed, 1, 4)
-- 重构指数:从字节1的低7位和字节2的高1位
local exponent = (b1 % 0x80) * 0x02 + math.floor(b2 / 0x80)
-- 重构尾数:从字节2的低7位、字节3和字节4
-- 并转换为[0,1)范围的小数
local mantissa = math.ldexp(((b2 % 0x80) * 0x100 + b3) * 0x100 + b4, -23)
-- 处理特殊指数值
if exponent == 0xFF then
-- 指数全1:无穷大或NaN
if mantissa > 0 then
return 0 / 0 -- NaN
else
mantissa = math.huge -- 无穷大
exponent = 0x7F
end
elseif exponent > 0 then
-- 规格化数:添加隐含的1
mantissa = mantissa + 1
else
-- 非规格化数:调整指数
exponent = exponent + 1
end
-- 处理符号位
if b1 >= 0x80 then
mantissa = -mantissa
end
-- 使用ldexp重构最终数值:mantissa * 2^(exponent - 127)
return math.ldexp(mantissa, exponent - 0x7F)
end
-- 将数字转换为 Float32 精度
-- 通过打包再解包的过程,模拟单精度浮点数的精度损失
-- @param number 输入的数字
-- @return 转换为Float32精度后的数字
function p.toFloat32(number)
return p.UnpackFloat32(p.PackFloat32(number))
end
-- Float32 精度的加法运算
-- 确保加法结果符合单精度浮点数的精度限制
-- @param a 第一个加数
-- @param b 第二个加数
-- @return Float32精度的加法结果
function p.AddFloat32(a, b)
local a_f = p.toFloat32(a) -- 转换为Float32精度
local b_f = p.toFloat32(b) -- 转换为Float32精度
return p.toFloat32(a_f + b_f) -- 加法后再次转换确保精度
end
-- Float32 精度的乘法运算
-- 确保乘法结果符合单精度浮点数的精度限制
-- @param a 被乘数
-- @param b 乘数
-- @return Float32精度的乘法结果
function p.MulFloat32(a, b)
local a_f = p.toFloat32(a) -- 转换为Float32精度
local b_f = p.toFloat32(b) -- 转换为Float32精度
return p.toFloat32(a_f * b_f) -- 乘法后再次转换确保精度
end
-- Float32 乘法运算(从 MediaWiki frame 参数获取输入)
-- 用于 MediaWiki 模板调用,从 frame.args 中获取参数 a 和 b
-- @param frame MediaWiki frame 对象,包含 args.a 和 args.b 参数
-- @return Float32精度的乘法结果,如果参数无效则返回0
function p.MulFloat32Args(frame)
local a = tonumber(frame.args.a) -- 从frame获取参数a并转换为数字
local b = tonumber(frame.args.b) -- 从frame获取参数b并转换为数字
-- 参数验证:如果任一参数为nil,返回0
if a == nil or b == nil then
return 0
end
return p.MulFloat32(a, b)
end
-- Float32 数字的向下取整(截断)
-- 先转换为Float32精度,再进行向下取整
-- @param number 要截断的数字
-- @return 截断后的整数
function p.TruncFloat32(number)
return math.floor(p.toFloat32(number))
end
return p

沪公网安备 31011002002714 号