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? Some开发者_运维百科thing that does not involve casting?
How about just mappedItems * 100.0 / totalItems
and casting this to the appropriate type?
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.
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
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.
Well, assuming your counts are smaller than int.MaxValue:
int percent = mappedItems * 100 / totalItems;
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?
Just to add that as you've got int
s 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.
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
This is what works for me.
double percentage = (double) (mappedietms * 100) / totalitems;
label6.Text = $@"Health: [{Math.Round(percentage ,1)}]";
精彩评论