signo rápidamente en flotador C ++ ... ¿Hay alguna dependencia de la plataforma en este código?

StackOverflow https://stackoverflow.com/questions/2508436

Pregunta

La búsqueda en línea, he encontrado la siguiente rutina para calcular el signo de un flotador en formato IEEE. Esto podría extenderse fácilmente a un doble, también.

// returns 1.0f for positive floats, -1.0f for negative floats, 0.0f for zero
inline float fast_sign(float f) {
    if (((int&)f & 0x7FFFFFFF)==0) return 0.f; // test exponent & mantissa bits: is input zero?
    else {
        float r = 1.0f;
        (int&)r |= ((int&)f & 0x80000000); // mask sign bit in f, set it in r if necessary
        return r;
    }
}

( Fuente : `` señal rápida de 32 bits flotantes '' , Peter Schoffhauzer)

Estoy cansado de usar esta rutina, sin embargo, debido a las operaciones de bits binarios. Necesito el código para trabajar en máquinas con diferentes órdenes de bytes, pero no estoy seguro de cuánto de esta previsto por la norma IEEE, ya que no podía encontrar la versión más reciente, publicado este año. Alguien me puede decir si este trabajo, sin tener en cuenta el orden de bytes de la máquina?

Gracias, Patrick

¿Fue útil?

Solución

¿Cómo cree que fabs() y fabsf() se implementan en el sistema, o para que las comparaciones de materia con una constante 0? Si no es por operaciones bit a bit, es muy posiblemente debido a que los autores de compiladores no creen que sería más rápido.

Los problemas de portabilidad con este código son:

  1. int flotador y puede que no tengan el mismo orden de bits o incluso el mismo tamaño. De ahí también, las máscaras podrían estar equivocados.
  2. flotación podría no ser la representación IEEE
  3. Usted rompe las reglas de alias estricto. Se permite que el compilador para asumir que un puntero / referencia a un flotador y un puntero / referencia a un int no puede punto a la misma posición de memoria. Así, por ejemplo, la norma no garantiza que r se inicializa con 1,0 antes de que se modifica de la siguiente línea. Podría volver a ordenar las operaciones. Esto no es pura especulación, ya diferencia de (1) y (2) no está definida, no define a la ejecución, por lo que no necesariamente se puede simplemente mirar hacia arriba para su compilador. Con suficiente optimización, he visto GCC saltar la inicialización de variables flotador que se hace referencia sólo a través de un puntero de tipo hizo juegos de palabras.

Me gustaría primero hacer lo obvio y examinar el código emitido. Sólo si ello resulta poco fiable es que vale la pena pensar en hacer cualquier otra cosa. No tengo ninguna razón particular para pensar que sé más sobre la representación bit a bit de los flotadores que mi compilador; -)

inline float fast_sign(float f) {
    if (f > 0) return 1;
    return (f == 0) ? 0 : -1;
    // or some permutation of the order of the 3 cases
}

[Editar: en realidad, GCC sí hace algo de una comida de que incluso con -O3. El código emitido no es necesariamente lento, pero hace uso de operaciones de punto flotante por lo que no está claro que sea rápido. Por lo que el siguiente paso es punto de referencia, la prueba si la alternativa es más rápido en cualquier compilador que puede poner en sus manos, y si es así que sea algo que la gente portar su código puede activar con un #define o lo que sea, de acuerdo con los resultados de su propia punto de referencia.]

Otros consejos

No hay que olvidar que para mover un valor de coma flotante de un registro FPU a un registro de número entero requiere una escritura en la memoria RAM, seguido de una lectura.

Con el código de punto flotante, que siempre será mejor mirar el cuadro más grande:

Some floating point code
Get sign of floating point value
Some more floating point code

En el escenario anterior, el uso de la FPU para determinar el signo sería más rápido, ya que no habrá una lectura / escritura cabeza 1 . El procesador Intel FPU puede hacer:

FLDZ
FCOMP

que establece las banderas de código de condición para > 0, < 0 y == 0 y se puede utilizar con FCMOVcc.

Inlining lo anterior en código FPU bien escrito le ganará a cualquier número entero manipulaciones de bits y no perder precisión 2 .

Notas:

  1. El Intel IA32 tiene una optimización de lectura tras escritura donde no esperará a que los datos sean comprometidos con la memoria RAM / cache, pero sólo tiene que utilizar el valor directamente. Todavía invalida la memoria caché, aunque por lo que hay un efecto en cadena.
  2. El Intel FPU es 80bits internamente, flotadores son 32 y dobles 64, por lo que la conversión a flotar / doble para recargar como un entero perderá algunos bits de precisión. Estas son partes importantes a medida que está buscando transiciones alrededor de 0.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top