Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Signed division with unsigned numerator

Tags:

c

signed

embedded

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:

  • Doesn't need an if statement
  • Doesn't require QWORDs

Thanks!

like image 654
Gdogg Avatar asked May 27 '11 20:05

Gdogg


People also ask

What is the difference between signed and unsigned division?

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.

How do you convert signed value to unsigned value?

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.

What is signed and unsigned numbers in assembly language?

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.

Is unsigned positive or negative?

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.


2 Answers

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.

like image 75
Chris Dodd Avatar answered Sep 18 '22 07:09

Chris Dodd


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.

like image 34
Himadri Choudhury Avatar answered Sep 22 '22 07:09

Himadri Choudhury