Vaccano
Vaccano

Reputation: 82547

What's the best way to create a percentage value from two integers in C#?

I have two integers that I want to divide to get a percentage.

This is what I have right now:

int mappedItems = someList.Count(x => x.Value != null);
int totalItems = someList.Count();
(int)(((double)mappedItems /(double) totalItems) * 100)

This gives the right answer. But that is a lot of casting to do something as simple as get a percentage between two numbers.

Is there a better way to do this? Something that does not involve casting?

Upvotes: 40

Views: 65012

Answers (9)

Syv Development
Syv Development

Reputation: 47

This is what works for me.

 double percentage = (double) (mappedietms * 100) / totalitems;

label6.Text = $@"Health: [{Math.Round(percentage ,1)}]";

Upvotes: 0

dragonroot
dragonroot

Reputation: 5851

The right integer-only way to get percentage with proper rounding is:

int result = ( mappedItems * 200 + totalItems ) / ( totalItems * 2 );

How do we get there? If we do this thing in floating point, it would be Math.Floor( mappedItems * 100.0 / totalItems + 0.5 ). We need to transform this formula to be integer-only by multiplying and dividing 0.5 by totalItems, then moving 0.5 * totalItems into dividend, and then multiplying both dividend and divisor by 2 to make fractions go away:

mappedItems * 100.0 / totalItems + 0.5 => mappedItems * 100.0 / totalItems + totalItems * 0.5 / totalItems => ( mappedItems * 100.0 + 0.5 * totalItems ) / totalItems => ( mappedItems * 200.0 + totalItems ) / ( totalItems * 2 ).

At this point the formula is integer-only. When we do integer division, we get floored result, so the integer-only result is equivalent to the mentioned floating-point one.

Upvotes: 12

Brad Parks
Brad Parks

Reputation: 72303

try this:

int mappedItems = someList.Count(x => x.Value != null);
int totalItems = someList.Count();
int percent = Convert.ToInt32(complete * 100.0 / total);

in this example, you'd get result being "50"

int mappedItems = 14;
int totalItems = 28;
int result = Convert.ToInt32(mappedItems * 100.0 / totalItems);
// result is 50

Upvotes: 1

ChrisF
ChrisF

Reputation: 137198

Just to add that as you've got ints and want to calculate the percentage (a floating point value) you are going to have to do casting. Whether it's explicit as in C# or implicit as in some scripting languages the cast will still happen. It's better to make it explicit.

If you want fewer casts per line of code you could write:

double mappedItems = (double)someList.Count(x => x.Value != null);
double totalItems = (double)someList.Count();
double percentage = (mappedItems / totalItems) * 100.0);

Though as others have pointed out - check for totalItems being 0 (preferably before casting to double) to avoid a divide by zero.

Upvotes: 1

Guffa
Guffa

Reputation: 700910

You can get a correctly rounded result using only integer operations:

int percent = (200 * mappedItems + 1) / (totalItems * 2);

By multiplyingby two, adding one and dividing by two, you are effectively adding a half. This makes the integer division do a rounding instead of truncating.

Upvotes: 6

oefe
oefe

Reputation: 19926

If you just wanted to avoid the casts, you could write:

(100 * mappedItems) / totalItems

but that will quickly overflow when mappedItems > int.MaxValue / 100.

And both methods round the percentage down. To get correct rounding, I would keep the result as a double:

((double)mappedItems /(double) totalItems) * 100

Upvotes: 10

tster
tster

Reputation: 18257

Well, assuming your counts are smaller than int.MaxValue:

int percent = mappedItems * 100 / totalItems;

Upvotes: 4

Mick
Mick

Reputation: 5217

You could use (mappedItems * 100) / totalItems but this would always round down. The method that you have used is better. Why not wrap the code up as a method?

Upvotes: 1

John Feminella
John Feminella

Reputation: 311765

How about just mappedItems * 100.0 / totalItems and casting this to the appropriate type?

Upvotes: 63

Related Questions