如何递减一个浮点变量直到它正好为零

How to decrement a float variable until it's exactly zero

我正在为相机制作键盘控件,我遇到了有关浮动不准确的问题。我有变量“float Xvelocity”和“float Zvelocity”,每次按住相应的方向键(A、D、W 或 S)时,我通过增加或减去加速度来增加这些速度。 但是,我尝试使浮点数趋于零的所有操作都以非常奇怪的方式起作用。我认为这会很简单:

if (keys[GLFW_KEY_A] & xVelocity >-speed)
    xVelocity -= acceleration / deltaTime;
if (keys[GLFW_KEY_D] & xVelocity < speed)
    xVelocity += acceleration / deltaTime;
if (keys[GLFW_KEY_W] & zVelocity >-speed)
    zVelocity -= acceleration / deltaTime;
if (keys[GLFW_KEY_S] & zVelocity < speed)
    zVelocity += acceleration / deltaTime;

if (!keys[GLFW_KEY_A] & xVelocity<0.f) {
    xVelocity+=deceleration / deltaTime;
}
if (!keys[GLFW_KEY_D] & xVelocity>0.f) {
    xVelocity-=deceleration / deltaTime;
}
if (!keys[GLFW_KEY_W] & zVelocity<0.f) {
    zVelocity+=deceleration / deltaTime;
}
if (!keys[GLFW_KEY_S] & zVelocity>0.f) {
    zVelocity-=deceleration / deltaTime;
}

origin -= right * xVelocity;
origin -= vec3(front.x, 0.f, front.z) * zVelocity;

这不会让我的相机完全停止移动!它确实会减速,但它很少会完全变为零,因此在释放按键后它会继续缓慢移动,要么朝向它之前的方向,要么远离它。有人可以解释为什么这种减速没有按我的预期工作(可能是因为浮点数不准确,但也许是另一个原因),我该如何继续修复它?

这不是浮点精度问题,除非您的 accelerationdeltaTimevelocity 已校准,因此从数学上讲,velocity 恰好在之后达到零整数步数。更有可能的是,问题只是您的 velocity 不是 acceleration/deltaTime 的精确倍数,甚至考虑到浮点数问题。例如,假设 velocity 是 3.7 而 acceleration/deltaTime 是 .2。然后 velocity 将逐步执行 3.5、3.3、3.1、... .5、.3、.1 和 −.1。

所以 velocity 永远不会变成零,因为它正好穿过它。当 velocity 为 .1 个单位时,你永远不能减速 0.2 个单位;物体在其速度达到零时停止。

一个解决方案是检测这一点并将结果限制为零:

if (!keys[GLFW_KEY_A] & xVelocity<0.f)
{
    xVelocity = xVelocity >= - deceleration / deltaTime ? 0 : xVelocity + deceleration / deltaTime;
}