Calculations in C

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did not learn C in school. I learned Fortran instead. I know how to program this in Fortran, but I am having trouble with IAR C and the Mega 8.

unsigned char A, B, C, D, E;
B = 220;
C = 133;
D = 128;
E = 49;
A = ((B + 1) * 0x0000000B * C) / ((D * 0x001C) - (10640/E));

AVRStudio shows the wrong result for A. The first two multiplications are 16 bit operations. I thought the 32 bit constant would make it do 32 bit operations. I get a truncation error in the second multiplication. I should not have to resort to assembler to do this.

What can I do?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you have an overflow problem. Unsigned char means your variables are 8-bit, i.e., they hold values between 0 and 255.

In your case, "(B + 1) * 0x0000000B * C" is 323323 . You need 32-bit to hold a value that big.

Try declaring your variables as "unsigned long" .

Regards,
Alejandro.
http://www.ocam.cl

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I thought the 32 bit constant would make it do 32 bit operations.

The catch is that 0x0000000B isn't 32 bits, rather it's an "int" (16 bits)
regardless of the leading zeroes. Try:

0x0000000BL

(that's the letter "L" at the end, for "long").

The other operations look about right, but keep an eye on them.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could do it as a floating point operation then cast back to an long afterwards to get rid of a bulk of the rounding errors.
Mike

Keep it simple it will not bite as hard

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, McKenney!

I added the "L" after 0x0000000B, and it works! :D

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The rule to keep in mind is if everything is int, the expression is evaluated using ints. If there is ONE long in the exp, everything gets promoted to longs, gets eval-ed using longs. If there is ONE float in the exp, everything gets promoted to float, exp is eval-ed as floats. You can force an int eval with parens or (int) cast, etc.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
The rule to keep in mind is if everything is int, the expression is evaluated using ints. If there is ONE long in the exp, everything gets promoted to longs, gets eval-ed using longs. If there is ONE float in the exp, everything gets promoted to float, exp is eval-ed as floats. You can force an int eval with parens or (int) cast, etc.

A further gotcha is that in C, if you write

long_var = int_exprs...

the "int_exprs" are done in "int" type unless one of the operands is a long. In other words, the result type of an assignment does not force type promotion on the right hand side!
// richard

Richard Man http://imagecraft.com

Beyond Arduino - When you're ready to get serious...
JumpStart C Tools, The Better Alternative.