Here's a set of inputs and outputs for Math.floorMod(x, 5)
as an example.
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
Just to be clear, all the inputs in column 1 result in the output in column 1 etc.
I want to be able to do this with floats too, but I've been unable to find any Math.relevantMethod()
to help me with this. The idea is that all floats should map onto a span of floats between 0
and y
(the second argument) Pac-Man style.
The java. lang. Math. floorMod() is a built-in math function in java which returns the floor modulus of the integer arguments passed to it. Therefore, floor modulus is (a – (floorDiv(a, b) * b)), has the same sign as the divisor b, and is in the range of -abs(b) < t < +abs(b).
floor(double a) returns the largest (closest to positive infinity) double value that is less than or equal to the argument and is equal to a mathematical integer. Special cases: If the argument value is already equal to a mathematical integer, then the result is the same as the argument.
It took me a while to develop the algorithm and work out all the kinks, but here it is. I dub it 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);
}
Here's a table of inputs and outputs for floatMod(x, 2.0d) as an example. (I fixed the slight rounding errors for tidiness.)
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
Here's some more examples.
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
If you're interested in how the algorithm x - Math.floor(x/y) * y
works, I'll try my best to explain. Let's use the floatMod(x, 2.0d)
example from above.
First, take this numberline of possible values for 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
The spaces between the vertical lines represent chunks of length y stacked side-by-side in both directions. The filled circle means inclusive, while the hollow circle means exclusive, and the ones illustrated above encompass chunk 0 represented by the dashed line.
Next, x/y
(y = 2.0 in this case) takes a given position on the numberline x and gives what it is in terms of chunks. So, 2.0 is the end of chunk 0 and the beginning of chunk 1, so 2.0/y = 1.0.
We'll say x/y = c;
1.0/y → 0.5c as 1.0 is half a chunk
3.2/y → 1.6c
-2.4/y → -1.2c
etc.
Next, Math.floor(c)
means whichever chunk we're in, reduce c to the beginning of said chunk. In other words, which one is x in?
0.5c → 0.0c
1.6c → 1.0c
-1.2c → -2.0c
Next, it multiplies the result by y again to get it back in terms of x.
0.0c * y → 0.0
1.0c * y → 2.0
-2.0c * y → -4.0
Finally, it just takes this value and calculates how far x is away from it, as in how far away is x from the beginning of the chunk it's in?
Another way of looking at it: It needs to subtract out the extra chunks in x, so it figures out how many chunks forward or backward x is from chunk 0 and removes that amount. This keeps it within the bounds of 0 and y.
1.0 - 0.0 → 1.0
3.2 - 2.0 → 1.2
-2.4 - -4.0 → 1.6
(Uhh... Ok so, after writing through most of the explanation for the algorithm, I realized there was a way to simplify it. After I did, I realized it's actually the exact same as the floorMod algorithm, just with floats. I'm here acting like some kind of savant who's discovered the unified theory of everything when all I did was take one extra step from what was right under my nose. I do promise that I racked my brain to develop this from scratch though.
The original algorithm I had was -Math.floor(x/y) * y + x
which got pretty confusing to explain at a certain point. I'm still glad I wrote this though as I believe it's good information and it was a lot of fun.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With