Compiler bug?

Hi,
I’m using an AT Mega2560 with a GPS module and a TFT screen.
In order to display the relative position on screen I need to convert an ASCII string of numbers into an integer.
To convert the ASCII number I have simply subtracted the value of “0” then multiplied it by 1,10,100 etc according to its position in the string.
This all works fine until a number greater than 3 is multiplied by 10,000 which gives a totally wrong result.
Multiplying by 100,000 then dividing by 10 gives the correct answer.
I have extracted the code and listed it below. This will print to console 4 sets of numbers, 2 with original code and 2 with corrected code.
This should cut and paste into the Arduino IDE.

Using the same code (changing the print functions) and compiling it with Code::Blocks to run on the PC gives fully working code.
I only have the AT Mega2560 so can’t say if it works on any other Arduino.
I sure that the AT Mega I’m using is ok as other maths functions (sine, cos, tan etc) work fine.
Have I miss understood something or is this a bug in the compiler?

void setup() {
 #include <string.h>
 #include <ctype.h>

  Serial.begin(9600);
char arr1[]={'3','3','3','3','3','3'};    //this works
 char arr[]={'5','5','5','5','5','5'};  //this doesn't work
 prnArray((char*)arr);
prnArray((char*)arr1);
 prnArray1((char*)arr);
prnArray1((char*)arr1);

}

void loop() {
  // put your main code here, to run repeatedly:
while(1);
}
void prnArray(char arr[])
{
    int i=5;
  long num=0;
  num=num+(arr[i]-'0');
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*10);
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*100);
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*1000);
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+(((arr[i]-'0')*10000));    //this is faulty
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*100000);
Serial.print(num,DEC);
Serial.println("");


}
void prnArray1(char arr[])
{  int i=5;
  long num=0;
  num=num+(arr[i]-'0');
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*10);
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*100);
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*1000);
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+(((arr[i]-'0')*100000)/10);  // the solution
Serial.print(num,DEC);
Serial.println("");
  i--;
  num=num+((arr[i]-'0')*100000);
Serial.print(num,DEC);
Serial.println("");

}

Why are you converting an ASCII string to a value and then using print() to convert it back to an ASCII string?

Mark

Let's see, you try to multiply 4 times 10,000 and try to fit the result into a 16 bit signed int which has a maximum value of 32,767. Wait, what is 4 times 10,000 again? Do you see the problem yet?

Hello and welcome,

Try to add a 'L' at the end, like, 10000L

Delta_G: Let's see, you try to multiply 4 times 10,000 and try to fit the result into a 16 bit signed int which has a maximum value of 32,767. Wait, what is 4 times 10,000 again? Do you see the problem yet?

Presumably an unsigned int on the PC is bigger ?

...R

It's a long integer!!!

333333 works fine

555555 doesn't

555555 does if the fifth digit is multiplied by 100,000 then divided by 10!!!!

Integer arithmetic and overflow

num=num+(((arr[i]-'0')*10000));

It isn’t possible to represent 50000 in sixteen bit signed integer arithmetic.
The type of ‘num’ is immaterial.

volatile char foo = '5';

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  long num;
  num=num+(((foo-'0')*10000));    //this is faulty
  Serial.println (num);
  }  // end of setup

void loop () { }

Output:

-15536

volatile char foo = '5';

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  long num;
  num=num+(((long (foo)-'0')*10000));    //this is faulty
  Serial.println (num);
  }  // end of setup

void loop () { }

Output:

50000

Working as expected.

num might be long but "(((foo-'0')*10000))" is evaluated as an int and ints are 16 bits on this platform.

Alternative solution:

 num=num+(((foo-'0')*10000L));

Ok thanks for that.

but why does the sixth digit work(times 100,000)?

100000 is treated as a long because it does not fit in an int. Because the one value (the 100000) is long the rest of the expression is promoted to long.

Got that
Cheers