Home > Back-end >  Why multiplying an integer by a number gives wrong answers in C Arduino?
Why multiplying an integer by a number gives wrong answers in C Arduino?

Time:11-21

I am trying to calculate the value of the potentiometer equivalent to the angle, so I need to multiply by 180 and then divide by the range. Upon doing so, I noticed that the number I'm getting is not the number I was expecting so I started debugging by multiplying by 180 only and realized the output was not as predicted. Here is the simple code that outputs the weird readings: `

#define POTENTIOMETER_PIN A0
int val;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

  // put your main code here, to run repeatedly:
void loop()
{
  val = analogRead(POTENTIOMETER_PIN);
  Serial.println(val*180);
  delay(250);
}

`

A value between (0 to 1023)*180 was expected, rather the serial monitor spits out values such as: -18932 -18752 -18572 -18392 -18392

CodePudding user response:

It would seem that your compiler defines int as being a 16 bit signed number.

Thus there is a limit of 32383 to -32384.

You are exceeding this and so the values 'wrap around'.

Try changing the code to use 'long' instead of 'int'.

CodePudding user response:

Take a look at the map() function for your use case
https://www.arduino.cc/reference/en/language/functions/math/map/

int val = 0;

void loop()
{
  val = analogRead(POTENTIOMETER_PIN);
  val = map(val, 0, 1023, 0, 180);
  Serial.println(val);
}

Internally, this makes use of a larger type than the humble int, using a long, which is (probably) 32-bits rather than 16

From the documentation above

long map(long x, long in_min, long in_max, long out_min, long out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min)   out_min;
}

The reason this works better for you and can do the math correctly is because a 16-bit number doesn't contain enough precision for the multiplication, while map() uses a 32-bit number internally to represent the value while it does the math on it!

Specifically, if, during your logic you rely on 16-bit math, the value exceeds that ~32768 range, it will wrap around and become negative!

https://www.arduino.cc/reference/en/language/variables/data-types/int/

On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1).

Finally, (and there is much debate, including why Arduino chooses to supply int at all) it's generally good practice to always specify exactly the type you you're after such as uint32_t, rather than relying on int, which frustratingly can have a different size on different device targets

On the Arduino Due and SAMD based boards (like MKR1000 and Zero), an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31) - 1).

  • Related