lua中math.floor值偏差的问题

本文通过几个具体的示例探讨了Lua语言中使用math.floor进行取整操作时出现的异常现象,并提出了一种可能的解决方案——即在进行取整前先保留六位有效数字。

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

math.floor((1.16-1.0)*100) = 15

math.floor(0.16*100) = 16

考虑到可能是lua中数字都是double类型的原因 所以实验了下以下

math.floor(1.9999999999999999) = 2

math.floor(0.9999999999999999) = 1

又疑惑了 为什么判断出这种结果

目前用了规避方式就是做这种运算的时候先保留6位有效数字 然后再做math.floor

BallisticCalc = require("BallisticCalc") Basalt = require("basalt") CoordTransformer = require("CoordTransformer") Quaternion = require("Quaternion") Track = require("Track") Util = require("Util") Vector3d = require("Vector3d") -- 系统初始化 -- local targetpos = { x = 0, y = 0, z = 0 } local Cannon_Config = { Charge = 6, length = 18, G = -0.05, Drag = 0.01, Dep = -5, Ele = 90, Tol = 0.01, Mode = 3 } local selfpos = coord.getCoord() local q = peripheral.wrap("front").getRotation() local vel = ship.getVelocity() local i = 1 local rotation_matrix = { x = Vector3d:new(1, 0, 0), y = Vector3d:new(0, 1, 0), z = Vector3d:new(0, 0, 1) } local cannon = peripheral.wrap("back") local getPlayers = coord.getPlayersAll(50) local players = {} cannon.assemble() local hasTargrt = false local current_position = Vector3d:new(-1, 0, 0) local err_yaw, err_pitch local yaw_control = peripheral.wrap("Create_RotationSpeedController_0") local pitch_control = peripheral.wrap("Create_RotationSpeedController_1") local yaw_speed, pitch_speed = 0, 0 local mode = 1 local controller = "AkashiSCO" -- GUI初始化函数 -- local function createGUI() local MainFrame = Basalt.getMainFrame() -- 目标坐标显示组件 local targetXGui = MainFrame:addTextBox({ editable = false, background = colors.white, foreground = colors.red }):setPosition(4, 1):setSize(13, 1):setText(" TargetX"); local targetYGui = MainFrame:addTextBox({ editable = false, background = colors.white, foreground = colors.green }):setPosition(20, 1):setSize(13, 1):setText(" TargetY"); local targetZGui = MainFrame:addTextBox({ editable = false, background = colors.white, foreground = colors.blue }):setPosition(36, 1):setSize(13, 1):setText(" TargetZ"); -- 玩家选择控制组件 local TargetController = MainFrame:addTextBox({ editable = false, background = colors.white, foreground = colors.black }):setPosition(16, 2):setSize(20, 1):setText(" control_player"); local buttomleft = MainFrame:addButton({ text = "<<--", background = colors.white, foreground = colors.black }):setPosition(11, 2):setSize(4, 1) local buttomright = MainFrame:addButton({ text = "-->>", background = colors.white, foreground = colors.black }):setPosition(36, 2):setSize(4, 1) -- 火炮配置组件 local Charge_text = MainFrame:addTextBox():setPosition(2, 4):setSize(10, 1):setText("Charge:" .. Cannon_Config.Charge) local length_text = MainFrame:addTextBox():setPosition(15, 4):setSize(10, 1):setText("length:" ..Cannon_Config.length) local Dep_text = MainFrame:addTextBox():setPosition(27, 4):setSize(10, 1):setText("Dep:" .. Cannon_Config.Dep) local Ele_text = MainFrame:addTextBox():setPosition(40, 4):setSize(10, 1):setText("Ele:" .. Cannon_Config.Ele) local G_text = MainFrame:addTextBox():setPosition(27, 5):setSize(10, 1):setText("G:" .. Cannon_Config.G) local Drag_text = MainFrame:addTextBox():setPosition(15, 5):setSize(10, 1):setText("Drag:" .. Cannon_Config.Drag) local reload_buttom = MainFrame:addButton({ text = "Apply Setting" }):setPosition(18, 6):setSize(13, 1) --速度监控组件 --local speed_x = MainFrame.addTextBox({text = "114"}):setPosition(0 , 10):setSize(10,1) return { targetXGui = targetXGui, targetYGui = targetYGui, targetZGui = targetZGui, TargetController = TargetController, buttomleft = buttomleft, buttomright = buttomright, reload_buttom = reload_buttom, Charge_text = Charge_text, length_text = length_text, Dep_text = Dep_text, Ele_text = Ele_text, G_text = G_text, Drag_text = Drag_text --speed_x = speed_x } end -- 初始化GUI并获取组件引用 -- local guiElements = createGUI() -- 玩家列表处理 -- local function getPlayerslist() i = 1 for _, v1 in pairs(getPlayers) do for k, v2 in pairs(v1) do if k == "name" then players[i] = v2 i = i + 1 end end end i = 1 end getPlayerslist() -- 工具函数 -- local function calcuspaces(max_length, text) local text_length = string.len(text) if text_length >= max_length then return "" end local total_spaces = max_length - text_length local left_spaces = math.floor(total_spaces / 2) return string.rep(" ", left_spaces) .. text end local function getChatBoxContent(chatMessage) if string.find(chatMessage, "xaero%-waypoint") then local chatLocation = {} for word in string.gmatch(chatMessage, "[%~%-%d]+") do table.insert(chatLocation, word) end if chatLocation[3] == nil then chatLocation[3] = 69 end if #chatLocation >= 4 then return { x = tonumber(chatLocation[2]), y = tonumber(chatLocation[3]), z = tonumber(chatLocation[4]) } end end return nil end local function normalize_angle_diff(angle) local normalized = angle % 360 if normalized > 180 then normalized = normalized - 360 elseif normalized < -180 then normalized = normalized + 360 end return normalized end local function extract_number(input_str) -- 匹配字符串中任意位置的第一个连续数字 local number_str = input_str:match("[-+]?%d*%.?%d+") -- 加强类型转换校验 return tonumber(number_str) or 0 end --计算目标相对于自身的速度 local function calculate_relative_velocity( self_world_velocity, -- 自身世界速度 (Vector3d) self_quaternion, -- 自身四元数 (Quaternion) target_world_velocity -- 目标世界速度 (Vector3d) ) -- 步骤1:计算相对世界速度 local relative_world_vel = target_world_velocity - self_world_velocity -- 步骤2:应用四元数旋转 local rotated_velocity = self_quaternion:conj():rotate(relative_world_vel) return rotated_velocity end -- 按钮事件处理 -- guiElements.buttomleft:onClick(function() i = i - 1 if i < 1 then i = #players end local len = #players[i] local SpaceRep = string.rep(" ", math.floor((19 - len) / 2)) guiElements.TargetController:setText(SpaceRep .. players[i]) controller = players[i] end) guiElements.buttomright:onClick(function() i = i + 1 if i > #players then i = 1 end local len = #players[i] local SpaceRep = string.rep(" ", math.floor((19 - len) / 2)) guiElements.TargetController:setText(SpaceRep .. players[i]) controller = players[i] end) guiElements.reload_buttom:onClick(function() Cannon_Config.Charge = extract_number(guiElements.Charge_text:getText()) Cannon_Config.length = extract_number(guiElements.length_text:getText()) Cannon_Config.Drag = extract_number(guiElements.Drag_text:getText()) Cannon_Config.Dep = extract_number(guiElements.Dep_text:getText()) Cannon_Config.Ele = extract_number(guiElements.Ele_text:getText()) Cannon_Config.G = extract_number(guiElements.G_text:getText()) end) -- 目标获取函数 -- local function getTarget() while true do local _, user, msg = os.pullEvent("chat") local target = getChatBoxContent(msg) if target ~= nil and user == controller then targetpos = Vector3d:new(target.x, target.y or 69, target.z) hasTargrt = true local x_text = calcuspaces(13, "X=" .. targetpos.x) local y_text = calcuspaces(13, "Y=" .. targetpos.y) local z_text = calcuspaces(13, "Z=" .. targetpos.z) guiElements.targetXGui:setText(x_text) guiElements.targetYGui:setText(y_text) guiElements.targetZGui:setText(z_text) end end end -- 控制逻辑函数 -- local function calc_speed_t(target) local speed = target / 0.32222222222222222 return math.min(math.max(speed, -48), 48) end local function isdisassemble() while true do os.pullEvent("redstone") if redstone.getInput("top") then cannon.disassemble() else cannon.assemble() end end end -- 主控制逻辑 -- local function Main() repeat os.sleep(0.5) until hasTargrt == true while true do selfpos = coord.getCoord() q = peripheral.wrap("front").getRotation() q = Quaternion:new( q.x , q.y , q.z , q.w ) vel = ship.getVelocity() local speed = Vector3d:new(vel.x, vel.y, vel.z) local targetspeed = Vector3d:new(0, 0, 0) -- 目标静止 local target_local_speed = calculate_relative_velocity(speed , q , targetspeed) -- 将目标速度转换到自身坐标系 -- 计算初始弹道 local target_relative = CoordTransformer.InverseCoord(selfpos, targetpos, q) local Yaw, Dist_xz = BallisticCalc.calc_Yaw_and_Dist_xz(target_relative, rotation_matrix, 90) Yaw = Util:setInScope(Yaw) local t_y = targetpos.y - selfpos.y - 1 local Pitch, time = BallisticCalc.customcalc( Dist_xz, t_y, Cannon_Config.Charge, Cannon_Config.length, Cannon_Config.G, Cannon_Config.Drag, Cannon_Config.Dep, Cannon_Config.Ele, Cannon_Config.Tol, mode ) local calc_return = BallisticCalc.calc_leading_shot( target_relative, target_local_speed, { n = Cannon_Config.Charge , k = Cannon_Config.length , g = Cannon_Config.G , drag = Cannon_Config.Drag }, { a_min = Cannon_Config.Dep , a_max = Cannon_Config.Ele}, 30,0.001,-90 ) Pitch = calc_return.pitch or 0 Yaw = calc_return.yaw or 0 local now_yaw = cannon.getYaw() local now_pitch = cannon.getPitch() err_yaw = normalize_angle_diff(Yaw - now_yaw) err_pitch = normalize_angle_diff(Pitch - (now_pitch or 0)) yaw_speed = calc_speed_t(err_yaw) or 0 pitch_speed = -calc_speed_t(err_pitch) or 0 os.sleep(0.05) end end -- 执行函数 -- local function setYawspeed() repeat os.sleep(0.5) until hasTargrt == true while true do os.sleep(0.05) if math.abs(yaw_speed) > 1 or math.abs(err_yaw) > 1 then yaw_control.setTargetSpeed(yaw_speed) else yaw_control.setTargetSpeed(0) if Yaw then cannon.setYaw(Yaw) end end end end local function setpitchspeed() repeat os.sleep(0.5) until hasTargrt == true while true do os.sleep(0.05) if math.abs(pitch_speed) > 1 or math.abs(err_pitch) > 1 then pitch_control.setTargetSpeed(pitch_speed) else pitch_control.setTargetSpeed(0) if Pitch then cannon.setPitch(Pitch) end end end end -- 启动所有并行任务 -- parallel.waitForAll( Main, setYawspeed, setpitchspeed, getTarget, isdisassemble, Basalt.run ) 这是我的代码 Vector3d = {} Vector3d.__index = Vector3d -- 构造函数 function Vector3d:new(x, y, z) local instance = { x = x or 0, y = y or 0, z = z or 0 } setmetatable(instance, self) return instance end function Vector3d:copy(cpyVector) return Vector3d:new(cpyVector.x, cpyVector.y, cpyVector.z) end -- 加法 function Vector3d:add(other) return Vector3d:new(self.x + other.x, self.y + other.y, self.z + other.z) end function Vector3d.__add(a, b) return a:add(b) end -- 减法 function Vector3d:subtract(other) return Vector3d:new(self.x - other.x, self.y - other.y, self.z - other.z) end function Vector3d.__sub(a, b) return a:subtract(b) end -- 点积 function Vector3d:dot(other) return self.x * other.x + self.y * other.y + self.z * other.z end function Vector3d:operate(func) return Vector3d:new(func(self.x), func(self.y), func(self.z)) end -- 叉积 function Vector3d:cross(other) local x = self.y * other.z - self.z * other.y local y = self.z * other.x - self.x * other.z local z = self.x * other.y - self.y * other.x return Vector3d:new(x, y, z) end function Vector3d:scale(scalar) return Vector3d:new( self.x * scalar, self.y * scalar, self.z * scalar ) end function Vector3d.__mul(a, b) if type(a) == "number" then return b:scale(a) elseif type(b) == "number" then return a:scale(b) end --error("Vector multiplication requires explicit cross/dot") return a:scale(b) --return a:cross(b) end function Vector3d:magnitude() return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) end function Vector3d:magnitudesq() return (self.x * self.x + self.y * self.y + self.z * self.z) end function Vector3d:multiply(scale) return Vector3d:new(self.x * scale, self.y * scale, self.z * scale) end function Vector3d:multiplyByMatrix(m) local v_x = m.x:multiply(self.x) local v_y = m.y:multiply(self.y) local v_z = m.z:multiply(self.z) return v_x + v_y + v_z end -- 归一化 function Vector3d:normalize() local magnitude = math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) return Vector3d:new(self.x / magnitude, self.y / magnitude, self.z / magnitude) end return Vector3d 这是我的库,当我移动的时候他提前量明显过于大了,而且速度高于一定的时候,他在调用我的库的__mul(a,b)的时候,b会为nil
最新发布
06-03
### Luamath.floor 函数的用法 `math.floor` 是 Lua 标准库中的一个数学函数,用于返回不大于指定数的最大整数(即向负无穷方向取整)。以下是关于该函数的专业解析和示例说明。 #### 1. 函数定义 `math.floor(x)` 接受一个数参数 `x`,并返回小于或等于 `x` 的最大整数。如果输入为正数,则去掉小数部分;如果输入为负数,则会向下舍入到更小的整数[^2]。 #### 2. 示例代码 以下是一些使用 `math.floor` 的示例: ```lua -- 正数的例子 print(math.floor(3.7)) -- 输出: 3 print(math.floor(5.0)) -- 输出: 5 -- 负数的例子 print(math.floor(-3.7)) -- 输出: -4 print(math.floor(-5.0)) -- 输出: -5 ``` #### 3. 解释 - 在第一个例子中,`math.floor(3.7)` 返回 `3`,因为 `3` 是不大于 `3.7` 的最大整数。 - 第二个例子中,`math.floor(-3.7)` 返回 `-4`,因为 `-4` 是不大于 `-3.7` 的最大整数[^2]。 #### 4. 常见应用场景 `math.floor` 常用于需要对浮点数进行取整操作的场景,例如计算分页时的页码、处理时间戳等。 ```lua -- 计算分页时的页码 local totalItems = 123 local itemsPerPage = 10 local totalPages = math.ceil(totalItems / itemsPerPage) -- 向上取整 local currentPage = math.floor((itemIndex - 1) / itemsPerPage) + 1 -- 向下取整 ``` #### 5. 注意事项 在使用 `math.floor` 时需要注意浮点数精度问题。由于浮点数的内部表示方式可能导致微小的误差,因此在某些情况下可能会出现意外的结果[^1]。 ```lua print(math.floor(1.9999999999999999)) -- 输出: 1 print(math.floor(1.999999999999999)) -- 输出: 2 ``` 上述例子展示了浮点数精度可能带来的影响。为了规避此类问题,可以结合 `math.modf` 或其他方法来处理浮点数的小数部分。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值