java - 加减精确值以 float

标签 java floating-point

问题:

float 的总数是有限的,大约有 2^32 个。使用 float ,您可以使用 java.lang.Math.nextAfter 直接转到下一个或上一个。我称之为一次飞跃。我的主要问题(由子问题组成)是,如何使用 leaps 在 float 车上导航?

Float navigation

首先,我怎样才能一次将一个 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 个 float 之间有多少跳跃。这是这个的示例实现:

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 物理引擎,但我在浮点运算方面遇到了问题。我了解了相对误差 float 比较,它有点帮助,但这并不神奇。我想要的是精确计算 float 。

我已经知道很多以 10 为底的数字不能用 float 精确表示,但特别是,我不在乎。我想要的只是以 2 为基数的精确 float 算术。

为了简化,在我的碰撞检测和响应过程中,我检查形状是否重叠(在本例中让我们保持一维)并使用它们的权重替换重叠的 2 个形状。

看这个例子: One dimensional collision detection and resolving

如果黑线是 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,但它会消除使用 float 的全部意义。我想使用的技术让用户隐含地选择他的精度,理论上应该以任何精度工作。

最佳答案

底层 IEEE 754 浮点模型具有此属性:如果您将位重新解释为整数,则在之后(或之前取决于方向)获取下一个 float 就像获取下一个(或上一个)整数一样,即向重新解释为整数的位模式加或减 1。

步进 n 次是向位模式添加(或减去)n。就这么简单,只要符号不变,不溢出到 NaN 或 Inf。

如果符号一致,则两个 float 之间的不同 float 是两个整数的差。

如果符号不同,因为 float 具有类似符号大小的表示形式,不适合整数表示形式,因此您将不得不进行一些算术计算。

关于java - 加减精确值以 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44008357/

相关文章:

java - 如何使用 STAX api 处理大型 XML 文件 (9 GB)

java - 输入流函数中找不到文件异常错误

Swift Float80 数据类型在 Xcode 8 beta 中不可用

php - float 问题! (在 PHP 中)

matlab - 如何在 MATLAB 中的数组中存储多于 4 位小数

c++ - G++ 将 float 视为非法指令

java - 编写太空侵略者代码,无法获得子弹消灭外星人

java - 如何将一个 bean 的构造函数参数传递给嵌套 bean

java - 在一类中创建多时间选择器

c - 将浮点值舍入为例如单精度