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算法完全相同,只是使用浮點數。我在這里表現得像某種學者,他發現了萬物的統一理論,而我所做的只是從我眼皮底下的東西多走了一步。我保證,我絞盡腦汁從頭開始開發它。
我最初的算法在某一時刻變得非?;靵y。我仍然很高興我寫了這篇文章,因為我相信這是很好的信息,而且很有趣。-Math.floor(x/y) * y + x

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
添加回答
舉報