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?
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.
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;
}
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.
LISP commun fait: http://www.lispworks.com/documentation/HyperSpec/Body/f_floorc.htm
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
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.)
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.
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));
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
}
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
}