¿Cuándo uso fabs y cuándo es suficiente usar std :: abs?

100

Supongo que absy fabsse comportan de manera diferente al usar math.h. Pero cuando uso solo cmathy std::abs, ¿tengo que usar std::fabso fabs? ¿O no está esto definido?

matemáticas
fuente

Respuestas:

124

En C ++, siempre es suficiente usar std::abs; está sobrecargado para todos los tipos numéricos.

En C, abssolo funciona con números enteros y necesita fabsvalores de punto flotante. Estos están disponibles en C ++ (junto con toda la biblioteca de C), pero no es necesario usarlos.

Mike Seymour
fuente
¿Es así en todas las plataformas? Esp. ¿Windows y Mac OS X? ¿O está al menos en el estándar C ++?
matemáticas
3
@brubelsabs: sí. No hay necesidad de una función fabs separada en C ++ ya que C ++ tiene una sobrecarga de funciones (abs se puede definir para numerosos tipos y está en C ++). También está garantizado por la norma. Por supuesto, si busca un compilador desactualizado de más de 10 años, es posible que encuentre uno que no lo admita.
stinky472
1
Está en el estándar de C ++, por lo que es el caso en todas las plataformas con un compilador decente, incluyendo Windows y Mac OS X. Cláusula 26.5 dice que, además de la intversión de la biblioteca C, hay sobrecargas para long, float, doubley long double. La cláusula 26.2.7 también define una sobrecarga para complex.
Mike Seymour
6
Si olvida el std::y simplemente lo usa abs, su código funcionará como se esperaba en Windows pero usará la intversión en Linux, que puede ser increíblemente difícil de depurar.
Adversus
" todos los tipos numéricos" [cita requerida]. Puedo ver int, long, long long, std :: intmax_t, float, double, long double. No hay versiones cortas o de caracteres (o versiones sin firmar) que pueda ver.
user673679
23

Todavía está bien usar fabspara doubley floatargumentos. Prefiero esto porque asegura que si accidentalmente elimino std::el abs, el comportamiento seguirá siendo el mismo para las entradas de punto flotante.

Acabo de pasar 10 minutos depurando este mismo problema, debido a mi propio error de usar en abslugar de std::abs. Supuse que using namespace std;inferiría std::abspero no fue así, y en su lugar estaba usando la versión C.

De todos modos, creo que es bueno usarlo en fabslugar de abspara entradas de punto flotante como una forma de documentar su intención con claridad.

Alan Turing
fuente
2
Eso es raro. Tu llamada debería haber sido ambigua (y por lo tanto un error) ¿verdad?
Nick
¿No debería usar fabsf para flotar? Entonces no creo que sean idénticos.
Nick
Tenga cuidado con Android NDK g ++, también cede a la función c abs () en lugar de std :: abs (). Sin embargo, en el compilador de Visual Studio c ++, abs siempre apunta a std :: abs ().
southerton
@Nick, creo que estoy de acuerdo contigo: parece que no entiendo ese comportamiento de Alan Turing, es decir, para mí, la sobrecarga std::abssiempre parece invocarse (y no la versión C de abs) al llamar abs, siempre que using namespace std;se explique en el comenzando. Sin embargo, no sé si esto es específico del compilador.
MaviPranav
@Nick no es un error, ya que hay un nombre de función que coincide. Se define la implementación cuál se elegirá.
Pato Sandaña
11

Hay una razón más para recomendar std::fabsexplícitamente las entradas de punto flotante.

Si olvida incluir <cmath>, su std::abs(my_float_num)puede ser en std::abs(int)lugar de std::abs(float). Es difícil de notar.

Kenichi Hidai
fuente
1

"abs" y "fabs" solo son idénticos para los tipos flotantes de C ++, cuando se pueden traducir sin mensajes de sobrecarga ambiguos.

Estoy usando g ++ (g ++ - 7). Junto con el uso de plantillas y especialmente cuando se usa mpreal, hay casos con mensajes de "sobrecarga ambigua", abs(static_cast<T>(x))lo que no siempre resuelve eso. Cuando abs es ambiguo, hay posibilidades de que fabs esté funcionando como se esperaba. Para sqrt no encontré un escape tan simple.

Desde hace semanas estoy luchando duro con C ++ "no existen problemas". Estoy actualizando un programa antiguo de C ++ a C ++ 14 para obtener más y mejor uso de la plantilla que antes. A menudo, el mismo parámetro de plantilla puede ser cualquier tipo flotante estándar o complejo o un tipo de clase. Por qué siempre, el doble de largo actuó algo más sensato que otros tipos. Todo estaba funcionando y ya había incluido mpreal antes. Luego estaba configurando mi tipo flotante predeterminado en mpreal y recibí una avalancha de errores de sintaxis. Eso dio miles de sobrecargas ambiguas, por ejemplo, para abs y sqrt, pidiendo diferentes soluciones. Algunos necesitaban funciones de ayuda sobrecargadas, pero fuera de una plantilla. Tuve que reemplazar individualmente mil usos de 0.0L y 1.0L con el tipo constante exacto usando Zero o One o un type_cast - la definición de conversión automática imposible debido a ambigüedades.

Hasta mayo encontré muy agradable la existencia de conversiones implícitas. Pero sería mucho más simple sin ninguna, y tener constantes de guardado de tipos con conversiones de tipos explícitas seguras a cualquier otro tipo de constante estándar.

BS3
fuente