web-dev-qa-db-fra.com

Diviser et obtenir le reste en même temps?

Apparemment, x86 (et probablement beaucoup d'autres jeux d'instructions) place à la fois le quotient et le reste d'une opération de division dans des registres séparés.

Maintenant, nous pouvons probablement faire confiance aux compilateurs pour optimiser un code tel que celui-ci en utilisant un seul appel pour diviser:

( x / 6 )
( x % 6 )

Et ils le font probablement. Néanmoins, les langages (ou les bibliothèques, mais principalement à la recherche de langages) permettent-ils de donner les résultats divide et modulo simultanément? Si oui, de quoi s'agit-il et à quoi ressemble la syntaxe?

42
Ben

C a div ET ldiv . Que cela génère des instructions distinctes pour le quotient et le reste dépendra de l'implémentation de votre bibliothèque standard, des paramètres de compilation et d'optimisation particuliers. À partir de C99, vous avez aussi lldiv pour les plus grands nombres.

46
bta

Python fait.

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

Ce qui est étrange, car Python est un langage de haut niveau.

Ruby aussi:

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

* MODIFIER *

Il convient de noter que l'objectif de ces opérateurs n'est probablement pas de faire le travail de la manière la plus efficace possible. Il est plus probable que les fonctions existent pour des raisons de correction/portabilité.

Pour ceux que ça intéresse, je crois c’est le code de l’implémentation Python pour 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;
}
30
Eloff

En C #/.NET, vous avez Math.DivRem: http://msdn.Microsoft.com/en-us/library/system.math.divrem.aspx

Mais selon ce fil ce n’est pas vraiment une optimisation.

10
Stringer
3
Pedro Rodrigues

Comme l'a mentionné Stringer Bell, il existe DivRem qui n'est pas optimisé jusqu'à .NET 3.5.

Sur .NET 4.0 il utilise NGen .

Les résultats obtenus avec Math.DivRem (debug; release = ~ 11000ms)

11863
11820
11881
11859
11854

Résultats obtenus avec MyDivRem (debug; release = ~ 11000ms)

29177
29214
29472
29277
29196

Projet ciblé pour x86.


Math.DivRem Exemple d'utilisation

int mod1;
int div1 = Math.DivRem(4, 2, out mod1);

Signatures de méthode

DivRem(Int32, Int32, Int32&) : Int32
DivRem(Int64, Int64, Int64&) : Int64

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

Référence MSDN

3
BrunoLM

Le framework .NET a Math.DivRem :

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

Bien que DivRem soit juste un wrapper autour de quelque chose comme ceci:

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

(Je ne sais pas du tout si la gigue peut optimiser ce type de choses en une seule instruction.)

2
LukeH

FWIW, Haskell a à la fois divMod et quotRem dont le dernier correspond directement à l’instruction machine (selon les opérateurs Intégraux quot vs div ), alors que divMod ne peut pas.

1
Jon Wolski

En Java, la classe BigDecimal a l'opération divideAndRemainder renvoyant un tableau de 2 éléments avec le résultat et le reste de la division.

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

Ce retourne le résultat et le reste 

        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