获得模数和除法结果的最佳方法?

Ale*_*lex 0 java performance

鉴于模除法和整数除法密切相关,您可能会认为在一次操作中获取这两个值是有意义的。有没有具有这种功能的语言?

后续问题:对于不具备此功能的语言,是否最好通过减去除法 * 分母的结果来计算模数?

// In java, if I want both values I need to do this:
int myNumber = 125;
int denominator = 6;

int division = myNumber / denominator;  // 20
int modulo1   = myNumber % denominator;  // 5

// Follow up: Is this a more efficient way to compute the modulo?
int modulo2 = myNumber - division * denominator;
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 6

使用时BigInteger可以一次运算查询商和余数

\n
BigInteger myNumber = BigInteger.valueOf(125), denominator = BigInteger.valueOf(6);\nBigInteger[] result = myNumber.divideAndRemainder(denominator);\nSystem.out.println(myNumber + " / " + denominator + " = " + result[0]);\nSystem.out.println(myNumber + " % " + denominator + " = " + result[1]);\n
Run Code Online (Sandbox Code Playgroud)\n
125 / 6 = 20\n125 % 6 = 5\n
Run Code Online (Sandbox Code Playgroud)\n

但是,当您使用整数值进行计算时,最好信任 JIT\xc2\xa0compiler/hotspot\xc2\xa0optimizer。

\n

例如当我使用

\n
static void test(int myNumber, int denominator) {\n    int division = myNumber / denominator;  // 20\n    int modulo1   = myNumber % denominator;  // 5\n\n    // prevent over-optimization\n    if(division != 20 || modulo1 != 5) throw new AssertionError();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

并经常运行test(125, 6),我得到以下使用 JDK\xc2\xa011/x86 编译的本机代码

\n
  0x0000029f3ef97b2c: mov     eax,edx\n  0x0000029f3ef97b2e: test    r8d,r8d\n  0x0000029f3ef97b31: je      29f3ef97b63h      ;*idiv {reexecute=0 rethrow=0 return_oop=0}\n                                                ; - SO71326541::test@2 (line 23)\n\n  0x0000029f3ef97b33: cmp     eax,80000000h\n  0x0000029f3ef97b38: jne     29f3ef97b42h\n  0x0000029f3ef97b3a: xor     edx,edx\n  0x0000029f3ef97b3c: cmp     r8d,0ffffffffh\n  0x0000029f3ef97b40: je      29f3ef97b46h\n  0x0000029f3ef97b42: cdq\n  0x0000029f3ef97b43: idiv    eax,r8d\n  0x0000029f3ef97b46: mov     r11d,edx\n  0x0000029f3ef97b49: cmp     eax,14h\n  0x0000029f3ef97b4c: jne     29f3ef97b72h      ;*if_icmpne {reexecute=0 rethrow=0 return_oop=0}\n                                                ; - SO71326541::test@11 (line 27)\n\n  0x0000029f3ef97b4e: cmp     edx,5h\n  0x0000029f3ef97b51: jne     29f3ef97b86h      ;*if_icmpeq {reexecute=0 rethrow=0 return_oop=0}\n                                                ; - SO71326541::test@16 (line 27)\n
Run Code Online (Sandbox Code Playgroud)\n

我们可以清楚地看到,这两个操作,myNumber / denominator已经myNumber % denominator融合成一条idiv指令了。

\n