使用Lua 5.1时,大数值下判断点是否在圆扇区为何失效?
问题根源:浮点数精度限制
你的函数在处理大数值时出错,核心原因是双精度浮点数的精度有限,具体体现在两个环节:
叉乘计算的精度丢失
are_clockwise函数里的叉乘运算-v1.x * v2.y + v1.y * v2.x,当坐标数值极大时,乘法会产生远超双精度有效范围的中间值。双精度浮点数仅能精确表示约15-17位十进制的整数,大数值相乘后会丢失低位精度,导致叉乘结果的符号判断错误——原本应该为正/负的结果被反转,直接影响扇区方向的判断逻辑。半径平方的精度偏差
is_in_radius中直接计算radius ^ 2和rp.x * rp.x + rp.y * rp.y,当radius是极大值时,其平方会超出双精度能精确表示的整数范围(约9e15),此时存储的平方值是近似值;同时坐标分量的平方计算也会出现同样的精度丢失,导致两者的比较结果与实际不符。
修复方案
通过向量归一化和缩放式半径判断,将所有计算限制在小数值范围内,避免精度丢失:
function PointInSector(point, center, sector_start, sector_end, radius) -- 向量归一化,处理零向量边界情况 local function normalize(v) local len_sq = v.x*v.x + v.y*v.y if len_sq < 1e-12 then -- 视为零向量 return {x=0, y=0} end local len = math.sqrt(len_sq) return {x = v.x/len, y = v.y/len} end local function are_clockwise(v1, v2) -- 归一化后叉乘结果范围被限制在[-1,1],避免大数值精度问题 return -v1.x * v2.y + v1.y * v2.x > 0 end local function is_in_radius(rp, radius) -- 缩放坐标到[-1,1]范围,避免大数值平方的精度丢失 local rx = rp.x / radius local ry = rp.y / radius -- 加微小epsilon处理浮点误差 return rx*rx + ry*ry <= 1.0 + 1e-12 end local rel_pt = { x = point.x - center.x, y = point.y - center.y } -- 先判断半径范围,减少无效计算 if not is_in_radius(rel_pt, radius) then return false end -- 点与圆心重合时直接返回true local rel_len_sq = rel_pt.x*rel_pt.x + rel_pt.y*rel_pt.y if rel_len_sq < 1e-12 then return true end -- 归一化所有参与叉乘的向量 local norm_start = normalize(sector_start) local norm_end = normalize(sector_end) local norm_rel = normalize(rel_pt) return not are_clockwise(norm_start, norm_rel) and are_clockwise(norm_end, norm_rel) end
关键修改说明
- 向量归一化:将所有参与叉乘的向量缩放到模长为1,让叉乘结果始终在[-1,1]范围内,彻底避免大数值乘法的精度丢失。
- 缩放式半径判断:通过将坐标除以radius,把平方计算限制在[-1,1]的平方范围内,避免大数值平方的精度偏差。
- 边界处理:添加了零向量(点与圆心重合)的判断,以及浮点误差容忍的epsilon值,减少极端情况的误判。
内容的提问来源于stack exchange,提问作者applepie
相关产品推荐
相关产品推荐

