سؤال

على ما يبدو ، يضع x86 (وربما الكثير من مجموعات التعليمات الأخرى) كل من الحاصل والباقي من عملية الفجوة في سجلات منفصلة.

الآن ، يمكننا على الأرجح الوثوق بالمجموعات المترجمين لتحسين رمز مثل هذا لاستخدام مكالمة واحدة فقط لتقسيمها:

( x / 6 )
( x % 6 )

وربما يفعلون. لا يزال ، افعل أي اللغات (أو المكتبات ، ولكن تبحث بشكل رئيسي عن اللغات) دعم إعطاء كل من الانقسام ونتائج Modulo في نفس الوقت؟ إذا كان الأمر كذلك ، كيف هم ، وكيف تبدو بناء الجملة؟

هل كانت مفيدة؟

المحلول

ج لديه div و ldiv. ما إذا كانت هذه تولد تعليمات منفصلة للالتقاط والباقي سيعتمد على تنفيذ مكتبة قياسي وبين إعدادات التحويلات والتحسين. بدءًا من C99 ، لديك أيضًا lldiv لأعداد أكبر.

نصائح أخرى

بيثون يفعل.

>>> divmod(9, 4)
(2, 1)

وهو أمر غريب ، لأن بيثون هي لغة عالية المستوى.

وكذلك يفعل روبي:

11.divmod(3) #=> [3, 2]

* تعديل *

تجدر الإشارة إلى أن الغرض من هؤلاء المشغلين ربما لا يكونون العمل بأكبر قدر ممكن من الكفاءة ، فمن الأرجح أن تكون الوظائف موجودة لأسباب صحيحة/قابلية النقل.

بالنسبة للمهتمين ، أعتقد هذا هو الرمز من تنفيذ Python لـ Integer Divmod:

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#/. NET لديك Math.DivRem: http://msdn.microsoft.com/en-us/library/system.math.divrem.aspx

لكن حسب هذا الموضوع هذا ليس تحسينًا كبيرًا.

كما ذكر سترينجر بيل هناك 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 

مرجع MSDN

إطار .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 ، Haskell لديه كليهما divMod و quotRem هذا الأخير يتوافق مباشرة مع تعليمات الجهاز (حسب مشغلات متكاملة quot مقابل 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
    }

في جافا الفصل BigDecimal لديه العملية divideAndRemainder إرجاع مجموعة من عنصرين مع النتيجة والباقي من القسم.

BigDecimal bDecimal = ...
BigDecimal[] result = bDecimal.divideAndRemainder(new BigDecimal(60));

جافادوك: https://docs.oracle.com/javase/7/docs/api/java/math/bigdecimal.html#divideandremainder(java.math.bigdecimal)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top