java - 什么是与 Math.floorMod() 完全相同但使用 float 而不是整数的方法?

标签 java floating-point modulo

这是 Math.floorMod(x, 5) 的一组输入和输出举个例子。

int x;

inputs:
x = -15 | -14 | -13 | -12 | -11
    -10 | -09 | -08 | -07 | -06
    -05 | -04 | -03 | -02 | -01
    +00 | +01 | +02 | +03 | +04*
    +05 | +06 | +07 | +08 | +09
    +10 | +11 | +12 | +13 | +14

outputs:
   *+00 | +01 | +02 | +03 | +04

需要说明的是,第 1 列中的所有输入都会导致第 1 列中的输出等。

我也想用 float 来做到这一点,但我一直无法找到任何 Math.relevantMethod() 来帮助我解决这个问题。这个想法是所有 float 都应该映射到 0y(第二个参数)吃 bean 人风格之间的 float 范围。

最佳答案

解决方案

我花了一些时间来开发算法并解决所有问题,但就是这样。我将其命名为 floatMod()

double floatMod(double x, double y){
    // x mod y behaving the same way as Math.floorMod but with doubles
    return (x - Math.floor(x/y) * y);
}

这里有一个 floatMod(x, 2.0d) 的输入和输出表作为例子。 (为了整洁起见,我修复了轻微的舍入错误。)

double x;

inputs:
x = -4.0 | -3.6 | -3.2 | -2.8 | -2.4
    -2.0 | -1.6 | -1.2 | -0.8 | -0.4
    +0.0 | +0.4 | +0.8 | +1.2 | +1.6*
    +2.0 | +2.4 | +2.8 | +3.2 | +3.6
    +4.0 | +4.4 | +4.8 | +5.2 | +5.6

outputs:
   *+0.0 | +0.4 | +0.8 | +1.2 | +1.6

这里还有一些例子。

floatMod(0.1f, 1f);     //returns: 0.1
floatMod(1.1f, 1f);     //returns: 0.100000024 aka 0.1 + 0.000000024
floatMod(2.1f, 1f);     //returns: 0.099999905 aka 0.1 - 0.000000095
floatMod(10000.1f, 1f); //returns: 0.099609375 aka 0.1 - 0.000390625

floatMod(0.1d, 1d);     //returns: 0.1
floatMod(1.1d, 1d);     //returns: 0.10000000000000009 aka 0.1 + 0.00000000000000009
floatMod(2.1d, 1d);     //returns: 0.10000000000000009 aka 0.1 + 0.00000000000000009
floatMod(10000.1d, 1d); //returns: 0.10000000000036380 aka 0.1 - 0.00000000000036380

算法解释

如果您对算法 x - Math.floor(x/y) * y 的工作原理感兴趣,我会尽力解释。让我们使用上面的 floatMod(x, 2.0d) 示例。

首先,取 x 可能值的数轴:

                                ●------------------------○
       |                        |                        |                        |
-2.4 -2.0 -1.6 -1.2 -0.8 -0.4 +0.0 +0.4 +0.8 +1.2 +1.6 +2.0 +2.4 +2.8 +3.2 +3.6 +4.0 +4.4

垂直线之间的空间表示在两个方向上并排堆叠的长度为 y 的 block 。实心圆表示包含,空心圆表示不包含,上图包含虚线表示的chunk 0。

接下来x/y(在本例中为 y = 2.0)在数轴 x 上占据一个给定位置,并以 block 的形式给出它的位置。所以,2.0 是 block 0 的结尾和 block 1 的开始,所以 2.0/y = 1.0。

我们会说 x/y = c;

1.0/y → 0.5c 因为 1.0 是半个 block
3.2/年 → 1.6c
-2.4/y → -1.2c

下一步Math.floor(c) 意味着无论我们在哪个 block 中,都将 c 减少到所述 block 的开头。换句话说,x在哪一个?

0.5c → 0.0c
1.6c → 1.0c
-1.2c → -2.0c

接下来,它再次将结果乘以 y 以 x 的形式返回。

0.0c * y → 0.0
1.0c * y → 2.0
-2.0c * y → -4.0

最后,它只需要这个值并计算 x 离它有多远,比如 x 离它所在 block 的开头有多远?

另一种看待它的方式:它需要减去 x 中的额外 block ,因此它计算出从 block 0 向前或向后 x 有多少 block ,并删除该数量。这使其保持在 0 和 y 的范围内。

1.0 - 0.0 → 1.0
3.2 - 2.0 → 1.2
-2.4 - -4.0 → 1.6


(呃...好吧,在写完算法的大部分解释后,我意识到有一种方法可以简化它。在我这样做之后,我意识到它实际上与 floorMod 算法完全相同,只是漂浮。我在这里表现得像个发现了万物统一理论的学者,而我所做的只是从我眼皮底下的东西多走了一步。我保证我会绞尽脑汁从头开始开发这个.

我的原始算法是 -Math.floor(x/y) * y + x,在某些时候解释起来很困惑。我仍然很高兴我写了这篇文章,因为我相信这是很好的信息,而且很有趣。)

关于java - 什么是与 Math.floorMod() 完全相同但使用 float 而不是整数的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55205437/

相关文章:

performance - 是否有任何现实世界的 CPU 不使用 IEEE 754?

比较 C 中的 float

math - 快速计算(a * b)mod c,其中c = 2 ^ N + -1

java - Wicket 口 RepeatingView : delete placeholder if list is empty

java - 将自定义数据添加到 ListView 和 ArrayAdapter 项目

math - float 学有问题吗?

c++ - C++ 中高数的模幂运算

java - 计算一个数的最大余数

java - 在tomcat中的两个子域之间共享 session 属性

Java 和 Jabber/Smack