2010-10-09 25 views
38

Aparentemente, x86 (y probablemente muchos otros conjuntos de instrucciones) ponen tanto el cociente como el resto de una operación de división en registros separados.Dividir y obtener el resto al mismo tiempo?

Ahora, podemos probablemente compiladores de confianza para optimizar un código como este para utilizar sólo una llamada a dividir:

(x/6) 
(x % 6) 

Y probablemente hacer. Aún así, ¿algún idiomas (o bibliotecas, pero principalmente en busca de idiomas) admite dar los resultados de dividir y módulo al mismo tiempo? Si es así, ¿qué son y cómo se ve la sintaxis?

+1

el fragmento de código no es un ejemplo de algo que nunca podría ser optimizada de esta manera ... –

+1

Me acabo de dar cuenta que tenía el fragmento de código incorrecto. Actualizado. – Ben

+2

Excelentes respuestas de todos. Apesta que solo puedo elegir uno como la "respuesta" cuando muchos de ellos son respuestas válidas. – Ben

Respuesta

42

C tiene div and 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. A partir de C99, también tiene lldiv para números más grandes.

+7

Es sorprendente por qué no se acepta esta respuesta: coincide exactamente con lo que se pidió. – toriningen

+0

Es interesante observar que el módulo solo no está implementado con 'div' en 4.8: http://stackoverflow.com/questions/4361979/how-does-the-gcc-implementation-of-module-work-and-why-does -it-not-use-the –

+0

Se adelantó y aceptó esta respuesta.Sé que todavía hay muchas respuestas válidas aquí, por lo que es difícil decir que una es "más correcta" que las otras, pero C es un buen punto de partida para hablar de estas cosas. – Ben

28

Python does.

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

Que es extraño, porque Python es un lenguaje de alto nivel.

lo mismo ocurre con Ruby:

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

* EDITAR *

Cabe señalar que el propósito de estos operadores es, probablemente, no para hacer el trabajo tan eficientemente como sea posible, es más probable las funciones existen por razones de corrección/portabilidad.

Para los interesados, creo this is the code de la aplicación 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; 
} 
+0

¿'divmod' ejecuta solo una operación? ¿Cuál es el código detrás de esta función? – BrunoLM

+0

Pegúenme a eso. divmod() es una función incorporada en Python. –

+0

@BrunoLM Apostaría una gran cantidad de [inserte bebida favorita] que 'divmod' simplemente realiza ambas operaciones por separado y empaqueta los resultados, pero no tiene ninguna prueba que ofrecer. –

2

El marco .NET tiene Math.DivRem:

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

Aunque, DivRem es sólo una envoltura alrededor de algo como esto:

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

(no tengo ni idea de si o no la fluctuación puede/hace optimizar ese tipo de cosas en una sola instrucción.)

3

Como Stringer Bell mencionó que hay DivRem que is not optimized hasta .NET 3.5.

En .NET 4.0 it uses NGen.

Los resultados que obtuve con Math.DivRem (depuración; liberar = ~ 11000ms)

11863 
11820 
11881 
11859 
11854 

resultados que obtuve con MyDivRem (depuración; liberar = ~ 11000ms)

29177 
29214 
29472 
29277 
29196 

proyecto destinado para x86.


Math.DivRem Ejemplo de uso

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

firmas de método

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

.NET 4.0 Código

[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 Reference

+3

Esta respuesta es un poco engañosa ya que los tiempos que aparecen parecen mostrar que Math.DivRem está optimizado en .Net 4.0, pero como nota un poco hacia el lado, de hecho no está optimizado en absoluto. De hecho, en mis pruebas, Math.DivRem() es un poco más lento que el ingenuo div y mod ops solo, en todas las versiones de .Net. En otras palabras, no está optimizado en absoluto. –

0
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

Esto devuelve el resultado de una de 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 
    } 
Cuestiones relacionadas