UINT subtraction result different MEGA vs ESP8266

Hi,

just hit this issue and I'm not sure whether this is expected or not. when performing calculation with unsigned values (subtracting greater value from smaller), Arduino Returns max uint value plus negative result. That would be fine, as we are working with unsigned ints. Doing the same with signed INTs causes problem not appearing, of course.

This happens when running this program on MEGA32u4 and does not happen when running the same sketch on ESP8266. Didn't try MEGA328 though

I hit this problem when doing a fish feeder with millis() condition if(abs(millis()-lastFeed)>feedFreq){ ... }. when the UINT rolls over, the condition is true immediately after rollover because I get a number close to UINT_MAX. I know I'm using UINT when I'm supposed to use ULONG, but this is only for testing the rollover.

can anybody explain what is going on here and why the behaviour of MEGA is different than on ESP8266?

unsigned int a=4;
unsigned int b=3;


void setup(){
 Serial.begin(115200);
 delay(5000);
}

void loop(){

  Serial.println("==========");
  Serial.println("abs(a-b)="+String(abs(a-b))); // try String(abs()) casting
  Serial.println("abs(b-a)="+String(abs(b-a)));

  Serial.println("----------");
  Serial.println("String(a-b)="+String(a-b)); // try only String() casting
  Serial.println("String(b-a)="+String(b-a));

  Serial.println("----------");
  Serial.print("a-b="); Serial.println(a-b); //default println casting
  Serial.print("b-a="); Serial.println(b-a);

  delay(2000);

}

MEGA32U4 output:

==========
abs(a-b)=1
abs(b-a)=65535
----------
String(a-b)=1
String(b-a)=65535
----------
a-b=1
b-a=65535

ESP8266 output:

==========
abs(a-b)=1
abs(b-a)=1
----------
String(a-b)=1
String(b-a)=-1
----------
a-b=1
b-a=-1

looks like ESP8266's subtraction result is INT and MEGA32U4's result is UINT. workaround could be used like this:

if(d>a){ subtractResult=d-a; } else {subtractResult=a-d; }

but this is inefficient. or do I have to do it this way on MEGA?

EDIT: cleaned up a bit, verify it compiles - it does now

void setup(){
 unsigned int a=4;
 unsigned int b=3;
 unsigned int c=2;
 unsigned int d=1;
 Serial.begin(115200);
}

Those local variables are useless.

The code you posted won't even compile. So, you are pissing into the wind when you talk about it producing incorrect results.

sorry that's me being stupid when cleaning up the code. I've corrected it. it compiles. Now can you advise?

Now can you advise?

No, because you f**ked up. You are NEVER supposed to replace code in the original post, after you get replies telling you that there are problems with it.

Using abs() with an unsigned int argument is just plain stupid. Why do you feel the need to do that?

maybe because on ESP8266 i get a negative value?

I seriously think that your problem has NOTHING to do with math involving unsigned ints, and ALL to do with the String class.

STOP USING THE STRING CLASS JUST SO YOU CAN USE ONE SERIAL PRINT STATEMENT INSTEAD OF TWO.

your caps lock got stuck

you did not get the point what I'm asking for. I'm not asking for syntax check, nor efficiency of using String class.

okay, so to get some real hint, I've stripped the code down to this, hopefully you aren't distracted by something again

Code:

unsigned int a=4;
unsigned int b=3;

void setup(){
 Serial.begin(115200);
 delay(5000);
}

void loop(){
  Serial.println("==========");
  Serial.print("a-b=");
  Serial.println(a-b);
  Serial.print("b-a=");
  Serial.println(b-a);
  delay(2000);
}

MEGA32U4 output:

==========
a-b=1
b-a=65535

ESP8266 output:

==========
a-b=1
b-a=-1

Try this Store b-a in signed type i.e. int and serial print int value. Could be problem with Serial.print() on 16bit vs 32bit(esp8266). On one its overflowing on the other one not. Cant explain have no time to think about that but pretty interesting problem.

surepic:
Try this
Store b-a in signed type i.e. int and serial print int value. Could be problem with Serial.print() on 16bit vs 32bit(esp8266). On one its overflowing on the other one not. Cant explain have no time to think about that but pretty interesting problem.

finally some comment that makes sense. only took few posts, thanks :slight_smile: it might be worth looking at sources, but no idea what to look for

now I’ve found another weird thing. I switched the machine ( -1 was returned by sketch compiled on a Mac) to a Windows one and now I’m getting this from the ESP8266

ESP8266 output

==========
a-b=1
b-a=4294967295

this time it calculates correctly but somehow the result from math operation on two unsigned INTs is a LONG. Sketch is still the same (previously modified to prevent PaulS’ distraction):

unsigned int a=4;
unsigned int b=3;

void setup(){
 Serial.begin(115200);
 delay(5000);
}

void loop(){
  Serial.println("==========");
  Serial.print("a-b=");
  Serial.println(a-b);
  Serial.print("b-a=");
  Serial.println(b-a);
  delay(2000);
}

maybe sir PaulS has something to say here now? or have you found some wrong syntax or String class? :grinning:

If you are now getting 65536 on the Uno and 4294967295 on the ESP, then you are getting correct results. The size of an int, or unsigned int, on the two platforms is different, so the results will be different. This is to be expected.

int isn't a fixed size. Yes, on a Uno and Mega it's 2 bytes but on a ESP8266 it's 4-bytes.

The results which roll over are the ones I would expect. Because uint - uint should happen in uint. Why the Mac compiler does not and threats it as an signed, I don't know.

surepic: Try this Store b-a in signed type i.e. int and serial print int value. Could be problem with Serial.print() on 16bit vs 32bit(esp8266). On one its overflowing on the other one not. Cant explain have no time to think about that but pretty interesting problem.

right, here it is. if I save the result into a signed integer, it is calculated like I operated on signed INTs.

unsigned int a=4;
unsigned int b=3;

signed int resultA,resultB;

void setup(){
 Serial.begin(115200);
 delay(5000);
}

void loop(){

  resultA=a-b; // this would be 1
  resultB=b-a; // this would be -1
  
  Serial.println("==========");
  Serial.print("a-b=");
  Serial.println(a-b);
  Serial.print("b-a=");
  Serial.println(b-a);

  Serial.print("ResultA=");
  Serial.println(resultA);
  Serial.print("ResultB=");
  Serial.println(resultB);
  
  delay(2000);
}

MEGA32U4 output:

==========
a-b=1
b-a=65535
ResultA=1
ResultB=-1

ESP8266 output:

==========
a-b=1
b-a=4294967295
ResultA=1
ResultB=-1

good to know that this is to be expected, thanks.

regarding the original problem where it returned -1 from subtraction of two unsigned values, I'll probably "reinstall" complete IDE on the Mac and test again

thanks again

Thats why sometimes its better to check with sizeof(variable type) to see with how many bytes or bits you gonna deal with.

PaulS: If you are now getting 65536 on the Uno and 4294967295 on the ESP, then you are getting correct results. The size of an int, or unsigned int, on the two platforms is different, so the results will be different. This is to be expected.

septillion: int isn't a fixed size. Yes, on a Uno and Mega it's 2 bytes but on a ESP8266 it's 4-bytes.

Could this be avoided by delcaring the variable as uint16_t instead of unsigned int?

Could this be avoided by delcaring the variable as uint16_t instead of unsigned int?

Yes. A uint16_t is 16 bits on the Arduino and on the ESP.

Thanks for the advices, i'll do it :-)