قسّم واحصل على الباقي في نفس الوقت؟
سؤال
على ما يبدو ، يضع 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
إطار .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));