54

どうやら、x86(およびおそらく他の多くの命令セット)は、除算演算の商と剰余の両方を別々のレジスタに入れます。

これで、コンパイラが次のようなコードを最適化して、除算に 1 つの呼び出しのみを使用することをおそらく信頼できるようになります。

( x / 6 )
( x % 6 )

そして、彼らはおそらくそうします。それでも、除算と剰余の両方の結果を同時に与えることをサポートする言語(またはライブラリ、ただし主に言語を探している) はありますか? もしそうなら、それらは何で、構文はどのように見えますか?

4

9 に答える 9

54

Cはとを持っdivldivいます。これらが商と剰余に対して別々の命令を生成するかどうかは、特定の標準ライブラリの実装とコンパイラおよび最適化の設定によって異なります。C99以降、lldivより多くの数が必要になります。

于 2010-10-09T00:39:18.767 に答える
31

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;
}
于 2010-10-09T00:06:33.937 に答える
11

C#/.NET の場合Math.DivRem: http://msdn.microsoft.com/en-us/library/system.math.divrem.aspx

しかし、このスレッドによると、これはそれほど最適化ではありません。

于 2010-10-09T00:11:35.953 に答える
3

ストリンガーベルが述べたように、.NET3.5まで最適化されていないDivRemものがあります。

.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

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

MSDNリファレンス

于 2010-10-09T00:36:34.217 に答える
3

Common Lispの機能:http ://www.lispworks.com/documentation/HyperSpec/Body/f_floorc.htm

于 2010-10-09T00:16:26.333 に答える
3

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

(ジッターがそのようなことを単一の命令に最適化できるかどうか、または実際に最適化できるかどうかはわかりません。)

于 2010-10-09T00:13:50.893 に答える
2

FWIW, Haskell has both divMod and quotRem that latter of which corresponds directly to the machine instruction (according to Integral operators quot vs. div) while divMod may not.

于 2016-01-11T01:09:38.923 に答える
0
    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
    }
于 2014-11-21T18:55:35.990 に答える