Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's a method that works exactly like Math.floorMod() but with floats instead of ints?

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.

like image 616
PianoMastR64 Avatar asked Mar 17 '19 09:03

PianoMastR64


People also ask

What is math floorMod?

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).

How do you double a floor in Java?

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.


1 Answers

Solution

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

Algorithm explanation

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.)

like image 89
PianoMastR64 Avatar answered Sep 21 '22 00:09

PianoMastR64