Absolute function inconsistent results?

I get different results using the abs() function depending on the argument passed to it. In the code below line 18 gives a different result (-10) from line 24 (10). I expected line 27 to give the same as line 33.

Can someone please explain this to me?

Thank you, Dale Gloer

 Serial.begin(115200);
 Serial.println(" Started ") ;

 unsigned int test;
 int Atest;
 int Ftest;
 int eighty = 80;
 int ninety =90;
/* test = ninety - eighty;
 Serial.println(test);
 Atest = abs(test);
 Serial.println(Atest);
 */
 Serial.println(" First try ");
  test = eighty - ninety;
 Serial.println(test);
 Atest = abs(test);                                //  this is line 18
 Serial.println(Atest);
 Serial.println("  Now the math  ");
 Ftest = ninety + Atest;
 Serial.println(Ftest);
 Serial.println("  Now the second try  ");
 Atest = abs(eighty - ninety);                   // this is line 24
 Serial.println(Atest);
 Serial.println("  Now the math  ");
 Ftest = ninety + Atest;
 Serial.println(Ftest);
}

void loop() 
{  
}

abs() is a macro function. To learn more, please look up the implementation of arduino abs() macro.

Atest = abs(eighty - ninety);

abs is a macro, not a function. Everything need to be evaluated before you plunk it in there. There is even a warning to this effect on the reference page for abs ( or at least there was last time I was there)

The variable test is declared to be unsigned. How can it ever be negative?

First of all, an unsigned int can be negative. This only affects the internal representation of the value according to the language reference for int.

Quoting the relevant part: " On the Uno and other ATMEGA based boards, unsigned ints (unsigned integers) are the same as ints in that they store a 2 byte value. Instead of storing negative numbers however they only store positive values, yielding a useful range of 0 to 65,535 ((2^16) - 1). "

Secondly reading the references for the abs() macro, while it appears that it is true that it is a macro, there is also a Function called abs() - defined in the language reference. There is also a way to disable the macro listed in one of the entries.

It is correct that there is a warning about using a function within a abs() call. I need to read more carefully and improve my understanding of what I read. On to making my code do what I need!

Dale Gloer

First of all, an unsigned int can be negative.

By definition, an unsigned variable cannot be negative

The quotation from the language reference does not say that. All it really says is that an int (signed or unsigned) is stored in 2 bytes

This is one of the reasons why macros are stupid to use compared to a proper function. Type safety! I quite like the constraints of a strongly typed language, thank you very much.

If you're not careful about type safety and using signed numbers when negatives are possible, you get weird this like (unsigned int)-1 > 0 being true.

selkirk5934: Secondly reading the references for the abs() macro, while it appears that it is true that it is a macro, there is also a Function called abs() - defined in the language reference. There is also a way to disable the macro listed in one of the entries.

Where do you see it as a function?

This page is talking about the macro. It even includes the warning.

Delta_G: Where do you see it as a function?

In the C and C++ standards.

oqibidipo:
In the C and C++ standards.

Oh, I thought he was saying on the reference section for this site.

In this case, the fact that abs() is a macro has nothing to do with the problem.
abs(x) expands to essentially:

    if (x>0)
      return x;
    return -x;

if x is declared as an unsigned variable, the compiler will recognize the if statement as always TRUE, and will simplify the expression to just “return x”

I thought gcc would issue a warning for this sort of thing (“comparison is always true” or something like that), but:

  • apparently not. (I couldn’t get it to happen, even in a test program outside of Arduino, with -Wall -Wextra)
  • I can’t find the specific warning in the gcc documentation.
  • Arduino compiles typically disable most warnings anyway.

x > 0 is not always true with unsigned x, but x >= 0 is.

cmp.cc:3:12: warning: comparison of unsigned expression >= 0 is always true [-Wtype-limits]
   if (x >= 0) return 1;

x > 0 is not always true with unsigned x, but x >= 0 is.

Ah. It would have worked better if the test had (x<0) instead of (x>0) !
Still seems to need -Wextra