x86 - sub - Divide y consigue el resto al mismo tiempo?
sub instruction assembly (10)
C tiene div
y ldiv
. Si estos generan instrucciones separadas para el cociente y el resto dependerá de su implementación particular de la biblioteca estándar y la configuración del compilador y la optimización. Comenzando con C99, también tienes lldiv
para números más grandes.
Aparentemente, x86 (y probablemente muchos otros conjuntos de instrucciones) ponen tanto el cociente como el resto de una operación dividida en registros separados.
Ahora, probablemente podemos confiar en que los compiladores optimicen un código como este para usar solo una llamada para dividir:
( x / 6 )
( x % 6 )
Y probablemente lo hagan. Aún así, ¿los idiomas (o bibliotecas, pero principalmente en busca de idiomas) admiten dar los resultados de división y módulo al mismo tiempo? Si es así, ¿qué son y cómo se ve la sintaxis?
Common Lisp lo hace: http://www.lispworks.com/documentation/HyperSpec/Body/f_floorc.htm
Como Stringer Bell mencionó, hay DivRem
que no está optimizado hasta .NET 3.5.
En .NET 4.0 usa NGen .
Los resultados que obtuve con Math.DivRem
(debug; release = ~ 11000ms)
11863
11820
11881
11859
11854
Resultados que obtuve con MyDivRem
(depuración; lanzamiento = ~ 11000 ms)
29177
29214
29472
29277
29196
Proyecto apuntado para x86.
Math.DivRem
uso de Math.DivRem
int mod1;
int div1 = Math.DivRem(4, 2, out mod1);
Firmas de métodos
DivRem(Int32, Int32, Int32&) : Int32
DivRem(Int64, Int64, Int64&) : Int64
Código .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
http://msdn.microsoft.com/en-us/library/system.math.divrem.aspx
El framework .NET tiene http://msdn.microsoft.com/en-us/library/system.math.divrem.aspx :
int mod, div = Math.DivRem(11, 3, out mod);
// mod = 2, div = 3
Aunque, DivRem
es solo un contenedor de algo como esto:
int div = x / y;
int mod = x % y;
(No tengo idea de si el jitter puede / optimiza ese tipo de cosas en una sola instrucción).
En C # /. NET tienes Math.DivRem
: http://msdn.microsoft.com/en-us/library/system.math.divrem.aspx
Pero de acuerdo con este hilo esto no es tanto una optimización.
En Java, la clase BigDecimal
tiene la operación divideAndRemainder
devolviendo una matriz de 2 elementos con el resultado y el resto de la división.
BigDecimal bDecimal = ...
BigDecimal[] result = bDecimal.divideAndRemainder(new BigDecimal(60));
Esto devuelve el resultado y el resto
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
}
FWIW, Haskell tiene tanto divMod
como quotRem
el último de los cuales corresponde directamente a la instrucción de máquina (de acuerdo con Operadores integrales vs. div ) mientras que divMod
no.
Python lo hace.
>>> divmod(9, 4)
(2, 1)
Lo cual es extraño, porque Python es un lenguaje de alto nivel.
También lo hace Ruby:
11.divmod(3) #=> [3, 2]
* EDIT *
Cabe señalar que el objetivo de estos operadores es probablemente no hacer el trabajo de la manera más eficiente posible, es más probable que las funciones existan por razones de corrección / portabilidad.
Para los interesados, creo que este es el código de la implementación de Python para divmod entero:
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;
}
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
}