Since they are the implementation, they are free to make as many assumptions as they want. They know the format of the double and can play tricks with that instead.
Likely (as in almost not even a question), your double is the binary64 format. This means the sign has it's own bit, and an absolute value is merely clearing that bit. For example, as a specialization, a compiler implementer may do the following:
template <>
double abs<double>(const double x)
{
// breaks strict aliasing, but compiler writer knows this behavior for the platform
uint64_t i = reinterpret_cast<const std::uint64_t&>(x);
i &= 0x7FFFFFFFFFFFFFFFULL; // clear sign bit
return reinterpret_cast<const double&>(i);
}
This removes branching and may run faster.
Answer from GManNickG on Stack OverflowHow to get absolute value from double - c-language - Stack Overflow
microcontroller - Implementing an absolute value function in C - Electrical Engineering Stack Exchange
Fast abs function
Simple C Question on abs() and fabs()
Videos
Since they are the implementation, they are free to make as many assumptions as they want. They know the format of the double and can play tricks with that instead.
Likely (as in almost not even a question), your double is the binary64 format. This means the sign has it's own bit, and an absolute value is merely clearing that bit. For example, as a specialization, a compiler implementer may do the following:
template <>
double abs<double>(const double x)
{
// breaks strict aliasing, but compiler writer knows this behavior for the platform
uint64_t i = reinterpret_cast<const std::uint64_t&>(x);
i &= 0x7FFFFFFFFFFFFFFFULL; // clear sign bit
return reinterpret_cast<const double&>(i);
}
This removes branching and may run faster.
There are well-known tricks for computing the absolute value of a two's complement signed number. If the number is negative, flip all the bits and add 1, that is, xor with -1 and subtract -1. If it is positive, do nothing, that is, xor with 0 and subtract 0.
int my_abs(int x)
{
int s = x >> 31;
return (x ^ s) - s;
}
The standard C library is providing the optimized solutions for many problems with considerations based on the architecture, compiler in use and others. The abs() function defined in stdlib.h is one of these, and it is used for your purpose exactly. To emphasize the point, here is ARM compiler result when using abs vs a version of a homebrew abs: https://arm.godbolt.org/z/aO7t1n
Paste:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
srand(111);
int x = rand() - 200;
printf("%d\n", abs(x));
}
results in
main:
push {r4, lr}
mov r0, #111
bl srand
bl rand
sub r1, r0, #200
cmp r1, #0
rsblt r1, r1, #0
ldr r0, .L4
bl printf
mov r0, #0
pop {r4, pc}
.L4:
.word .LC0
.LC0:
.ascii "%d\012\000"
And
#include <stdio.h>
#include <stdlib.h>
int my_abs(int x)
{
return x < 0 ? -x : x;
}
int main(void)
{
srand(111);
int x = rand() - 200;
printf("%d\n", my_abs(x));
}
results in
my_abs:
cmp r0, #0
rsblt r0, r0, #0
bx lr
main:
push {r4, lr}
mov r0, #111
bl srand
bl rand
sub r1, r0, #200
cmp r1, #0
rsblt r1, r1, #0
ldr r0, .L5
bl printf
mov r0, #0
pop {r4, pc}
.L5:
.word .LC0
.LC0:
.ascii "%d\012\000"
Notice that the main code is identical (only a label name is different) in both programs as my_abs got inlined, and its implementation is the same as the standard one.
The speed of a given solution will depend greatly on the architecture, but in C I would say
return (n > 0 ? n : -n);
and let the compiler figure out the best solution.
EDIT: @jonk points out correctly that this will fail for the most-negative possible value of n, assuming that two's-complement arithmetic is used.
Yes, my solution has a conditional branch, but yours has an arithmetic operator and two bitwise operators. Can your microcontroller shift 15 places in a single clock?
So, I was thinking of making fast abs function, which would be necesary to improve performance, and I had an idea to do it something like this
int abs(int input){
return input & -0;
}Essentially, I am trying to make a simple function that removes the sign bit. The problem is, I heard that alot of compliers would ignore this because its a zero. How could I do it that compliers wouldnt ignore it, and it would work for the intended purpose?
Edit: Thanks for all the answers the issue has been resolved!