Hello,
I have come across what appears to be a bug with long integer multiplication on my Arduino Duemilanove. I am using Arduino 0016 on Ubuntu Linux. I have written a test driver to reproduce my issue and am posting it here so other users can verify that they have the same issue and/or see if it is resolved on their systems.
I have heard that avr-gcc version 4.3.0 (which is the version I have) had problems with some long int multiplications. I will upgrade that on my system and see if that resolves the issue with multiplication that I have seen. If that works I will report back with my success or failure issues with the new avr-gcc version. Maybe upgrading to 0017 of the IDE will help; I'll check that too.
Has anyone else seen this or something similar to it out there?
Here is the output from my test driver:
Testing multiplcation of longs
testRoutine(): Got byte argument 13
testRoutine(): Multiplicaton Result a = 13000
testRoutine(): Value of b After assignment from byte b = 13
testRoutine(): Multiplicaton Result b = b * 1000 was: 65
ERROR: Expected Result of 13000, got this instead: 65
testRoutine(): Multiplicaton Result b = byteArg * 1000 13000
And here is the source code to reproduce it:
// ///////////////////////////////////////////////////////////////////////////
//
// Arduino code for testing multiplication of long numbers.
// 20090903, Adam E. Hampton. This code is released to the public domain.
//
// ///////////////////////////////////////////////////////////////////////////
//
// The purpose of this code is to illustrate some odd behavior I see with
// "unsigned long int" variables being cast in from a byte. It appears that
// tyring to multiply an "unsignled long int" after assigning it a value from
// a byte variable produces unexpected results.
//
// Seen on: Arduino Duemilanove with an ATMega 186 @ 20MHz,
// using Arduino 0016 on Ubuntu Linux 8.10.
//
// ///////////////////////////////////////////////////////////////////////////
// ///////////////////////////////////////////////////////////////////////////
void setup () {
Serial.begin(9600); // Serial output to the computer on pin 1.
delay(50);
}
// ///////////////////////////////////////////////////////////////////////////
void loop () {
Serial.println("");
Serial.println("Testing multiplcation of longs");
Serial.println("");
// Test Case: multiply some stuff by powers of 10.
byte myByte = 13;
testRoutine(myByte);
delay(1000);
}
unsigned long int testRoutine (byte byteArg) {
Serial.print("testRoutine(): Got byte argument ");
Serial.println(byteArg, DEC);
unsigned long int a = 0;
a = byteArg * 1000;
// This works correctly.
Serial.print("testRoutine(): Multiplicaton Result a = ");
Serial.println(a);
if (a != 13000) {
Serial.println(" ERROR: Expected Result of 13000 for a, got something else.");
}
// Next lets try a direct assignment from the byte argument. The assignment works.
unsigned long int b = 0;
b = (unsigned long int) byteArg;
Serial.print("testRoutine(): Value of b After assignment from byte b = ");
Serial.println(b);
// Next try multiplying the long integer by 10^3. This is where things break.
b = b * 1000;
Serial.print("testRoutine(): Multiplicaton Result b = b * 1000 was: ");
Serial.println(b);
if (b != 13000) {
Serial.print(" ERROR: Expected Result of 13000, got this instead: ");
Serial.println(b);
}
else {
Serial.println(" Got correct response from b = b * 1000.");
}
// Just for the purpose of a sanity check we test the original case again,
// just like it was done with the "a" variable: direct product of the byte arg
// and an integer.
b = 0;
b = byteArg * 1000;
Serial.print("testRoutine(): Multiplicaton Result b = byteArg * 1000 ");
Serial.println(b);
if (b != 13000) {
Serial.print(" ERROR: Expected Result of 13000, got this instead: ");
Serial.println(b);
}
else {
Serial.println(" Got correct response from b = byteArg * 1000.");
}
// Next check to see if multiplying b but 1 (identity) fixes the issue.
b = 0;
b = (unsigned long int) byteArg;
Serial.print("testRoutine(): Value of b after assignment from byte = ");
Serial.println(b);
// Next try multiplying the long integer by 1
// *** WHEN Un-Commented this block crashes my arduino. It never comes
// back from the b = b * 1 operation correctly. The next time b is touched
// the micro freezes.
// b = b * 1;
// Serial.print("testRoutine(): Multiplicaton Result b = b * 1 is : ");
// Serial.println(b);
// if (b != 13) {
// Serial.print(" ERROR: Expected Result of 13, got this instead: ");
// Serial.println(b);
// } else {
// Serial.println(" Got correct response from b = b * 1.");
// }// *** WHEN Un-Commented this line crashes my arduino:
// 1234 * 1234 = 1522756. This routine checks to see if the Arduino agrees.
unsigned long int c = 0;
c = 1234;
c = c * c;
Serial.print("testRoutine(): 1234 * 1234 in c = ");
Serial.println(c);
if (c != 1522756) {
Serial.print(" ERROR: Expected Result of 1522756, got this instead: ");
Serial.println(c);
}
else {
Serial.println(" Got correct response from c = 1234 * 1234.");
}
// 12345 * 67890 = 838102050.
// This routine checks to see if the Arduino agrees.
Serial.println("testRoutine(): Check sanity of 12345 * 67890 = ? ");
unsigned long int x = 12345;
unsigned long int y = 67890;
unsigned long int z = 838102050;
unsigned long p = x * y;
if (p != z) {
Serial.print(" ERROR: Did not get the expected 838102050. Got this: ");
Serial.println(p);
}
else {
Serial.print(" Got correct repsonse, 838102050, in variable: ");
Serial.println(p);
}
}