Why am I getting this multiplication error?

Hello all,

I'm in the middle of writing a much larger program which interfaces with a real time clock. The way I keep track of time is by converting the current time into an unsigned long which stores time as "Seconds past midnight on Sunday."

Anyway, some comparisons weren't working and I dug around until I found the root problem. Here's a simple sketch to illustrate the error. What's going on?

When I multiply 12*3600, the result should be 43200. This value is stored in an unsigned long so size shouldn't be a problem, right? Instead the arduino prints 4294944960! Any ideas?

unsigned long result;

void setup(){
  Serial.begin(9600);
}

void loop(){
  result = 12*3600;  
  Serial.println(result);
  delay(1000);  
}

Some weirdness casting to ints to unsigned longs?

unsigned long result;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int step;
  
  result = 12 * 3600;
  Serial.print("result = ");
  Serial.println(result);
  
  Serial.print("(result & 0xFFFF) = ");
  Serial.println(result & 0xFFFF);
  
  result = (unsigned long)(12 * 3600);
  Serial.print("(ulong)(i * i) = ");
  Serial.println(result);
  
  step = 12 * 3600;
  result = (unsigned long)step;
  Serial.print("(ulong)(i) = ");
  Serial.println(result);
  
  result = (unsigned long)12 * (unsigned long)3600;
  Serial.print("(ulong) * (ulong) = ");
  Serial.println(result);
  Serial.write('\n');

  delay(10000);
}

returns

result = 4294944960
(result & 0xFFFF) = 43200
(ulong)(i * i) = 4294944960
(ulong)(i) = 4294944960
(ulong) * (ulong) = 43200

20 * 3600 = 72000

result = 6464
(result & 0xFFFF) = 6464
(ulong)(i * i) = 6464
(ulong)(i) = 6464
(ulong) * (ulong) = 72000

20 * 66000

result = 1320000
(result & 0xFFFF) = 9280
(ulong)(i * i) = 1320000
(ulong)(i) = 9280
(ulong) * (ulong) = 660000

It appears that the multiplication is always done as a 2Byte int unless you specifically tell it not too, but i don't know why the cast up to an unsigned long is setting the upper bytes to FFFF?

aspartame,

Bingo, and thanks for writing up that sketch. Right away I added (unsigned long) to the offending areas in my original program, and that solved things immediately.

I guessed that it had to have something to do with integers, as the problem existed when "result" was more than 32,768 but not when it was below. Thanks very much!

Here's the explanation. 12 and 3600 are both integer constants, so the compiler generates the product, 43200, and stores it as an int, because int*int = int. But 43200 is too large to be represented by an Arduino 16-bit int. If you try this:

int x = 43200;
Serial.print(x);

you'll get "-22336".

Converting -22336 to an unsigned long gives you 4294944960.

To solve the problem, simply write

result = 12UL * 3600UL;

Mikal

Hi berga, there is a library called DateTime in the playground that has functions to convert to and from dates and unsigned longs, have a look at the source code to see it that helps with what you want to do.
http://www.arduino.cc/playground/Code/DateTime