signum function - sign(x)

Hi everyone,

can you please submit your most optimized functions for signum?

If anybody wonder it's defined this way:
if x>0 return 1
if x<0 return -1
if x=0 return 0

I do:

template
type sign(type value) {
return type((value>0)-(value<0));
}

It is part of my Utility library.

Example:

#include <Utility.h>

void setup(){
Serial.begin(9600);

int i = 0;
Serial.println( sign(i), DEC);

char j = -1;
Serial.println( sign(j), DEC);

double k = 3.14;
Serial.println( sign(k), DEC);
}

void loop(){
}

This is probably not the most efficient way? But it is a way :slight_smile:

Minor gotcha with that implementation because AFAIK the C language does not guarantee that expressions return 1 for "true" (they can return any non-zero value).

My favorite implementation is the one that's the clearest to read and lets the compiler do its own optimization (which is usually darned good):

static inline int8_t sgn(int val) {
  if (val < 0) return -1;
  if (val==0) return 0;
  return 1;
}

I bet this will compile to something as efficient as any other method given the quality of GCC today!

1 Like

Minor gotcha with that implementation because AFAIK the C language does not guarantee that expressions return 1 for "true" (they can return any non-zero value).

This might be the case, but Arduino is c++, yes?

In c++ I'm pretty sure a true will be explicitly promoted to the integral value 1.

I agree the version you present is cleaner though.

In c++ I'm pretty sure a true will be explicitly promoted to the integral value 1.

Yup (assuming the compiler is conformant). From conv...

4 An rvalue of type bool can be converted to an rvalue of type int, with
false becoming zero and true becoming one.

4 If the destination type is bool, see conv.bool. If the source type
is bool, the value false is converted to zero and the value true is
converted to one.

Personally, I would (and have) used both constructs regardless of the standard but it's good to know there shouldn't be any future problems.

  • Brian

Cool...learned something.

I think I was wrong about the compiler being super-optimal too. Here's what it came up with (version 4.4.0):

      movw r18,r24
      sbrc r25,7
      rjmp .L7
      ldi r24,lo8(0)
      cp r18,__zero_reg__
      cpc r19,__zero_reg__
      brne .L8
      ret
.L8:
      ldi r24,lo8(1)
      ret
.L7:
      ldi r24,lo8(-1)
      ret

And here's what I came up with, smaller and faster:

signed char sgn(int val) __attribute__((naked));
signed char sgn(int val)
{
  asm (
"      sbrc r25,7\n"
"      rjmp sgn_isNegative\n"

"  sbiw r24,1\n"
"  brpl sgn_isPositive\n"

"      clr  r24\n"
"      ret\n"

"sgn_isPositive:\n"
"      ldi r24,lo8(1)\n"
"      ret\n"

"sgn_isNegative:\n"
"      ldi r24,lo8(-1)\n"
"      ret\n"
  );
}

Warning! Not tested....

Hi ,

can you please submit your functions for signum?

it's defined this way:

if ((x1 != 0) && (x2 != 0) && ( sign(x1) != sign(x2)))
{
p = x1 + x2 ;

}

else if

{
p = sign(x1) * min ( abs(v1), abs(v2));

}

else
{
i want repete until (x1 or / and x2 )!=0

thank you.

oups sorry it's p = sign(x1) * min ( abs(x1), abs(x2));