Signo rápido de entero en C

Hay una función de signo en C:

int sign(int x) { if(x > 0) return 1; if(x < 0) return -1; return 0; } 

Desafortunadamente, el costo de comparación es muy alto, por lo que necesito modificar la función para reducir el número de comparaciones.

Intenté lo siguiente:

 int sign(int x) { int result; result = (-1)*(((unsigned int)x)>>31); if (x > 0) return 1; return result; } 

En este caso solo obtengo una comparación.

¿Hay alguna manera de evitar las comparaciones en absoluto?

EDITAR posible duplicado no da una respuesta para una pregunta ya que todas las respuestas son C ++, utiliza la comparación (que se supone que debo evitar) o no devuelve -1 , +1 , 0 .

En primer lugar, la comparación de enteros es muy barata. Es una ramificación que puede ser costosa (debido al riesgo de predicciones erróneas de la sucursal).

He evaluado su función en una caja de Sandy Bridge usando gcc 4.7.2, y toma aproximadamente 1.2ns por llamada.

Lo siguiente es aproximadamente un 25% más rápido, a aproximadamente 0.9ns por llamada:

 int sign(int x) { return (x > 0) - (x < 0); } 

El código de máquina para lo anterior es completamente sin twigs:

 _sign: xorl %eax, %eax testl %edi, %edi setg %al shrl $31, %edi subl %edi, %eax ret 

Vale la pena señalar dos cosas:

  1. El nivel básico de rendimiento es muy alto.
  2. La eliminación de la ramificación mejora el rendimiento aquí, pero no drásticamente.
 int sign(int x) { // assumes 32-bit int and 2s complement signed shifts work (implementation defined by C spec) return (x>>31) | ((unsigned)-x >> 31); } 

La primera parte ( x>>32 ) le da -1 para números negativos y 0 para 0 o números positivos. La segunda parte le da 1 si x> 0 o igual a INT_MIN, y 0 en caso contrario. O te da la respuesta final correcta.

También está el return (x > 0) - (x < 0); canónico return (x > 0) - (x < 0); Pero, desafortunadamente, la mayoría de los comstackdores usarán twigs para generar código para eso, aunque no haya twigs visibles. Puedes intentar convertirlo manualmente en código sin sucursales como:

 int sign(int x) { // assumes 32-bit int/unsigned return ((unsigned)-x >> 31) - ((unsigned)x >> 31); } 

lo que es posiblemente mejor que lo anterior ya que no depende del comportamiento definido por la implementación, pero tiene un error sutil en el sentido de que devolverá 0 para INT_MIN.

 int sign(int x) { return (x>>31)|(!!x); } 

Si s(x) es una función que devuelve el signo-bit de x (lo implementó mediante ((unsigned int)x)>>31 ), puede combinar s(x) y s(-x) de alguna manera. Aquí hay una “tabla de verdad”:

x> 0: s (x) = 0; s (-x) = 1; tu función debe volver 1

x <0: s (x) = 1; s (-x) = 0; su función debe devolver -1

x = 0: s (x) = 0; s (-x) = 0; su función debe devolver 0

Para que puedas combinarlos de la siguiente manera:

 s(-x) - s(x) 
 int i = -10; if((i & 1 << 31) == 0x80000000)sign = 0;else sign = 1; //sign 1 = -ve, sign 0 = -ve