View Full Version : Multiplication in EasyC returns insane values!
Does anyone else get crazy values when you try to multiply in EasyC?
46 * 10 = -52
466 * 100 = -18936
Any idea's why this is happening? I tried these math operations on both FRC and Vex controllers.
TIA,
Nathan
It sounds like you're running into variable overflow. If you're using a signed char as a data type, you only have eight bits to work with, so your value can't exceed 127 or -128. As such, when you multiply 46 * 10, you get 460, which is too large, so it wraps around. Wikipedia explains it more fully than I can:
http://en.wikipedia.org/wiki/Integer_overflow
Kevin Sevcik
13-01-2008, 14:17
jgannon beat me to it because I had to go and verify, but yes. -52 is exactly what you get if you try to stuff 460 into a signed char. Your output variable needs to be a signed int to handle that kind of number. the inputs could still be signed chars, I think, as the PIC has an 8 x 8 hardware multiplier that returns a 16-bit answer.
That's what I thought I did at first, but I already had it as an INT. I tried doing the math operations using DOUBLEs as well, but no difference...
Still stuck here,
Nathan
Joe Ross
13-01-2008, 14:50
That's what I thought I did at first, but I already had it as an INT. I tried doing the math operations using DOUBLEs as well, but no difference...
Still stuck here,
Nathan
This statement would work in Visual Studio or another ISO/ANSI compliant compiler. The Microchip C18 compiler (which easy C uses at the back end) is not ANSI compliant. The particular deviation you are running into is described in the C18 compiler user's guide:
2.7.1 Integer Promotions
ISO mandates that all arithmetic be performed at int precision or greater. By default,
MPLAB C18 will perform arithmetic at the size of the largest operand, even if both
operands are smaller than an int. The ISO mandated behavior can be instated via the
-Oi command-line option.
For example:
unsigned char a, b;
unsigned i;
a = b = 0x80;
i = a + b; /* ISO requires that i == 0x100, but in C18 i == 0 */
Note that this divergence also applies to constant literals. The chosen type for constant
literals is the first one from the appropriate group that can represent the value of the
constant without overflow.
For example:
#define A 0x10 /* A will be considered a char unless -Oi
specified */
#define B 0x10 /* B will be considered a char unless -Oi
specified */
#define C (A) * (B)
unsigned i;
i = C; /* ISO requires that i == 0x100, but in C18 i == 0 */
This explains the problem with your first example because even though you put the final value as an integer, C18 calculates the result as an 8 bit value, since both operands are 8 bit values. One way to fix this is to cast one of the operands as an int, or to use the -Oi compiler option
I don't use easyC, so I don't know if it possible to cast or change compiler options, but hopefully that gives you an idea where to look.
For the second example, use an unsigned int (if unsigned is OK) or long if you need to maintain signs, since you are overflowing a signed int.
Thanks for the reply!! I casted my first example like so:
int temp = 0;
temp = (int)46 * (int)10;
PrintToScreen ( "%d\n" , (int)temp );
The printed value is 460, so it works!
I tried this code however:
long temp = 0;
temp = (long)466 * (long)100;
PrintToScreen ( "%ld\n" , (long)temp ) ;
And "0b608" prints out. I'm assuming the value is in hex, which is kind of annoying. Did I write the print to screen parameters incorrectly?
Thanks for all your help,
Nathan
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.