views:

487

answers:

6

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?

+6  A: 

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

John Feminella
Be careful with division by 0 if the list is empty.
Eduardo Scoz
or add an `M` suffix like `* 100M`.
Jan Jongboom
The original solution allows for values of mappedItems within the full range (Int32.MaxValue / Int32.MinValue). Your solution will cause an overflow for values > (Int32.MaxValue / 100) or < (Int32.MinValue / 100)
Frank Bollack
@Eduardo: Definitely! And if the list is empty you can avoid trying to compute `mappedItems` and `totalItems` to begin with. That can be helpful if the computation for `mappedItems` is expensive (in this case it's not, though).@Frank » This is true, but sometimes readability is a more important concern for maintenance.
John Feminella
@Jan: What is the `M` suffix? I have not heard of that.
Vaccano
@Vaccano: The `M` suffix means a `decimal` literal. See http://msdn.microsoft.com/en-us/library/aa691085%28VS.71%29.aspx .
John Feminella
Thanks for the answer. I was already checking for zero and the rounding does not matter. This works great!
Vaccano
+1  A: 

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?

Mick Sharpe
John's suggestion is better.
Mick Sharpe
+3  A: 

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

int percent = mappedItems * 100 / totalItems;
tster
+3  A: 

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
oefe
+3  A: 

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.

Guffa
+1  A: 

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.

ChrisF