4

In Java, we have two different modulo (and remiander) operations, % and Math.floorMod(). The difference is in the area of the mapping destination, which can either depend on the sign of the first or the sign of the second operand. This page explains the difference nicely.

Is there an equivalent (fast) operation in C++ with the same effect as Math.floorMod()?

I currently go with the following (and for performance reasons it's not even fully equivalent to Math.floorMod()):

inline int floor_mod(int x, int y) {
    x %= y;

    if (x < 0) {
        x += y;
    }

    return x;
}

I think there might be an intrinsic or something similar which compiles to only 1 instruction on some CPUs.

HTNW
  • 27,182
  • 1
  • 32
  • 60
Daniel S.
  • 6,458
  • 4
  • 35
  • 78
  • Shouldn't it be `if (y < 0) ...`? – Bob__ Jul 15 '20 at 14:22
  • @Bob__: say `x` is `-101`, `y` is `100`. `x %= y` results in the same as `x = x % y`, so `x` will be `-101 % 100`, which is equal to `-1` (in C++). So you need to check if `x` is negative, so you can take it's complement if necessary. –  Jul 15 '20 at 14:31
  • @BlayerBond Well, [your](https://wandbox.org/permlink/LzJC4U1kPKeVTZF2) version seems equivalent to the java function, but [OP's](https://wandbox.org/permlink/vjfYtTNGiy0fWe8J) not so much. – Bob__ Jul 15 '20 at 14:57
  • I was confused because I didn't understand your last comment and thought I was mistaken. In meanwhile I rewrote it to assure myself it has the same output. Thanks for the comment, you are right about that there should be an additional if-test on `y` in case of `signed int`s. I rewrote the `main` to check and got a more clear result. –  Jul 15 '20 at 16:13

3 Answers3

4

Well...

I'm afraid you'll have to make one yourself. A one-liner is a custom floorModulo, however one if-test might be faster (and more readable) if you're expecting an unsigned int& as divisor.

#include <iostream>

int myCustomModulo(const int& a, const int& b);

int main()
{
    std::cout
        << "| mod & +divisor | mod & -divisor |\n"
        << "| :------------- | -------------- |\n"
        ;
    int b{ 3 };
    for (int a{ -5 }; a < 0; ++a)
        std::cout
            << "| " << a << " mod " << b << "  =  " << myCustomModulo(a, b) << " "
            << "| " << a << " mod " << -b << " = " << myCustomModulo(a, -b) << " |"
            << std::endl
            ;
    for (int a{ 0 }; a < 6; ++a)
        std::cout
            << "|  " << a << " mod " << b << "  =  " << myCustomModulo(a, b) << " "
            << "|  " << a << " mod " << -b << " = " << myCustomModulo(a, -b) << " |"
            << std::endl
            ;
}

int myCustomModulo(const int& a, const int& b)
{
    return (a % b + b) % b;
}

Output:

| mod & +divisor | mod & -divisor |
| :------------- | -------------- |
| -5 mod 3  =  1 | -5 mod -3 = -2 |
| -4 mod 3  =  2 | -4 mod -3 = -1 |
| -3 mod 3  =  0 | -3 mod -3 = 0 |
| -2 mod 3  =  1 | -2 mod -3 = -2 |
| -1 mod 3  =  2 | -1 mod -3 = -1 |
|  0 mod 3  =  0 |  0 mod -3 = 0 |
|  1 mod 3  =  1 |  1 mod -3 = -2 |
|  2 mod 3  =  2 |  2 mod -3 = -1 |
|  3 mod 3  =  0 |  3 mod -3 = 0 |
|  4 mod 3  =  1 |  4 mod -3 = -2 |
|  5 mod 3  =  2 |  5 mod -3 = -1 |

Correct results from your link:

| mod & +divisor | mod & -divisor |
| :------------- | :--------------|
| -5 mod 3 =  1  | -5 mod -3 = -2 |
| -4 mod 3 =  2  | -4 mod -3 = -1 |
| -3 mod 3 =  0  | -3 mod -3 =  0 |
| -2 mod 3 =  1  | -2 mod -3 = -2 |
| -1 mod 3 =  2  | -1 mod -3 = -1 |
|  0 mod 3 =  0  |  0 mod -3 =  0 |
|  1 mod 3 =  1  |  1 mod -3 = -2 |
|  2 mod 3 =  2  |  2 mod -3 = -1 |
|  3 mod 3 =  0  |  3 mod -3 =  0 |
|  4 mod 3 =  1  |  4 mod -3 = -2 |
|  5 mod 3 =  2  |  5 mod -3 = -1 |
1

The remainder() function in the cmath header file is similar to math.floorMod() for integer operations

#include <cmath>
remainder(dividend, divisor)

The remainder function can be recreated as follows

int floor_mod(int x, int y)
{   
   return  x-(x/y)*y  ;  
}
1

While I'm not aware of any intrinsic capable of performing such operation, I'd like to modify the asker's implementation to better mimic the Java function Math.floorMod(dividend,divisor)

constexpr int floor_mod(int dividend, int divisor)
{
    return [divisor, remainder = dividend % divisor] {
        return remainder && (remainder < 0 != divisor < 0)
            ? remainder + divisor
            : remainder;
    } ();
}

Here this function is tested for some trivial inputs.

The overhead due to the extra operations seems to be less than the one needed by an extra modulo (See e.g. those quick benchmarks: (1) or (2)).

Bob__
  • 12,361
  • 3
  • 28
  • 42