HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Generic absolute value function

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
absolutegenericfunctionvalue

Problem

I wanted to write a generic abs function that would correctly work for every type. Basically, I wanted to use the following algorithm:

  • If the type is a built-in integer, use std::abs from `.



  • If the type is a built-in floating-point, use std::abs from .



  • If the type is a user-defined type with a namespace-level abs, use it.



  • Otherwise, call a generic abs algorithm.



Here is what I came up with:

#include 
#include 

namespace math
{
    namespace detail
    {
        // generic abs algorithm
        template
        constexpr auto abs(const T& value)
            -> T
        {
            return (T{} 
    constexpr auto abs(const T& value)
        -> T
    {
        using std::abs;
        using detail::abs;
        return abs(value);
    }
}


The idea is to create a generic
detail::abs algorithm, then to create another abs function that will choose the function to call thanks to the argument-dependant lookup. Here is what I tried to take into account:

-
While the generic algorithm also works for built-in integral and floating point types,
std::abs may produce optimized code for these types. Using std::abs when possible will probably generate an optimized executable. That said, std::abs lacks constexpr, which is a desirable feature, and the compiler might recognize a absolute value-like construct and optimize it away...

-
Some types have a namespace-level
abs that does not behave like the generic algorithm. Therefore, we have to call this namespace-level function if it exist.

-
Some types may be huge. Therefore, I chose to take the parameter by
const& since some namespace-level abs may also take their parameter by const&.

-
Some types only provide
operator

-
I chose to use T{} instead of 0 for the comparison in the generic algorithm in order to be able to represent the default value for any given type. A type is not guaranteed to be comparable to an integer.

Here is a test case to demonstrate what the

Solution

I believe you have a bug in your generic implementation, especially in relation to floating-point style classes that have signed-zero values:

your code:

return (T{} < value) ? value : -value;


would be better as a T{} value) ? -value : value;).

Your current logic will return -0.0 for an input value of 0.0, and that's not appropriate for an abs() function.

Additionally, I don't know how you would really test these things, because, if I am not mistaken, in floating-point comparisons with signed-zero values, -0.0 == 0.0 yet I would expect that abs(-0.0) would return 0.0.

How you resolve this issue though, I don't know.

Code Snippets

return (T{} < value) ? value : -value;

Context

StackExchange Code Review Q#60140, answer score: 5

Revisions (0)

No revisions yet.