When to use fabsf rather than fabs

In C++, there is hardly ever a reason to use fabsf. Use std::abs instead with floating point types. std::fabs may have use when you wish to convert the absolute value of an integer to double, but that's probably quite niche use case.

If you were writing C instead, then it is almost as simple: Use fabsf when you have a float, and fabs when you have a double. Same applies to other standard math functions with f suffix.

The definitions I have in my math.h are

_Check_return_ inline float fabs(_In_ float _Xx) _NOEXCEPT

The C++ standard library specifies overloads for std::fabs. One of them takes a float. Your standard library is not standard compliant, if the other overloads are missing.

The C standard library specifies double fabs(double). Your standard library is not standard compliant, if the quoted declaration applies to C.

Answer from eerorika on Stack Overflow
Top answer
1 of 3
4

You can easily test different possibilities using the code below. It essentially tests your bitfiddling against naive template abs, and std::abs. Not surprisingly, naive template abs wins. Well, kind of surprisingly it wins. I'd expect std::abs to be equally fast. Note that -O3 actually makes things slower (at least on coliru).

Coliru's host system shows these timings:

random number generation: 4240 ms
naive template abs: 190 ms
ugly bitfiddling abs: 241 ms
std::abs: 204 ms
::fabsf: 202 ms

And these timings for a Virtualbox VM running Arch with GCC 4.9 on a Core i7:

random number generation: 1453 ms
naive template abs: 73 ms
ugly bitfiddling abs: 97 ms
std::abs: 57 ms
::fabsf: 80 ms

And these timings on MSVS2013 (Windows 7 x64):

random number generation: 671 ms
naive template abs: 59 ms
ugly bitfiddling abs: 129 ms
std::abs: 109 ms
::fabsf: 109 ms

If I haven't made some blatantly obvious mistake in this benchmark code (don't shoot me over it, I wrote this up in about 2 minutes), I'd say just use std::abs, or the template version if that turns out to be slightly faster for you.


The code:

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>

#include <math.h>

using Clock = std::chrono::high_resolution_clock;
using milliseconds = std::chrono::milliseconds;

template<typename T>
T abs_template(T t)
{
  return t>0 ? t : -t;
}

float abs_ugly(float f)
{
  (*reinterpret_cast<std::uint32_t*>(&f)) &= 0x7fffffff;
  return f;
}

int main()
{
  std::random_device rd;
  std::mt19937 mersenne(rd());
  std::uniform_real_distribution<> dist(-std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());

  std::vector<float> v(100000000);

  Clock::time_point t0 = Clock::now();

  std::generate(std::begin(v), std::end(v), [&dist, &mersenne]() { return dist(mersenne); });

  Clock::time_point trand = Clock::now();

  volatile float temp;
  for (float f : v)
    temp = abs_template(f);

  Clock::time_point ttemplate = Clock::now();

  for (float f : v)
    temp = abs_ugly(f);

  Clock::time_point tugly = Clock::now();

  for (float f : v)
    temp = std::abs(f);

  Clock::time_point tstd = Clock::now();

  for (float f : v)
    temp = ::fabsf(f);

  Clock::time_point tfabsf = Clock::now();

  milliseconds random_time = std::chrono::duration_cast<milliseconds>(trand - t0);
  milliseconds template_time = std::chrono::duration_cast<milliseconds>(ttemplate - trand);
  milliseconds ugly_time = std::chrono::duration_cast<milliseconds>(tugly - ttemplate);
  milliseconds std_time = std::chrono::duration_cast<milliseconds>(tstd - tugly);
  milliseconds c_time = std::chrono::duration_cast<milliseconds>(tfabsf - tstd);
  std::cout << "random number generation: " << random_time.count() << " ms\n"
    << "naive template abs: " << template_time.count() << " ms\n"
    << "ugly bitfiddling abs: " << ugly_time.count() << " ms\n"
    << "std::abs: " << std_time.count() << " ms\n"
    << "::fabsf: " << c_time.count() << " ms\n";
}

Oh, and to answer your actual question: if the compiler can't generate more efficient code, I doubt there is a faster way save for micro-optimized assembly, especially for elementary operations such as this.

2 of 3
3

There are many things at play here. First off, the x87 co-processor is deprecated in favor of SSE/AVX, so I'm surprised to read that your compiler still uses the fabs instruction. It's quite possible that the others who posted benchmark answers on this question use a platform that supports SSE. Your results might be wildly different.

I'm not sure why your compiler uses a different logic for fabs and fabsf. It's totally possible to load a float to the x87 stack and use the fabs instruction on it just as easily. The problem with reproducing this by yourself, without compiler support, is that you can't integrate the operation into the compiler's normal optimizing pipeline: if you say "load this float, use the fabs instruction, return this float to memory", then the compiler will do exactly that... and it may involve putting back to memory a float that was already ready to be processed, loading it back in, using the fabs instruction, putting it back to memory, and loading it again to the x87 stack to resume the normal, optimizable pipeline. This would be four wasted load-store operations because it only needed to do fabs.

In short, you are unlikely to beat integrated compiler support for floating-point operations. If you don't have this support, inline assembler might just make things even slower than they presumably already are. The fastest thing for you to do might even be to use the fabs function instead of the fabsf function on your floats.

For reference, modern compilers and modern platforms use the SSE instructions andps (for floats) and andpd (for doubles) to AND out the bit sign, very much like you're doing yourself, but dodging all the language semantics issues. They're both as fast. Modern compilers may also detect patterns like x < 0 ? -x : x and produce the optimal andps/andpd instruction without the need for a compiler intrinsic.

🌐
Cppreference
en.cppreference.com β€Ί w β€Ί c β€Ί numeric β€Ί math β€Ί fabs
fabs, fabsf, fabsl, fabsd32, fabsd64, fabsd128 - cppreference.com
7) Type-generic macro: If the argument has type _Decimal128, _Decimal64, _Decimal32,(since C23)long double, double, or float, fabsd128, fabsd64, fabsd32,(since C23)fabsl, fabs, or fabsf is called, respectively. Otherwise, if the argument has integer type, fabs is called.
🌐
Microsoft Learn
learn.microsoft.com β€Ί en-us β€Ί cpp β€Ί c-runtime-library β€Ί reference β€Ί fabs-fabsf-fabsl
fabs, fabsf, fabsl | Microsoft Learn
You can try signing in or changing directories. Access to this page requires authorization. You can try changing directories. ... Calculates the absolute value of the floating-point argument. double fabs( double x ); float fabs( float x ); // C++ only long double fabs( long double x ); // C++ only float fabsf( float x ); long double fabsl( long double x ); #define fabs(X) // Requires C11 or later
🌐
Cppreference
en.cppreference.com β€Ί w β€Ί cpp β€Ί numeric β€Ί math β€Ί fabs.html
std::abs(float), std::fabs, std::fabsf, std::fabsl - cppreference.com
The additional overloads are not required to be provided exactly as (A). They only need to be sufficient to ensure that for their argument num of integer type, std::fabs(num) has the same effect as std::fabs(static_cast<double>(num)).
🌐
Linux Man Pages
man7.org β€Ί linux β€Ί man-pages β€Ί man3 β€Ί fabs.3.html
fabs(3) - Linux manual page
For an explanation of the terms used in this section, see attributes(7). β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Interface β”‚ Attribute β”‚ Value β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ fabs(), fabsf(), fabsl() β”‚ Thread safety β”‚ MT-Safe β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
🌐
Apple Developer
developer.apple.com β€Ί forums β€Ί thread β€Ί 90710
What does the function "fabs(_:)" … | Apple Developer Forums
In the case of the "abs" function ... parameter. That meant the floating point versions needed different names, so: "fabs", "fabsf" and "fabsl", with the initial "f" meaning "floating point"....
🌐
Lsu
ld2014.scusa.lsu.edu β€Ί cppreference β€Ί en β€Ί c β€Ί numeric β€Ί math β€Ί fabs.html
fabs, fabsf, fabsl - cppreference.com
Otherwise, if the argument has integer type or has type double, fabs is called. Otherwise, fabsf is called. If the argument is complex, then the macro invokes the corresponding complex function (cabsf, cabs, cabsl) If successful, returns the absolute value of arg (|arg|).
Find elsewhere
🌐
MKSSoftware
mkssoftware.com β€Ί docs β€Ί man3 β€Ί fabs.3.asp
fabs(), fabsf() -- floating-point absolute value function
fabsf() function is a single-precision version of Β· fabs(). x Β· Is a floating point value. The Β· fabs() function returns the absolute value of x. If x is NaN, NaN is returned. If the result underflows, 0 is returned. fabs(): ANSI/ISO 9899-1990 Β· fabsf(): PTC MKS Toolkit UNIX APIs extension Β·
🌐
Qnx
qnx.com β€Ί developers β€Ί docs β€Ί 8.0 β€Ί com.qnx.doc.neutrino.lib_ref β€Ί topic β€Ί f β€Ί fabs.html
fabs(), fabsf(), fabsl()
If you want all processes to use ... option to prevent the compiler from using a built-in version of the function. The fabs(), fabsf(), and fabsl() functions compute the absolute value of x....
🌐
Microsoft Learn
learn.microsoft.com β€Ί en-us β€Ί previous-versions β€Ί visualstudio β€Ί visual-studio-2013 β€Ί 18z15bk0(v=vs.120)
fabs, fabsf | Microsoft Learn
You can try signing in or changing directories. Access to this page requires authorization. You can try changing directories. ... Calculates the absolute value of the floating-point argument. double fabs( double x ); float fabs( float x ); // C++ only long double fabs( long double x ); // C++ only float fabsf( float x );
🌐
Linux Man Pages
linux.die.net β€Ί man β€Ί 3 β€Ί fabs
fabs(3) - Linux man page
fabs, fabsf, fabsl - absolute value of floating-point number
🌐
Cplusplus
cplusplus.com β€Ί reference β€Ί cmath β€Ί fabs
fabs
sqrt Β· tan Β· tanh Β· C++11 tgamma Β· C++11 trunc Β· HUGE_VAL Β· C++11 HUGE_VALF Β· C++11 HUGE_VALL Β· C++11 INFINITY Β· C++11 math_errhandling Β· NAN Β· C++11 double_t Β· float_t Β· Reference Β· <cmath> fabs Β· function Β· <cmath> <ctgmath> double fabs (double x); double fabs (double x); float fabsf (float x);long double fabsl (long double x); double fabs (double x); float fabs (float x);long double fabs (long double x); double fabs (double x); float fabs (float x);long double fabs (long double x); double fabs (T x); // additional overloads for integral types Β·
🌐
The Open Group
pubs.opengroup.org β€Ί onlinepubs β€Ί 9699919799 β€Ί functions β€Ί fabs.html
fabs
The DESCRIPTION is updated to indicate how an application should check for an error. This text was previously published in the APPLICATION USAGE section. The fabsf() and fabsl() functions are added for alignment with the ISO/IEC 9899:1999 standard.
🌐
Cplusplus
cplusplus.com β€Ί forum β€Ί general β€Ί 87998
Converting speed - C++ Forum
From the example above, it seems the fabsf() function is redundant because it performs very slow and without it the basic C code still works very well (lighting speed IMO).
🌐
Reddit
reddit.com β€Ί r/cpp_questions β€Ί difference between abs() and fabs(), and can i replace with each other in the program?? and abs() fn is kinda not working.....
r/cpp_questions on Reddit: Difference between abs() and fabs(), and can i replace with each other in the program?? And abs() fn is kinda not working.....
November 26, 2019 - fabs is one of a family of type-specific names from C. The C++ standard libraries provide these names, fabsf for float, fabs for double and fabsl for long double, for compatibility with C, so that barring other issues C code that uses these ...
🌐
GitHub
github.com β€Ί cole-trapnell-lab β€Ί cufflinks β€Ί issues β€Ί 116
Please use std::fabs instead of just fabs in C++ to avoid conflicts Β· Issue #116 Β· cole-trapnell-lab/cufflinks
March 23, 2019 - Please use std::fabs instead of just fabs in C++ to avoid conflicts#116 Β· Copy link Β· yurivict Β· opened Β· on May 25, 2019 Β· Issue body actions Β· clang-8 compiler complains about fabs on BSDs: In file included from codons.cpp:1: In file included from ./codons.h:3: In file included from ./GBase.h:13: /usr/include/c++/v1/math.h:761:41: error: no member named 'fabsf' in the global namespace; did you mean 'fabs'? abs(float __lcpp_x) _NOEXCEPT {return ::fabsf(__lcpp_x);} ~~^ /usr/include/math.h:255:8: note: 'fabs' declared here double fabs(double) __pure2; ^ In file included from codons.cpp:1:
Published Β  May 25, 2019
Author Β  yurivict
🌐
Cplusplus
cplusplus.com β€Ί forum β€Ί beginner β€Ί 136274
fabs versus abs? - C++ Forum
Actually, no. For floating point types it is usually something like: