Я припускаю, що abs
і fabs
поводяться по-різному під час використання math.h
. Але коли я користуюсь просто cmath
та std::abs
, чи повинен я використовувати std::fabs
або fabs
? Або це не визначено?
Я припускаю, що abs
і fabs
поводяться по-різному під час використання math.h
. Але коли я користуюсь просто cmath
та std::abs
, чи повинен я використовувати std::fabs
або fabs
? Або це не визначено?
Відповіді:
У C ++ його завжди достатньо використовувати std::abs
; він перевантажений для всіх числових типів.
У C abs
працює лише ціла кількість, і вам потрібно fabs
для значень з плаваючою точкою. Вони доступні в C ++ (разом із усією бібліотекою С), але використовувати їх не потрібно.
int
версії з бібліотеки C, є перевантажені для long
, float
, double
і long double
. Пункт 26.2.7 також визначає перевантаження для complex
.
std::
та просто користуєтесь abs
, ваш код буде працювати, як очікувалося, на Windows, але він буде використовувати int
версію на Linux, яку неможливо важко налагодити.
Це все ще добре використовувати fabs
для double
і float
аргументів. Я вважаю за краще це, тому що це гарантує, що якщо я випадково std::
позбавив його abs
, поведінка залишиться однаковою для входів з плаваючою точкою.
Щойно я витратив на налагодження цю саму проблему 10 хвилин через мою власну помилку використання abs
замість цього std::abs
. Я припускав, що using namespace std;
буде std::abs
зроблено висновок, але цього не було, і натомість використовував версію C.
У будь-якому випадку, я вважаю, що це добре використовувати fabs
замість abs
входів з плаваючою комою як спосіб чіткого документування свого наміру.
std::abs
завжди, як видається, викликається (а не C-версіями abs
) під час виклику до abs
тих пір, поки using namespace std;
це пояснюється на початок. Я не знаю, чи це конкретний компілятор.
Є ще одна причина рекомендувати std::fabs
явно вводити з плаваючою комою.
Якщо ви забудете включити <cmath>, std::abs(my_float_num)
можна std::abs(int)
замість цього std::abs(float)
. Це важко помітити.
"abs" і "fabs" ідентичні лише для плавких типів C ++, коли їх можна перекладати без неоднозначних повідомлень про перевантаження.
Я використовую g ++ (g ++ - 7). Разом із використанням шаблонів, особливо при використанні mpreal, є випадки з важкими повідомленнями про «неоднозначне перевантаження» - abs(static_cast<T>(x))
це не завжди це вирішує. Коли абс неоднозначний, є ймовірність, що файли працюють так, як очікувалося. Для sqrt я не знайшов такої простої втечі.
З тижнів я важко борюся над C ++ "не існуючими проблемами". Я оновлюю стару програму C ++ до C ++ 14 для більшого та кращого використання шаблонів, ніж це можливо раніше. Часто один і той же параметр шаблону може бути фактичним для будь-якого стандартного поплавця або складного типу або типу класу. Чому колись довгі подвійні діяли дещо розумнішими, ніж інші типи. Все працювало, і я раніше включав mpreal. Тоді я встановлював мій тип float за замовчуванням mpreal і отримував помилки синтаксису. Це дало тисячі неоднозначних перевантажень, наприклад, для abs та sqrt, плачу за різними рішеннями. Деякі потребували перевантажених довідкових функцій, але поза шаблоном. Довелося індивідуально замінювати тисячу звичань 0,0L та 1,0L на точний постійний тип, використовуючи Zero або One або type_cast - визначення автоматичного перетворення неможливе через неоднозначності.
До травня я вважав, що наявна неявна конверсія є дуже приємною. Але набагато простіше було б без будь-якого і мати тип-збереження констант із безпечними явними type_casts до будь-якого іншого стандартного постійного типу.