Original Post
int16_t a = -255;
int16_t b = 409;
int16_t c = 1000;
int16_t result = a * b / c;result: 26
expected: -104
What the heck is going on here?
int16_t a = -255;
int16_t b = 409;
int16_t c = 1000;
int16_t result = a * b / c;
i also believe (cant remember off the top of my head) that multiplication has presedence over division
which means that the multiplication happens first
try refreshing your compiler
Actually, you're running out of precision in that operation. -255 * 409 is -104,295, but [font=courier new,courier,monospace]int16_t[font=arial,helvetica,sans-serif] [/font][/font]only has 16 bits of storage, which means it can only store values in the range ?32,768 to 32,767. So what happens? Your intermediate result gets chomped down to 16 bits *before* the divide happens, and the end result is a weird value due to overflow.
What should you do about it? Use a bigger data type.
int16_t result = (int16_t)((int)a * (int)b / (int)c);
[quote name='Cornstalks' timestamp='1349812336' post='4988454']
Actually, you're running out of precision in that operation. -255 * 409 is -104,295, but [font=courier new,courier,monospace]int16_t[font=arial,helvetica,sans-serif] [/font][/font]only has 16 bits of storage, which means it can only store values in the range ?32,768 to 32,767. So what happens? Your intermediate result gets chomped down to 16 bits *before* the divide happens, and the end result is a weird value due to overflow.
What should you do about it? Use a bigger data type.
On a side note, C++ does enforce integer promotion in this situation, so the result in C++ will be as you expected.
And on yet another side note, even when I tried to reproduce your results with VS2010 compiling the code as C code, I still get -104 so it appears it does integer promotion like C++ requires even in C.
Thank you for explaining the situation, this clears up my doubts. I am programming an application in AVR Studio 5.1 using gcc for an Atmega328p microcontroller. Due to limited RAM on a microcontroller (2 KB) I tend to stick to 8-bit and 16-bit variables. I did some tests and it seems that increasing at least one of the vars in the equation will produce the correct result.
This does not seem to work though.
int16_t result = (uint32_t)a * b / c; // does not work
I'll do some more tests.
Regards,
Bismuth
[quote name='Brother Bob' timestamp='1349813870' post='4988466']
On a side note, C++ does enforce integer promotion in this situation, so the result in C++ will be as you expected.
And on yet another side note, even when I tried to reproduce your results with VS2010 compiling the code as C code, I still get -104 so it appears it does integer promotion like C++ requires even in C.
Your variable a holds a negative value and you're casting it to an unsigned integer. Unsigned variables cannot hold negative values. And yes, it is technically enough to cast just a or b, because the other operands will be promoted automatically.
If an [font=courier new,courier,monospace]int[font=arial,helvetica,sans-serif] [/font][/font]can represent all values of the original type, the value is converted to an [font=courier new,courier,monospace]int[/font]; otherwise, it is converted to an [font=courier new,courier,monospace]unsigned int[/font]. These are called the integer promotions. All other types are unchanged by the integer promotions.
[/quote]
If I'm understanding that right, on a 32-bit system (that is, whenintis 32-bits), then yes, you'd get the right result of -104 because each operand is implicitly promoted to anint. But on a system whereintis smaller than 32-bits, (like ifintis 16-bits), then you'll have overflow. Which is exactly why you need to either use bigger datatypes or use that cast.
To clarify this a little bit, the C standard says this about evaluating an integer expression:
If an [font=courier new,courier,monospace]int[font=arial,helvetica,sans-serif] [/font][/font]can represent all values of the original type, the value is converted to an [font=courier new,courier,monospace]int[/font]; otherwise, it is converted to an [font=courier new,courier,monospace]unsigned int[/font]. These are called the integer promotions. All other types are unchanged by the integer promotions.
If I'm understanding that right, on a 32-bit system (that is, whenintis 32-bits), then yes, you'd get the right result of -104 because each operand is implicitly promoted to anint. But on a system whereintis smaller than 32-bits, (like ifintis 16-bits), then you'll have overflow. Which is exactly why you need to either use bigger datatypes or use that cast.
[/quote]
you live, you learn
Just use 32 bit integers, I dont really see why trying so hard to use 16 bits, is there a reason for it?
I am programming an application in AVR Studio 5.1 using gcc for an Atmega328p microcontroller. Due to limited RAM on a microcontroller (2 KB) I tend to stick to 8-bit and 16-bit variables.
This topic has been locked by a moderator. New replies are not allowed.
With your permission, GameDev.net uses analytics cookies to understand how people use the platform. You can accept analytics or continue with necessary cookies only. Learn more