Saltar al contenido

¿Existe una función de signo estándar (signum, sgn) en C / C ++?

Solución:

Sorprendido de que nadie haya publicado la versión de C ++ con seguridad de tipos todavía:

template <typename T> int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}

Beneficios:

  • Realmente implementa signum (-1, 0 o 1). Las implementaciones aquí que usan copysign solo devuelven -1 o 1, que no es signum. Además, algunas implementaciones aquí están devolviendo un float (o T) en lugar de un int, lo que parece un desperdicio.
  • Funciona para ints, flotadores, dobles, cortos sin firmar o cualquier tipo personalizado construible a partir del entero 0 y ordenable.
  • ¡Rápido! copysign es lento, especialmente si necesita promover y luego reducir nuevamente. Esto no tiene ramas y se optimiza de manera excelente.
  • ¡Cumple con los estándares! El truco de bitshift es genial, pero solo funciona para algunas representaciones de bits y no funciona cuando tienes un tipo sin firmar. Podría proporcionarse como una especialización manual cuando sea apropiado.
  • ¡Preciso! Las comparaciones simples con cero pueden mantener la representación interna de alta precisión de la máquina (por ejemplo, 80 bits en x87) y evitar un redondeo prematuro a cero.

Advertencias:

  • Es una plantilla, por lo que la compilación puede llevar más tiempo en algunas circunstancias.
  • Aparentemente, algunas personas piensan en el uso de una función de biblioteca estándar nueva, algo esotérica y muy lenta que ni siquiera implementa signum es más comprensible.
  • los < 0 parte del cheque activa GCC -Wtype-limits advertencia cuando se crea una instancia para un tipo sin firmar. Puede evitar esto usando algunas sobrecargas:

    template <typename T> inline constexpr
    int signum(T x, std::false_type is_signed) {
        return T(0) < x;
    }
    
    template <typename T> inline constexpr
    int signum(T x, std::true_type is_signed) {
        return (T(0) < x) - (x < T(0));
    }
    
    template <typename T> inline constexpr
    int signum(T x) {
        return signum(x, std::is_signed<T>());
    }
    

    (Que es un buen ejemplo de la primera advertencia).

No conozco una función estándar para ello. Sin embargo, aquí hay una forma interesante de escribirlo:

(x > 0) - (x < 0)

Aquí hay una forma más legible de hacerlo:

if (x > 0) return 1;
if (x < 0) return -1;
return 0;

Si te gusta el operador ternario puedes hacer esto:

(x > 0) ? 1 : ((x < 0) ? -1 : 0)

Hay una función de biblioteca matemática C99 llamada copysign (), que toma el signo de un argumento y el valor absoluto del otro:

result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double

le dará un resultado de +/- 1.0, dependiendo del signo de valor. Tenga en cuenta que los ceros de coma flotante están firmados: (+0) dará como resultado +1 y (-0) dará como resultado -1.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : / /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *