题
显然,X86(可能还有许多其他指令集)将商和其余部分都放在单独的寄存器中。
现在,我们可能可以信任编译器来优化这样的代码,以仅使用一个调用来划分:
( x / 6 )
( x % 6 )
他们可能会这样做。不过,做任何 语言 (或库,但主要是寻找语言)支持同时给出鸿沟和模仿结果吗?如果是这样,它们是什么,语法是什么样的?
解决方案
C有 div
和 ldiv
. 。这些是否生成有关商和余数的单独指令将取决于您的特定标准库实施以及编译器和优化设置。从C99开始,您也有 lldiv
对于更大的数字。
其他提示
python做到了。
>>> divmod(9, 4)
(2, 1)
这很奇怪,因为Python是一种如此高的语言。
Ruby也是如此:
11.divmod(3) #=> [3, 2]
* 编辑 *
应当指出的是,这些操作员的目的可能不是尽可能高效地完成工作,出于正确性/可移植性原因,更有可能存在功能。
对于那些有兴趣的人,我相信 这是代码 整数Divmod实施的Python实施:
static enum divmod_result
i_divmod(register long x, register long y,
long *p_xdivy, long *p_xmody)
{
long xdivy, xmody;
if (y == 0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"integer division or modulo by zero");
return DIVMOD_ERROR;
}
/* (-sys.maxint-1)/-1 is the only overflow case. */
if (y == -1 && UNARY_NEG_WOULD_OVERFLOW(x))
return DIVMOD_OVERFLOW;
xdivy = x / y;
/* xdiv*y can overflow on platforms where x/y gives floor(x/y)
* for x and y with differing signs. (This is unusual
* behaviour, and C99 prohibits it, but it's allowed by C89;
* for an example of overflow, take x = LONG_MIN, y = 5 or x =
* LONG_MAX, y = -5.) However, x - xdivy*y is always
* representable as a long, since it lies strictly between
* -abs(y) and abs(y). We add casts to avoid intermediate
* overflow.
*/
xmody = (long)(x - (unsigned long)xdivy * y);
/* If the signs of x and y differ, and the remainder is non-0,
* C89 doesn't define whether xdivy is now the floor or the
* ceiling of the infinitely precise quotient. We want the floor,
* and we have it iff the remainder's sign matches y's.
*/
if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
xmody += y;
--xdivy;
assert(xmody && ((y ^ xmody) >= 0));
}
*p_xdivy = xdivy;
*p_xmody = xmody;
return DIVMOD_OK;
}
在C#/。网络中您有 Math.DivRem
:
http://msdn.microsoft.com/en-us/library/system.math.divrem.aspx
但根据 这个线程 这并不是那么优化。
正如斯特林格·贝尔(Stringer Bell)提到的那样 DivRem
哪一个 没有优化 最高为.NET 3.5。
在.NET 4.0上 它使用ngen.
我得到的结果 Math.DivRem
(调试;发行= 〜11000ms)
11863
11820
11881
11859
11854
我得到的结果 MyDivRem
(调试;发行= 〜11000ms)
29177
29214
29472
29277
29196
针对X86的项目。
Math.DivRem
用法示例
int mod1;
int div1 = Math.DivRem(4, 2, out mod1);
方法签名
DivRem(Int32, Int32, Int32&) : Int32
DivRem(Int64, Int64, Int64&) : Int64
.NET 4.0代码
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static int DivRem(int a, int b, out int result)
{
result = a % b;
return (a / b);
}
.net 4.0 il
.custom instance void System.Runtime.TargetedPatchingOptOutAttribute::.ctor(string) = { string('Performance critical to inline across NGen image boundaries') }
.maxstack 8
L_0000: ldarg.2
L_0001: ldarg.0
L_0002: ldarg.1
L_0003: rem
L_0004: stind.i4
L_0005: ldarg.0
L_0006: ldarg.1
L_0007: div
L_0008: ret
.NET框架具有 Math.DivRem
:
int mod, div = Math.DivRem(11, 3, out mod);
// mod = 2, div = 3
虽然, DivRem
只是围绕这样的东西的包装:
int div = x / y;
int mod = x % y;
(我不知道抖动能否/确实可以将这种事情优化到单个指令中。)
fwiw,哈斯克尔都有 divMod
和 quotRem
后者直接对应于机器指令(根据 整体运营商报价与div) 尽管 divMod
不得。
int result,rest;
_asm
{
xor edx, edx // pone edx a cero; edx = 0
mov eax, result// eax = 2AF0
mov ecx, radix // ecx = 4
div ecx
mov val, eax
mov rest, edx
}
返回结果剩余的
int result,rest;
_asm
{
xor edx, edx // pone edx a cero; edx = 0
mov eax, result// eax = 2AF0
mov ecx, radix // ecx = 4
div ecx
mov val, eax
mov rest, edx
}
在Java班上 BigDecimal
有操作 divideAndRemainder
返回2个元素的阵列,结果和剩余的分区。
BigDecimal bDecimal = ...
BigDecimal[] result = bDecimal.divideAndRemainder(new BigDecimal(60));