Quando devo usar fabs e quando é suficiente usar std :: abs?

100

Presumo que abse fabsestão se comportando de forma diferente ao usar math.h. Mas quando uso apenas cmathe std::abs, devo usar std::fabsou fabs? Ou isso não está definido?

matemática
fonte

Respostas:

124

Em C ++, é sempre suficiente usar std::abs; ele está sobrecarregado para todos os tipos numéricos.

Em C, abssó funciona com inteiros e você precisa fabsde valores de ponto flutuante. Eles estão disponíveis em C ++ (junto com toda a biblioteca C), mas não há necessidade de usá-los.

Mike Seymour
fonte
Isso ocorre em todas as plataformas? Esp. Windows e Mac OS X? Ou pelo menos no padrão C ++?
matemática
3
@brubelsabs: sim. Não há necessidade de uma função fabs separada em C ++, pois C ++ tem sobrecarga de função (abs pode ser definido para vários tipos e está em C ++). Também é garantido pela norma. Claro, se você procurar por algum compilador desatualizado com mais de 10 anos, poderá encontrar um que não o suporte.
fedorento472
1
Está no padrão C ++, por isso é o caso em todas as plataformas com um compilador decente, incluindo Windows e Mac OS X. Cláusula 26.5 diz que, além da intversão da biblioteca C, há sobrecargas para long, float, doublee long double. A cláusula 26.2.7 também define uma sobrecarga para complex.
Mike Seymour
6
Se você esquecer o std::e apenas usar abs, seu código funcionará como esperado no windows, mas usará a intversão no linux, o que pode ser incrivelmente difícil de depurar.
Adversus
" todos os tipos numéricos" [carece de fontes?]. Posso ver int, long, long long, std :: intmax_t, float, double, long double. Nenhuma versão curta ou com caracteres (ou versões sem sinal) que eu possa ver.
user673679
23

Ainda não há problema em usar fabspara doublee floatargumentos. Eu prefiro isso porque garante que, se eu acidentalmente remover std::o abs, que o comportamento permanecerá o mesmo para entradas de ponto flutuante.

Acabei de passar 10 minutos depurando esse problema, devido ao meu próprio erro de usar em absvez de std::abs. Presumi que o using namespace std;iria inferir, std::absmas isso não aconteceu e, em vez disso, estava usando a versão C.

De qualquer forma, acredito que seja bom usar em fabsvez de absentradas de ponto flutuante como uma forma de documentar claramente sua intenção.

Alan Turing
fonte
2
Isso é estranho. Sua chamada deveria ter sido ambígua (e, portanto, um erro) certo?
Nick
Você não deveria usar o fabsf para flutuar? Portanto, não acho que sejam idênticos.
Nick
Cuidado com o Android NDK g ++, ele também cede à função c abs () em vez de std :: abs (). No entanto, no compilador do Visual Studio c ++, abs sempre aponta para std :: abs ().
southerton
@ Nick, acho que concordo com você: não consigo entender esse comportamento de Alan Turing, ou seja, para mim, o sobrecarregado std::abssempre parece ser invocado (e não a versão C de abs) ao chamar abs, desde que using namespace std;esteja explicado no começando. Não sei se isso é específico do compilador.
MaviPranav
@Nick não é um erro, pois há um nome de função que corresponde. É a implementação definida qual será escolhido.
Pato Sandaña
11

Há mais um motivo para recomendar std::fabsexplicitamente entradas de ponto flutuante.

Se você esquecer de incluir <cmath>, seu std::abs(my_float_num)pode ser em std::abs(int)vez de std::abs(float). É difícil perceber.

Kenichi Hidai
fonte
1

"abs" e "fabs" são idênticos apenas para tipos de float C ++, quando podem ser traduzidos sem mensagens de sobrecarga ambíguas.

Estou usando o g ++ (g ++ - 7). Junto com o uso do template e especialmente ao usar o mpreal, há casos com mensagens de "sobrecarga ambígua" - abs(static_cast<T>(x))nem sempre resolvendo isso. Quando o abdômen é ambíguo, há chances de que os fabs estejam funcionando conforme o esperado. Para sqrt, não encontrei um escape tão simples.

Há semanas estou lutando arduamente em C ++ "problemas não existentes". Estou atualizando um programa C ++ antigo para C ++ 14 para obter mais e melhor uso de modelos do que antes. Freqüentemente, o mesmo parâmetro de modelo pode ser real qualquer tipo float padrão ou complexo ou um tipo de classe. Por que razão, long double agiu de forma um pouco mais sensata do que outros tipos. Tudo estava funcionando, e eu havia incluído a refeição antes. Então, eu estava configurando meu tipo de float padrão para mpreal e recebi um dilúvio de erros de sintaxe. Isso gerou milhares de sobrecargas ambíguas, por exemplo, para abdominais e sqrt, clamando por soluções diferentes. Alguns precisavam de funções de ajuda sobrecarregadas, mas fora de um modelo. Tive que substituir individualmente mil utilizações de 0,0L e 1,0L pelo tipo de constante exata usando Zero ou Um ou um type_cast - definição de conversão automática impossível devido às ambigüidades.

Até maio achei muito legal a existência de conversões implícitas. Mas muito mais simples seria sem nenhum, e ter constantes typesave com type_casts explícitos seguros para qualquer outro tipo de constante padrão.

BS3
fonte