tendencias populares para marketing lista hoy hashtags c++ c optimization math

c++ - populares - hashtags twitter lista



Módulos sin firmar: enfoque alternativo? (12)

Aparte del ciclo while, no estoy seguro de si la operación% se puede optimizar como un todo, pero la optimización puede ocurrir en el patrón de los valores para a & b.

Si en esos 21495808 tiempos se ejecuta la operación.

Si las posibilidades de pasar un valor por a que es menor que b (a <b) es al menos la mitad de eso. Agregar la siguiente declaración definitivamente mejorará el rendimiento general de la función.

if ( abs(a) < b ) // not specifically the abs function, can be your own implementation. return 0; else return a%b;

Si b es una potencia de 2 para al menos el 80% de los casos, podemos usar operadores bit a bit como en

return ( abs(a) & (b-1) );

Si se espera que los números sean algo menos que eso, se degradaría el rendimiento, ya que necesitamos verificar si b es potencia de 2 [incluso después de usar operadores bit a bit para lo mismo] para todo.

Incluso la funcionalidad para lograr abs (a) se puede optimizar utilizando operadores bit a bit, con sus propias limitaciones, pero es más rápido que verificar si a es <0.

n = (a ^ (a >> 31)) - (a >> 31); // instead of n = a < 0 ? -a : a;

Habría más cosas así, si puedes explorar.

Necesito optimizar esta función realmente pequeña pero molesta.

unsigned umod(int a, unsigned b) { while(a < 0) a += b; return a % b; }

Antes de gritar "No es necesario que lo optimice", tenga en cuenta que esta función se llama el 50% de la duración total del programa, ya que se llama 21495808 veces para el benchmark de caso de prueba más pequeño.

La función ya está siendo indicada por el compilador, por lo que no debe agregar la palabra clave en inline .


Aquí hay uno que funciona en toda la gama de unsigned sin ramificación, pero usa multiplicaciones y 2 divisiones

unsigned umod(int a, unsigned b) { return (a>0)*a%b+(a<0)*(b-1-~a%b); }


Dado que la versión de bucle parece ser bastante rápida, intentemos eliminar la división :)

unsigned umod(int a, unsigned b){ while(a>0)a-=b; while(a<0)a+=b; return a; }


Edición portátil, todavía con una sola división, sin ramificaciones y sin multiplicación:

unsigned umod(int a, unsigned b) { int rem = a % (int) b; return rem + (-(rem < 0) & b); }


En a % b , si alguno de los operandos unsigned está unsigned ambos se convierten en unsigned . Esto significa que si a es negativo, obtienes un valor UINT_MAX + 1 módulo en lugar de a . Si UINT_MAX+1 es divisible uniformemente por b , entonces las cosas están bien, y solo puede devolver a % b . Si no, tienes que hacer el módulo en tipo int .

unsigned int umod(int a, unsigned int b) { int ret; if (a >= 0) return a % b; if (b > INT_MAX) return a + b; ret = a % (int)b; if (ret < 0) ret += b; return ret; }

Editar : actualizado, pero debes usar la respuesta de café ya que es más simple (¿o no?). Esto está aquí para el registro.


En su función original, podría haber regresado después de que el ciclo while haya terminado para los números negativos, omitiendo así el mod. Esto tiene el mismo espíritu, reemplazando el bucle con un multiplicador, aunque podría hacerse para tener menos caracteres ...

unsigned int umod2(int a, unsigned int b) { return (a < 0) ? a + ((-a/b)+1)*b : a % b; }

Aquí está la versión de bucle:

unsigned int umod2_works(int a, unsigned int b) { if (a < 0) { while (a < 0) a += b; return a; } else { return a % b; } }

Ambos han sido probados para coincidir con la función original del OP.


Esto debería hacerlo:

unsigned umod(int a, unsigned b) { if (a < 0) { unsigned r = (-a % b); if (r) return b - r; else return 0; } else return a % b; }

Probado para que coincida con el original. La limitación es que a > INT_MIN en máquinas complementarias 2s.


Esto evita el bucle:

int tmp = a % b; if (tmp < 0) tmp += b;

Tenga en cuenta que tanto a como b deben estar firmados.


Mi solución preferida es modificar dos veces. No he intentado esto en C / C ++ o con unsigned, pero mis casos de prueba funcionan en Java:

((a % b) + b) % b

El beneficio no es la bifurcación y la simplicidad. El inconveniente es la doble mod. No comparé el rendimiento, pero tengo entendido que las ramificaciones perjudican el rendimiento en estos días.


Si a y b son mucho más pequeños que un int, entonces puedes simplemente agregar un múltiplo suficientemente grande de b a cada valor antes de modificar.

unsigned umod(int a, unsigned b) { return (unsigned)(a + (int)(b * 256)) % b; }

Por supuesto, este truco no funciona si un + (b * 256) puede desbordarse, pero para muchos de los usos que puedo ver para este código, puedes estar seguro de que nunca lo hará.


Usando el ~ :)

unsigned umod(int a, unsigned b) { if (a<0) return b-1-~a%b; return a%b; }

El % tiene mayor prioridad que -

Si está bien devolver b en lugar de 0 cuando -a es un múltiplo de b, puedes guardar algunas operaciones

unsigned umod(int a, unsigned b) { if (a<0) return b - (-a % b); return a%b; }

versión ligeramente golfizada :)

unsigned umod(int a, unsigned b) { return(a<0)?b-(-a%b):a%b; }

Aquí está el ensamblaje resultante

1 .globl umod3 2 .type umod3, @function 3 umod3: 4 .LFB3: 5 .cfi_startproc 6 testl %edi, %edi 7 js .L18 8 movl %edi, %eax 9 xorl %edx, %edx 10 divl %esi 11 movl %edx, %eax 12 ret 13 .p2align 4,,10 14 .p2align 3 15 .L18: 16 movl %edi, %eax 17 xorl %edx, %edx 18 negl %eax 19 divl %esi 20 subl %edx, %esi 21 movl %esi, %edx 22 movl %edx, %eax 23 ret


int temp; temp= (a > 0)? ( a % b ) : b -( (-a) % b ) ;

código a continuación:

int main() { int a; unsigned b; int temp; printf("please enter an int and a unsigned number/n"); scanf("%d",&a); scanf("%u",&b); modulus(a,b); temp= (a > 0)? ( a % b ) : b -( (-a) % b ) ; printf("/n temp is %d", temp); return 0; } void modulus(int x,unsigned y) { int c; if(x>0) { c=x%y; printf("/n%d/n",c);} else { while(x<0) x+=y; printf("/n%d/n",x);} } ./a.out please enter an int and a unsigned number -8 3 1 temp is 1