Подтвердить что ты не робот

Какая разница между `abs` vs` fabs` в (С++)

Я проверил разницу между abs и fabs на python здесь

Как я понимаю, есть некоторые различия в скорости и переданных типах, но мой вопрос связан с родным c++ на V.S.

Относительно V.S. Я попробовал следующее на Visual Studio 2013 (v120):

float f1= abs(-9.2); // f = 9.2
float f2= fabs(-9); // Compile error [*]

Итак fabs(-9) он даст мне ошибку компилятора, но когда я попытался сделать следующее:

double i = -9;
float f2= fabs(i); // This will work fine

Что я понимаю из первого кода, который он не будет компилировать, потому что fabs(-9) нужен двойной, и компилятор не смог преобразовать -9 в -9.0, но во втором коде компилятор преобразует i=-9 в i=-9.0 во время компиляции, поэтому fabs(i) будет работать нормально.

Любое лучшее объяснение?

Другое дело, почему компилятор не может принять fabs(-9) и преобразовать значение int в double автоматически, как то, что у нас есть в С#?

[*]:

Error: more than one instance of overloaded function "fabs" matches the argument list:
        function "fabs(double _X)"
        function "fabs(float _X)"
        function "fabs(long double _X)"
        argument types are: (int)   
4b9b3361

Ответ 1

В С++ std::abs перегружается как для типов с целыми числами, так и с плавающей точкой. std::fabs работает только с типами с плавающей запятой (pre С++ 11). Обратите внимание, что значение std:: важно, функция C ::abs, которая обычно доступна по наследству, будет обрабатывать только int!

Проблема с

float f2= fabs(-9);

не означает, что преобразование из int (тип -9) в double отсутствует, но компилятор не знает, какое преобразование для выбора (intfloat, double, long double), так как для каждого из этих трех существует a std::fabs. В вашем обходном пути явное указание компилятору использовать преобразование intdouble, поэтому неопределенность исчезает.

С++ 11 решает это, добавляя double fabs( Integral arg );, который вернет abs любого целочисленного типа, преобразованного в double. По-видимому, эта перегрузка также доступна в режиме С++ 98 с libstdС++ и libС++.

В общем, просто используйте std::abs, он пойдет правильно. (Интересная ловушка, отмеченная @Shafik Yaghmour. Беззнаковые целые типы делают смешные вещи на С++.)

Ответ 2

Мой Visual С++ 2008 не знал, что выбрать из long double fabs(long double), float fabs(float) или double fabs(double).

В заявлении double i = -9; компилятор будет знать, что -9 следует преобразовать в double, потому что тип i равен double.


abs() объявляется в stdlib.h и будет иметь дело с int значением.

fabs() объявляется в math.h и будет иметь дело с double значением.

Ответ 3

С С++ 11 использование только abs() очень опасно:

#include <iostream>
#include <cmath>

int main() {
    std::cout << abs(-2.5) << std::endl;
    return 0;
}

Эта программа выводит 2 в результате. (Посмотрите в прямом эфире)

Всегда используйте std::abs():

#include <iostream>
#include <cmath>

int main() {
    std::cout << std::abs(-2.5) << std::endl;
    return 0;
}

Эта программа выводит 2.5.

Вы можете избежать неожиданного результата с помощью using namespace std;, но я бы против этого против него, потому что он считается плохой практикой в ​​целом и потому, что вам нужно найти директиву using, чтобы узнать, означает ли abs() t29 > перегрузка или перегрузка double.