Java的Math.floorMod()在C++中的等效函数是什么?

4
在Java中,我们有两种不同的模运算(余数运算),%Math.floorMod()。它们的区别在于映射目标的范围,可以依赖于第一个操作数的符号或第二个操作数的符号。这个页面清楚地解释了两者的差异。 在C++中是否有相同效果且速度较快的操作等同于 Math.floorMod()
目前我使用以下方法(出于性能原因,它甚至与Math.floorMod()不完全相等):
inline int floor_mod(int x, int y) {
    x %= y;

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

    return x;
}

我认为在某些CPU上,可能会有一种内在的或类似的东西,它只编译成1条指令。


难道不应该是 if (y < 0) ... 吗? - Bob__
@Bob__: 假设 x-101y100x %= y 的结果与 x = x % y 相同,因此 x 将会是 -101 % 100,即等于 -1(在 C++ 中)。因此,您需要检查 x 是否为负数,以便必要时取它的补码。 - user12927872
@BlayerBond 嗯,你的版本看起来与Java函数等效,但OP的版本不太一样。 - Bob__
我感到困惑,因为我不理解你上次的评论,以为自己搞错了。同时,我重写了代码以确保它有相同的输出结果。感谢你的评论,你说得对,在处理“signed int”时应该加入额外的if测试条件。我重写了“main”函数进行检查,并获得了更清晰的结果。 - user12927872
3个回答

4

好的...

恐怕你需要自己创建一个。一个一行代码的函数是一个自定义的 floorModulo,但如果你期望的除数是一个无符号整数 unsigned int&,使用一个 if-判断可能会更快速和易读。

#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;
}

输出:

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

您链接的正确结果:

| 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
在cmath头文件中,remainder()函数类似于math.floorMod()用于整数操作。
#include <cmath>
remainder(dividend, divisor)


余数函数可以如下重新创建
int floor_mod(int x, int y)
{   
   return  x-(x/y)*y  ;  
}

1

虽然我不知道是否有任何内在能够执行这种操作的函数,但我想修改提问者的实现方式,以更好地模拟Java函数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;
    } ();
}

这里测试了一些微不足道的输入,该函数与额外模数所需的操作相比开销似乎要小(例如,请参见这些快速基准测试:(1)(2))。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接