问题:
浮点的总数是有限的,大约有2 ^ 32。使用float时,您可以使用java.lang.Math.nextAfter
直接转到下一个或上一个。我称这为一次飞跃。由子问题组成的主要问题是,如何使用跃迁在浮点数上导航?
首先,如何一次将多个 float 元素移动到另一个 float 元素上?
public static float moveFloat(float value, int leaps) {
for(int i = 0; i < Math.abs(leaps); i++)
value = Math.nextAfter(value, Float.POSITIVE_INFINITY * signum(leaps));
return value;
}
这种方式应该在理论上可行,但实际上并没有优化。如何一次添加呢?
我还需要知道2个浮点之间有多大的飞跃。这是此示例的示例实现:
public static int getLeaps(float value, float destination) {
int leaps = 0;
float direction = signum(destination - value);
while(value * direction < destination * direction) {
value = Math.nextAfter(value, Float.POSITIVE_INFINITY * direction);
leaps++;
}
return leaps;
}
同样,这里同样的问题。此实现不适合。
额外:
我称之为“飞跃”的东西,它有一个真实的名字吗?
背景:
我试图用Java创建一个简单的2D物理引擎,但我的浮点运算遇到了麻烦。我了解了相对错误浮点比较,虽然有所帮助,但这不是魔术。我想要的是准确的浮点数。
我已经知道很多基数十不能用浮点数精确表示,但是从实践上讲,我不在乎。我想要的只是基数2中的精确
float
算术。为简化起见,在碰撞检测和响应过程中,我检查形状是否重叠(在此示例中,我们停留在一个维度上),并使用其权重替换两个重叠的形状。
请参阅以下示例:
如果黑线是
float
值(以及彼此之间的间距),则无论精度如何,我都希望将两个形状(彩色线)都精确地置于棕色位置。 (棕色位置由权重比和四舍五入确定。我称渗透为重叠的面积/距离。如果渗透为5,则红色推1,蓝色推4)。问题是,要做到这一点,我必须将碰撞的穿透力(在这种情况下,穿透力恰好是浮子的ULP或1个跃点)保持在浮子中,我怀疑这会导致不准确。如果穿透值大于形状的坐标,则精度会降低,因此不会在良好的坐标处精确替换它们。
我想象的是保持碰撞的渗透,因为我需要一次又一次的跳跃,然后再使用它。
这是当前代码的简化版本:
public class ReplaceResolver implements CollisionResolver {
@Override
public void resolve(Collision collision) {
float deltaB = collision.weightRatio * collision.penetration; //bodyA's weight over the sum of the 2 (pre calculated)
float deltaA = 1f - deltaB;
//the normal indicates where the shape should be pushed. For now, my engine is only AA so a component of the normal (x or y) is always 0 while the other is 1
if(deltaB > 0)
replace(collision.bodyA, collision.normalB, deltaA);
if(deltaA > 0)
replace(collision.bodyB, collision.normalA, deltaB);
}
private void replace(Body body, Vector2 normal, float delta) {
body.getPosition().x += normal.x * delta; //body.getPosition() is a Vector2
body.getPosition().y += normal.y * delta;
}
}
显然,这不能正常工作,并且会累积浮点精度误差。我的碰撞检测很好地处理了该错误,该碰撞检测使用ULP检查浮点是否相等。但是,由于ULP极低,因此在穿越0时会中断。
我可以简单地修复物理仿真的epsilon,但是它将消除使用浮点数的全部问题。我要使用的技术允许用户隐式选择精度,并且理论上应该以任何精度进行工作。
最佳答案
底层IEEE 754浮点模型具有此属性:如果将位重新解释为Integer,则在(或之前,取决于方向)进行下一浮点运算时,就像在取下一个(或上一个)整数一样,即相加或相减1到位模式重新解释为整数。
步进n次是将n添加(或减去)到位模式。只要符号不改变,就很简单,并且您不会溢出到NaN或Inf。
如果符号一致,则两个浮点数之间的不同浮点数是两个整数之差。
如果符号不同,则由于浮点数具有类似于符号表示的符号幅度,因此不适合整数表示,因此您必须进行一些算术运算。
关于java - 添加和减去精确值以 float ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44008357/