Voting percentage calculation error [duplicate] - php

This question already has answers here:
How to deal with the sum of rounded percentage not being 100?
(5 answers)
Closed 9 years ago.
I have created a php program where user can can vote on polls and after that, the poll result will displayed with only percentage, however I am facing an error in my program. Code which I am using for percentage calculation is <?php echo round(($num_votes / $total_votes) * 100) ?>
Now If we talk about a sample poll result, assume we have five options
option A - 4 votes
option B - 2 votes
option C - 4 votes
option D - 1 votes
option E - 0 votes
Total votes = 11
In this scenario the percentage result generating is
option A - 36%
option B - 18%
option C - 36%
option D - 9%
option E - 0%But the total of percentage is 99% instead of 100%. What I want is total should always be 100% Any help would be appreciated
Thanks.

If you are working with rounded numbers, you can indeed end up with...rounded numbers. And the sum of those rounded numbers will be different from the regular sum. There's little you can do to change that. If you insist, you'd have to:
calculate the rounded numbers
calculate the sum, and if not 100%,
loop through the rounded numbers and decide which one should get the missing percent.
But you're messing with the data. You may think you're cleaning it, but you're messing it up.

This way lead to ~100%, 'number_format' is nice thing
$a = 4;
$b = 2;
$c = 4;
$d = 1;
$e = 0;
$total = $a + $b + $c + $d + $e;
$arr = array(
'a' => number_format(($a / $total) * 100, 3),
'b' => number_format(($b / $total) * 100, 3),
'c' => number_format(($c / $total) * 100, 3),
'd' => number_format(($d / $total) * 100, 3),
'e' => number_format(($e / $total) * 100, 3)
);
foreach ($arr as $answer => $percentage) {
echo $answer .': '. $percentage . '<br />';
}
// this will be 100.001 so we format is
echo 'total: '. number_format(array_sum($arr), 2);

You can specify number of digits after decimal places in round.
ex:round(number,2);

There's nothing out-of-the-box you can do about it, if you floor() everything you'll miss one point, if you ceil() you'll gain one point.
You could floor() everything then if then calculate the array_sum(), if not 100 then find min() and ceil() it.

Related

Calculate rating for 5 stars depending of reviews

I have good reviews, and I have bad reviews. I need calculate rating from this reviews for post.
Example:
Post 1 have 1 good reviews, and 2 bad reviews
Post 2 have 12 good reviews, and 5 bad reviews
Post 3 have 0 good reviews, and 0 bad reviews
How I can calculate rating? I need for post get 5 stars. I need score up to 5 stars or less. May be I need this formula?
$score = ($good_reviews * $bad_reviews) / 5; //get rating stars
But I don't get 5, or less number. How I can do it correctly?
Maybe you want this:
$rating = $good_reviews
? intval ( 5.4 * $good_reviews / ( $good_reviews + $bad_reviews))
: 0;
And now step by step:
SUM := $good_reviews + $bad_reviews is the sum of all reviews.
RATE := $good_reviews / SUM is the general rating of $good_reviews to the sum of reviews. The result is in the range 0.000 to 1.000 .
Multiplying it with 5.4 expands the range to 0.000 to 5.400. Its a little bit tricky to allow some bad votes for a 5 stars ranking. The factor can be every number between 5.000 and 5.9999999.
intval() reduces the number to an int from 0 to 5 (your stars).
The alternative by ?: avoids an division by zero error.
That formula will not give you what you need. It will only multiply good with bad and divide by 5. For example ((100 good * 20 bad) / 5) = 400. Way out of 5!
If you need score up to five stars you will need to use ranges.
Calculate percentage between good and bad and then do an if checks.
For example:
$percentage = (($good - $bad) / $good) * 100;
if($percentage => 100) {
//5 starts
} else if ($percentage < 100 && $percentage => 80) {
//4 stars
} else if ($percentage < 80 && $percentage => 60) {
//3 stars
} else if ($pecentage < 60 && $percentage => 40) {
//2 starts
} else {
//1 star
}
That's just a basic example. There are different ways to approach this. You need to adjust it to your needs and try if it works for you.
I did this really quick, so didn't test it. Please, check and see if it fits you. I just wanted to give you an idea.

Highest multiplication with multiple and max number set

Not quite sure what to set this title as, or what to even search for. So I'll just ask the question and hope I don't get too many downvotes.
I'm trying to find the easiest way to find the highest possible number based on two fixed numbers.
For example:
The most I can multiply by is, say, 18 (first number). But not going over the resulted number, say 100 (second number).
2 x 18 = 36
5 x 18 = 90
But if the first number is a higher number, the second number would need to be less than 18, like so:
11 x 9 = 99
16 x 6 = 96
Here I would go with 11, because even though the second number is only 9, the outcome is the highest. The second number could be anything as long as it's 18 or lower. The first number can be anything, as long as the answer remains below 100. Get what I mean?
So my question is, how would write this in php without having to use switches, if/then statements, or a bunch of loops? Is there some math operator I don't know about that handles this sort of thing?
Thanks.
Edit:
The code that I use now is:
function doMath($cost, $max, $multiplier) {
do {
$temp = $cost * $multiplier;
if ($temp > $max) { --$multiplier; }
} while ($temp > $max);
return array($cost, $temp, $multiplier);
}
If we look at the 11 * 9 = 99 example,
$result = doMath(11, 100, 18);
Would return,
$cost = 11, $temp = 99, $multiplier = 9
Was hoping there was an easier way so that I wouldn't need to use a loop, being as how there are a lot of numbers I need to check.
If I understood you right, you are looking for the floor function, combining it with the min function.
Both a bigger number c and a smaller number a are part of the problem, and you want to find a number b in the range [0, m] such that a * b is maximal while staying smaller (strictly) than c.
In your example, 100/18 = 5.55555, so that means that 18*5 is smaller than 100, and 18*6 is bigger than 100.
Since floor gets you the integral part of a floating point number, $b = floor($c/$a) does what you want. When a divides c (that is, c/a is an integer already), you get a * b == c.
Now b may be outside of [0,m] so we want to take the smallest of b and m :
if b is bigger than m, we are limited by m,
and if m is bigger than b, we are limited by a * b <= c.
So in the end, your function should be :
function doMath($cost, $max, $multiplier)
{
$div = min($multiplier, floor($max/$cost));
return array($cost, $div * $cost, $div);
}

Rounding in PHP to achieve 100%

I need to total the number of clicks over 10 links on my page and then figure out the percentage of people that clicked each. This is easy division, but how do I make sure that I get a round 100% at the end.
I want to use the below code, but am worried that a situation could arise where the percentages do not tally to 100% as this function simply removes the numbers after the period.
function percent($num_amount, $num_total) {
$count1 = $num_amount / $num_total;
$count2 = $count1 * 100;
$count = number_format($count2, 0);
echo $count;
}
Any advice would be much appreciated.
Instead of calculating one percentage in your function you could pass all your results as an array and process it as a whole. After calculating all the percentages and rounding them make a check to see if they total 100. If not, then adjust the largest value to force them all to total 100. Adjusting the largest value will make sure your results are skewed as little as possible.
The array in my example would total 100.02 before making the adjustment.
function percent(array $numbers)
{
$result = array();
$total = array_sum($numbers);
foreach($numbers as $key => $number){
$result[$key] = round(($number/$total) * 100, 2);
}
$sum = array_sum($result);//This is 100.02 with my example array.
if(100 !== $sum){
$maxKeys = array_keys($result, max($result));
$result[$maxKeys[0]] = 100 - ($sum - max($result));
}
return $result;
}
$numbers = array(10.2, 22.36, 50.10, 27.9, 95.67, 3.71, 9.733, 4.6, 33.33, 33.33);
$percentages = percent($numbers);
var_dump($percentages);
var_dump(array_sum($percentages));
Output:-
array (size=10)
0 => float 3.51
1 => float 7.69
2 => float 17.22
3 => float 9.59
4 => float 32.86
5 => float 1.28
6 => float 3.35
7 => float 1.58
8 => float 11.46
9 => float 11.46
float 100
This will also work with an associative array as the function parameter. The keys will be preserved.
These figures could now be presented in a table, graph or chart and will always give you a total of 100%;
What you want to do is this.
Total the number of clicks across the board, then divide each number by the total.
For example:
1134
5391
2374
2887
In this case, four buttons, with a total of 11786 clicks, so:
1134 / 11786 = 0.09621....
5391 / 11786 = 0.45740....
2374 / 11786 = 0.20142....
2887 / 11786 = 0.24495....
Then for each division, round the result to 'two decimal points', so the first result:
0.09621.... becomes 0.10
because the 3rd point is 5 or above, it would remain at 0.09 if the 3rd point was below 5.
Once you have all of the results rounded, multiply each by 100 then add them up.
The ending result will always be 100.
Should warn you however that depending on how you use each individual percentage, when you round them, any result less that 0.05 will become 0%, unless you keep the value before you round it so you can declare it as a percentage less than 1.
I think you want to use ceil() or round() .
Since these are floating point numbers, there is room for error. Be careful how you round, and be sure that you don't independently calculate the last remaining percentages. Simply subtract the total of what you have from 1 or 100.
Make sure you dont calculate separate sides of the equation, sum one side, then subtract the other from 1 or 100 or however you are handling your percentages.
I run into this quite a bit and have a hack for it.
$percentages = array(
'1' => 87.5,
'2' => 12.5,
'3' => 0,
'4' => 0,
'5' => 0
);
If you round those percentages for output, you will end up with 88% and 13% (101%)
round($percentages['1']);
round($percentages['2']);
// 88
// 13
So here is the code I use to fix it.
$checkTotal = array_sum($percentages);
$max = max(array_keys($percentages));
if ($checkTotal > 100) {
$percentages[$max] = $percentages[$max] - 1;
}
if ($checkTotal < 100) {
$percentages[$max] = $percentages[$max] + 1;
}
If it is 100, do nothing.
If it is less than 100, add 1 to equal 100
If it is over 100, subtract 1 to equal 100

PHP rating system

I have a table (review) which stores the values (1-5) for ratings. I will use the sum of these ratings for the overall score.
I have 5 stars on the page which will show on or off depending on the overall value.
I have the overall score by counting the total value of all the ratings divided by the number of reviews in the table. This give a value below 5 every time...great.
However I now have a problem where the value could either be 1.5 or 1.75 for instance. If the value is 1.5 I will show 1 and a half stars on and 3 and a half stars off. How should I determine if the value is 1.75 to show only the 1.5 value star.
Hope that makes sense.
That should be a simple math problem, since your resolution is 1/2, multiply by two, round it, then divide by 2:
round(x * 2) / 2
round((1.75) * 2) / 2 = 2
round((1.65) * 2) / 2 = 1.5
<?php
$tests = array(-1, 0, 0.25, 0.5, 1, 1.5, 1.75, 3, 4.22, 6);
foreach($tests as $test)
echo "Initial rate = ".$test.", adjusted rate = ".adjustRate($test)."\n";
function adjustRate($val)
{
if ($val < 0)
return 0;
if ($val > 5)
return 5;
return floor($val * 2) / 2;
}
Gives for example:
Initial rate = 1.75, adjusted rate = 1.5

round number to nearest 0.2 with PHP

I'm creating this rating system using 5-edged stars. And I want the heading to include the average rating. So I've created stars showing 1/5ths. Using "1.2" I'll get a full star and one point on the next star and so on...
But I haven't found a good way to round up to the closest .2... I figured I could multiply by 10, then round of, and then run a switch to round 1 up to 2, 3 up to 4 and so on. But that seems tedious and unnecessary...
round(3.78 * 5) / 5 = 3.8
A flexible solution
function roundToNearestFraction( $number, $fractionAsDecimal )
{
$factor = 1 / $fractionAsDecimal;
return round( $number * $factor ) / $factor;
}
// Round to nearest fifth
echo roundToNearestFraction( 3.78, 1/5 );
// Round to nearest third
echo roundToNearestFraction( 3.78, 1/3 );
function round2($original) {
$times5 = $original * 5;
return round($times5) / 5;
}
So your total is 25, would it be possible to not use floats and use 1->25/25? That way there is less calculations needed... (if any at all)
Why is everyone giving solutions that require a deeper inspection or conversion? Want 0.2? Then:
round($n / 0.2) * 0.2; // $n = 3.78 / 0.2 = 18.9 (=) 19 * 0.2 = 3.8 //
Want 5? Then:
round($n / 5) * 5; // $n = 17 / 5 = 3.4 (=) 3 * 5 = 15 //
It's as simple as that.

Categories