为了账号安全,请及时绑定邮箱和手机立即绑定

什么是一种与Math.floorMod()完全相同但使用浮点数而不是整数的方法?

什么是一种与Math.floorMod()完全相同但使用浮点数而不是整数的方法?

慕容森 2022-08-17 15:31:46
下面是 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 | +14outputs:    *+00 | +01 | +02 | +03 | +04需要明确的是,列 1 中的所有输入都会导致列 1 中的输出,依此类推。我也希望能够用花车做到这一点,但我一直找不到任何东西来帮助我。这个想法是,所有浮点都应该映射到和(第二个参数)吃豆人风格之间的浮点盘上。Math.relevantMethod()0y
查看完整描述

2 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

溶液

我花了一段时间来开发算法并解决所有问题,但事实就是如此。我配音.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);

}

下面是一个浮点模型(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) * yfloatMod(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 块。填充圆表示包含,而空心圆表示排他性,上面所示的圆包含由虚线表示的块 0。


接下来,(在本例中为 y = 2.0)在数字线 x 上采用给定位置,并给出块的数量。因此,2.0 是块 0 的末尾和块 1 的开头,因此 2.0/y = 1.0。x/y


我们会说 x/y = c;


1.0/y → 0.5c 作为 1.0 是半块

3.2/y → 1.6c

-2.4/y → -1.2c

等。


接下来,意味着无论我们处于哪个区块中,都将c减少到所述区块的开头。换句话说,哪一个是x?Math.floor(c)


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离它所在的块的开头有多远一样?


另一种看待它的方式:它需要减去x中的额外块,所以它从块0中计算出x向前或向后多少块,并删除该数量。这使其保持在 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


查看完整回答
反对 回复 2022-08-17
?
喵喔喔

TA贡献1735条经验 获得超5个赞

对模量使用浮点 esp 的一个问题是,您会看到明显的表示错误。你最好做的是舍入结果或计算,这样你就能得到理智的结果。一个简单的方法是假设你只需要N个精度数字,例如6。


public static double floorMod(double x, double y) {

    return Math.floorMod(Math.round(x * 1e6), Math.round(y * 1e6)) / 1e6;

}

对于上面的例子,你得到


floorMod(0.1f, 1f);     //returns: 0.1

floorMod(1.1f, 1f);     //returns: 0.1

floorMod(2.1f, 1f);     //returns: 0.1

floorMod(10000.1f, 1f); //returns: 0.099609 due to the limits of float.


floorMod(0.1d, 1d);     //returns: 0.1

floorMod(1.1d, 1d);     //returns: 0.1

floorMod(2.1d, 1d);     //returns: 0.1

floorMod(10000.1d, 1d); //returns: 0.1

另一种方法是指定精度


public static double floorMod(double x, double y, double precision) {

    double factor = Math.round(1 / precision);

    return Math.floorMod(Math.round(x * factor), Math.round(y * factor)) / factor;

}


floorMod(10000.1f, 1f, 0.1); // returns 0.1


查看完整回答
反对 回复 2022-08-17
  • 2 回答
  • 0 关注
  • 104 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信