Когда использовать fabs и когда достаточно использовать std :: abs?

100

Я предполагаю, что absи fabsпри использовании ведут себя иначе math.h. Но когда я использую только cmathи std::abs, нужно ли мне использовать std::fabsили fabs? Или это не определено?

математика
источник

Ответы:

124

В C ++ всегда достаточно использовать std::abs; он перегружен для всех числовых типов.

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

Майк Сеймур
источник
Так ли это на каждой платформе? Esp. Windows и Mac OS X? Или это хотя бы в стандарте C ++?
math
3
@brubelsabs: да. В C ++ нет необходимости в отдельной функции fabs, поскольку в C ++ есть перегрузка функций (abs может быть определен для многих типов, и это в C ++). Это также гарантируется стандартом. Конечно, если вы покопаетесь в поисках устаревшего компилятора, которому более 10 лет, вы можете найти тот, который его не поддерживает.
stinky472
1
Это в стандарте C ++, так что это дело на каждой платформе с приличным компилятором, включая Windows , и Mac OS X. Пунктом 26.5 говорит , что, в дополнение к intверсии из библиотеки C, есть перегруженные для long, float, doubleи long double. В пункте 26.2.7 также определяется перегрузка для complex.
Майк Сеймур,
6
Если вы забудете std::и просто используете abs, ваш код будет работать в Windows, как ожидалось, но будет использовать intверсию в Linux, что может быть невероятно сложно отладить.
Adversus
" все числовые типы" [ссылка]. Я вижу int, long, long long, std :: intmax_t, float, double, long double. Я не вижу коротких или символьных версий (или неподписанных).
user673679
23

По-прежнему можно использовать аргументы fabsfor doubleи float. Я предпочитаю это , потому что это гарантирует , что , если я случайно обирать std::выключить abs, что поведение остается неизменным с плавающей точкой входа.

Я просто потратил 10 минут на отладку этой самой проблемы из-за моей собственной ошибки в использовании absвместо std::abs. Я предполагал, что это using namespace std;будет вывод, std::absно этого не произошло, и вместо этого использовал версию C.

В любом случае, я считаю, что лучше использовать fabsвместо absввода с плавающей запятой как способ четко задокументировать свое намерение.

Алан Тьюринг
источник
2
Это странно. Ваш звонок должен был быть двусмысленным (и, следовательно, ошибочным), верно?
Ник
Разве вы не должны использовать fabsf для float? Поэтому я не думаю, что они идентичны.
Nick
Остерегайтесь Android NDK g ++, он также уступает функции c abs () вместо std :: abs (). Однако в компиляторе Visual Studio c ++ abs всегда указывает на std :: abs ().
southerton 05
@Nick, я думаю, что согласен с вами: я, кажется, не понимаю такого поведения Алана Тьюринга, т.е. для меня std::absвсегда вызывается перегруженный (а не C-версия abs) при вызове, absесли using namespace std;это объяснено в начало. Я не знаю, зависит ли это от компилятора.
MaviPranav
@Nick не является ошибкой, так как имя функции совпадает. Какой из них будет выбран, определяется реализацией.
Pato Sandaña
11

Есть еще одна причина std::fabsявно рекомендовать ввод с плавающей запятой.

Если вы забыли включить <CMATH>, ваш std::abs(my_float_num)может быть std::abs(int)вместо std::abs(float). Это сложно заметить.

Кеничи Хидай
источник
1

«abs» и «fabs» идентичны только для типов с плавающей запятой C ++, когда они могут быть переведены без неоднозначных сообщений о перегрузке.

Я использую g ++ (g ++ - 7). Вместе с использованием шаблонов и особенно при использовании mpreal бывают случаи с жесткими сообщениями о "неоднозначной перегрузке" - abs(static_cast<T>(x))не всегда это решает. Когда abs неоднозначен, есть вероятность, что fabs работает должным образом. Для sqrt я не нашел такого простого выхода.

С недели я трудно бороться на C ++ «не существующих проблем». Я обновляю старую программу C ++ до C ++ 14 для более широкого и лучшего использования шаблонов, чем это было возможно раньше. Часто один и тот же параметр шаблона может быть любым стандартным типом с плавающей запятой, сложным типом или типом класса. Да и вообще, длинный дубль действовал несколько разумнее, чем другие типы. Все работало, и раньше я включил mpreal. Затем я установил тип float по умолчанию на mpreal и получил массу синтаксических ошибок. Это дало тысячи неоднозначных перегрузок, например, для abs и sqrt, требующих различных решений. Некоторым требовались перегруженные справочные функции, но не по шаблону. Пришлось заменить по отдельности тысячу использований 0.0L и 1.0L точным типом константы с использованием Zero или One или type_cast - автоматическое определение преобразования невозможно из-за двусмысленности.

До мая я находил очень приятным наличие неявных преобразований. Но гораздо проще было бы без них и иметь константы с сохранением типов с безопасным явным преобразованием типа в любой другой стандартный тип константы.

BS3
источник