I'm trying to calculate a rolling average, and to try and get and optimize a bit, I've simplified the calculation so there is only one division. When the value is decreasing, there is a point where the current value is lowered to less than the average. At this point the average jumps. I imagine this is because the division is unsigned, and my numerator's sign bit is interpreted as a massive unsigned number. I am just not sure where I need to cast unsigned to insure this problem doesn't reappear.
unsigned int AverageUsage;
unsigned int TotalUsage;
unsigned int incCount;
AverageUsage = (TotalUsage - AverageUsage)/++incCount + AverageUsage;
AverageUsage will always be positive, but when TotalUsage drops below AverageUsage, I'm not sure what to expect with the division
AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage;
Will set the numerator to signed, but I am not sure how the division will occur.
AverageUsage = (signed int)((signed int)(TotalUsage - AverageUsage)/++incCount) + AverageUsage;
Should work (I can guarantee the result of this full operation will never be negative), but I am worried about cases when incCount reaches a value that 'looks' negative.
Is there a simple solution to this that hopefully:
Thanks!
Signed variables, such as signed integers will allow you to represent numbers both in the positive and negative ranges. Unsigned variables, such as unsigned integers, will only allow you to represent numbers in the positive.
To convert a signed integer to an unsigned integer, or to convert an unsigned integer to a signed integer you need only use a cast. For example: int a = 6; unsigned int b; int c; b = (unsigned int)a; c = (int)b; Actually in many cases you can dispense with the cast.
Variables such as integers can be represent in two ways, i.e., signed and unsigned. Signed numbers use sign flag or can be distinguish between negative values and positive values. Whereas unsigned numbers stored only positive numbers but not negative numbers.
Unsigned means non-negative The term "unsigned" in computer programming indicates a variable that can hold only positive numbers. The term "signed" in computer code indicates that a variable can hold negative and positive values.
The general rule of C binary ops (including division) is that the operands will both be converted to the same type, which is one of: int
, unsigned int
, long
, unsigned long
, intmax_t
, uintmax_t
, float
, double
, long double
. If both operands are of types in that list, they'll both be converted to the later one. If neither is, they'll both be converted to int
So in your example:
AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage
if incCount
is unsigned int
, then your cast has no effect -- the subtract will be converted to signed int and then right back to unisgned int and an unsigned division will be done. If you want a signed division, you'll need:
AverageUsage = (int)(TotalUsage - AverageUsage)/(int)++incCount + AverageUsage
which as you note may get you into trouble if incCount exceeds INT_MAX.
In general, processor instructions for division only specify one type, which is used for both operands. When there is a special instruction for division with differing types, its usually for a larger (double width) dividend, not a different signedness.
You have 2 options.
Use Floating Point Math
I think you want to do this to get a proper average anyway.
There is no such thing as a mixed floating/integer divide. So, both numerator and denominator will be converted to a floating point.
Whether the numerator or denominator is signed or unsigned then doesn't matter. There is no such thing as unsigned floating point. The denominator incCount will be converted to a floating point and full floating point division will be done.
Use Integer division and handle the special cases
If for some reason you want to stay with integer division, then both the numerator and denominator have to be the same signed/unsigned type.
Both Numerator/Denominator are signed
incCount will be converted to a signed number. If it is too large then it will look like a negative number and your answer will be wrong. You have to test for this overflow.
Both Numerator/Denominator are unsigned
You have to make the numerator unsigned and use a if () statement to handle the two cases: TotalUsage < AverageUsage
and TotalUsage > AverageUsage
. Here incCount can use the full range of integer bits since it will be treated as an unsigned number.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With