Electronic – Implementing an absolute value function in C

cmathmicrocontroller

I am implementing a function to find the absolute value like this:

uint16_t absolute_value(int16_t n)
{
  int16_t mask = n >> 15;
  return ((n+mask)^mask);
}

Is it any quicker than just doing a simple multiply by -1 if less than 0?

This code is on a microprocessor where speed is everything.

Best Answer

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.

Related Topic