Lua浮点数转分数函数FindFraction返回nil错误排查与解决
Lua浮点数转分数函数FindFraction的问题与修复
下面是一个用于将浮点数转换为分数形式的Lua函数FindFraction:
local function FindFraction(float) local i,f = math.modf(float) local result = 1 / f % 1 == 0 and '1 / ' .. math.floor(1 / f) or f == 0 and i or nil if not result then for k = 1, 10000 do if 1 / f * k % 1 == 0 then result = tostring(k + i .. ' / ' .. 1 / f * k) break end end end return float > 1 and i .. ' + (' .. result .. ')' or result end print(FindFraction(0.1)) -- 1 / 10 print(FindFraction(0.2)) -- 1 / 5 print(FindFraction(0.3)) -- 3 / 10 print(FindFraction(0.4)) -- 2 / 5 print(FindFraction(0.5)) -- 1 / 2 print(FindFraction(0.6)) -- 3 / 5 print(FindFraction(0.7)) -- 7 / 10 print(FindFraction(0.8)) -- 8 / 10 print(FindFraction(0.9)) -- 9 / 10 print(FindFraction(1)) -- 1 print(FindFraction(1.1)) -- nil or error ( what is wrong here? )
这个函数处理0.234这类浮点数时能正常输出117 / 500,但处理1.1这类数值时会返回nil引发错误。
问题原因
本质是浮点数精度误差:Lua使用的双精度浮点数无法精确表示0.1这类十进制小数,1.1拆分后的小数部分f实际是一个接近0.1但带有微小误差的数值(比如0.10000000000000009),这导致1/f不是整数,循环遍历k时也找不到满足1/f * k % 1 == 0的条件,最终返回nil。
修复方案
在拆分整数和小数部分后,对小数部分f做格式化处理,消除精度误差。具体是在函数第3行添加以下代码:
f = tonumber(string.format('%g',string.format('%.'..(10)..'f',f)))
修复后的完整函数:
local function FindFraction(float) local i,f = math.modf(float) f = tonumber(string.format('%g',string.format('%.'..(10)..'f',f))) -- 新增的精度修正代码 local result = 1 / f % 1 == 0 and '1 / ' .. math.floor(1 / f) or f == 0 and i or nil if not result then for k = 1, 10000 do if 1 / f * k % 1 == 0 then result = tostring(k + i .. ' / ' .. 1 / f * k) break end end end return float > 1 and i .. ' + (' .. result .. ')' or result end
此时调用print(FindFraction(1.1))会正确返回1 + (1 / 10)。
内容的提问来源于stack exchange,提问作者frogl8
相关产品推荐
相关产品推荐

