it-swarm.com.ru

Разделить и получить остаток одновременно?

По-видимому, x86 (и, вероятно, множество других наборов инструкций) помещают как частное, так и остаток операции деления в отдельные регистры.

Теперь мы, вероятно, можем доверять компиляторам для оптимизации кода, такого как этот, чтобы использовать только один вызов для деления:

( x / 6 )
( x % 6 )

И они, вероятно, делают. И все же, поддерживают ли какие-либо languages ​​(или библиотеки, но в основном ищущие языки) одновременное получение результатов и по разделению, и по модулю? Если да, то каковы они и как выглядит синтаксис?

42
Ben

C имеет div И ldiv . Будут ли они генерировать отдельные инструкции для частного и остаточного числа, будет зависеть от вашей конкретной реализации стандартной библиотеки, параметров компилятора и оптимизации. Начиная с C99, у вас также есть lldiv для больших чисел.

46
bta

Python делает.

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

Что странно, потому что Python - язык такого высокого уровня.

Так же как и Ruby:

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

* Правка *

Следует отметить, что цель этих операторов, вероятно, состоит не в том, чтобы выполнять работу настолько эффективно, насколько это возможно, скорее, функции существуют для обеспечения корректности/переносимости.

Для тех, кто заинтересован, я полагаю это код реализации Python для целочисленного 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;
}
30
Eloff

В C # /. NET у вас есть Math.DivRem: http://msdn.Microsoft.com/en-us/library/system.math.divrem.aspx

Но, согласно этой теме , это не такая уж оптимизация.

10
Stringer
3
Pedro Rodrigues

Как упоминал Стрингер Белл, существует DivRem, который не оптимизирован до .NET 3.5.

На .NET 4.0 он использует NGen .

Результаты, которые я получил с помощью Math.DivRem (debug; release = ~ 11000ms)

11863
11820
11881
11859
11854

Результаты, которые я получил с MyDivRem (отладка; выпуск = ~ 11000мс)

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

3
BrunoLM

.NET Framework имеет Math.DivRem :

int mod, div = Math.DivRem(11, 3, out mod);
// mod = 2, div = 3

Хотя DivRem - это просто обертка вокруг чего-то вроде этого:

int div = x / y;
int mod = x % y;

(Я понятия не имею, может ли джиттер оптимизировать такие вещи в одну инструкцию.)

2
LukeH

FWIW, Haskell имеет как divMod , так и quotRem последний из которых напрямую соответствует машинной инструкции (согласно операторы Integral quot и div ), а divMod может не иметь.

1
Jon Wolski

В Java класс BigDecimal имеет операцию divideAndRemainder, возвращающую массив из 2 элементов с результатом и остатком от деления.

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

Javadoc: https://docs.Oracle.com/javase/7/docs/api/Java/math/BigDecimal.html#divideAndRemainder(Java.math.BigDecimal)

0
Iván
    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
    }
0
Ernesto Alfonso

Это возвращает результат де остатка 

        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
    }
0
Ernesto Alfonso