2015-11-16 8 views
14

Я проверил разницу между abs и fabs на питона hereКакая разница между `abs` против` fabs` в (C++)

Как я понимаю, что есть какая-то разница в отношении скорости и пройденных типов, но мой вопрос, связанный с родным C++ на VS

Относительно 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, чтобы автоматически удвоить то, что у нас есть в C#?

[*]: 

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) 
+0

Здесь нет ошибок компилятора: http://coliru.stacked-crooked.com/a/80c5484bda892461 – NathanOliver

ответ

11

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

Проблема с

float f2= fabs(-9); 

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

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

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

+1

* В общем, просто используйте std :: abs, он пойдет правильно. * ... см. [Is std :: abs (0u) плохо сформирован?] (Http://stackoverflow.com/q/29750946/1708801) –

+0

@ShafikYaghmour Интересно, я никогда не сталкивался с этим. Удивительно, как много целых чисел без знака в C++. «Правильная» реализация, которая преобразует целое число без знака в «double», не является тем, что я ожидал бы от этого кода для TBH. –

+0

Не ошибитесь, это хороший ответ, я случайно столкнулся с этим, и хорошо знать об этом, потому что существует дисперсия внедрения, и она по-прежнему открыта. –

2

Мой Visual C++ 2008 не знаю, какой выбор из long double fabs(long double), float fabs(float) или double fabs(double).

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


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

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

+1

в C++ 'abs' и' fabs' находятся в '': http://en.cppreference.com/ w/cpp/numeric/math/fabs – NathanOliver

+1

@NathanOliver 'std :: abs' и' std :: fabs'. Остальные могут быть, но не обязательно. – juanchopanza

1

С C++ 11, используя abs() в одиночку очень опасно:

#include <iostream> 
#include <cmath> 

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

Эта программа выводит 2 в результате. (See it live)

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

#include <iostream> 
#include <cmath> 

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

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

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

Смежные вопросы