PHP rounding issue - php

I am getting a rounding issues, I have a database of 3 charities with different amounts.. then in the front I have the 3 charities displaying there percentage based on the amount assigned to them and the total percentage always needs to add to 100%.. currently if each charity has 1 assigned to it, it displays 33% on each which equals 99% where i need to cheat it in a way to always be equal to 100%..
Here is the PHP
$charity = $_POST['charity'];
$sql = "SELECT amount FROM charities";
$result = mysqli_query($con, $sql);
while($row = mysqli_fetch_array($result)) {
$total += $row['amount'];
}
$sql_individual = "SELECT * FROM charities WHERE charity='$charity'";
$result_individual = mysqli_query($con, $sql_individual);
while($row = mysqli_fetch_array($result_individual)) {
$charity = $row['amount'];
}
echo round($charity / $total * 100,0) . "%";
I found a maths solution for this.. but.. my maths isn't all that great.. but.. okay in all honesty i do not understand this fully:
c = 100 - (a + b) - e,g 34 = 100 - (33 + 33)
any Help Greatly Appreciated..

There are no rounding issues, You just round to an integer numbers, that means that if You have 5 values like these:
12,25%
13,25%
20,25%
30,25%
34,00%
after using round($x, 0) on them they will be rounded to these values:
12
13
20
30
34
After summing these rounded values You get the value of 99.
It is best to round at least to two decimal places when working with percentages - and only for displaying purposes. You shouldn't round any values that will be used for further math operation...

Related

Working out the new price from a %

I have tried to do this myself, it seems fairly simple i must be over complicating it, i have the following code:
// get the % we make
$row = DB::getInstance()->selectValues('SELECT * FROM `profit`');
$per = $row['profit_percentage'];
$pro = $per * 100 - ((str_replace("$", " ", trim($offer->children('campinfo', true)->amount) / 100)));
The value of $per = 60 this value $offer->children('campinfo', true)->amount can contain any value like: 0.55 or 25.34 what i'm trying to do is deduct 60 (the percentage) off the value of $offer->children('campinfo', true)->amount
I'm going round in circles
any help would be appreciated.
This boils down to simple math:
Giving a 60% discount is the same as only charging 40%.
So all you have to do is calculate $price * 0.4.
Pro tipp: Don't store your percentage as {0..100}, but as {0..1}. That way you can rewrite your code as (1 - $per) * $price!

PHP likely chance

Okay, so i don't really know how I go about this.
I'm currently working on a lottery system for a game.
I have a table with virtual items which I want to randomly select by a likely chance.
Table examples:
ID = 1, item_name = Sword, likely_chance = 75
ID = 2, Item_name = 10,000, likely_chance = 20
For id 2, 10,000 represents 10,000 coins.
I want to come up with an algorithm which will select a item with a higher chance of selecting a higher likely chance but also still be able to win a item with a lower likely chance rarely.
If you have items with "likely chances" of C1, C2, C3...Cn, then you can calculate the sum Ctotal.
Then, you can get a random value between 0 and Ctotal, and walk through your array (order is irrelevant) until the sum of "skipped" items exceeds this random value.
For example, in your case, Ctotal = 75 + 20 = 95. Get a random number between 0 and 95, and if it is less than 75 - give a sword; else - give 10000 coins. It will provide a fair winnings distribution according to your likely chances - 78.95% and 21.05%, respectively.
$items = ['Sword', '10000 coins'];
$chances = [70, 25];
$ctotal = array_sum($chances); echo "Total is $ctotal\n";
$rand = rand(0, $ctotal); echo "Rand is $rand\n";
$i = 0;
$currentSum = 0;
while (true)
{
$currentSum += $chances[$i];
if ($currentSum >= $rand)
{
echo "You win: ".$items[$i];
break;
}
$i++;
}
Here is the working Demo. Note that IDEOne remembers the last output and doesn't run this program again every time. The output will appear to be the same, but it is not.

PHP Pow Function a reverse required

I have something with pow I need to return a whole inter for different results (reversed basically)
For Example (rounded to 4 decimals):
<?php
$var = 10 * pow(1.01,0); // = 10
$var = 10 * pow(1.01,1); // = 10.1
$var = 10 * pow(1.01,2); // = 10.201
$var = 10 * pow(1.01,3); // = 10.303
etc
How could I return the whole number for 10.1150 = 1 since it is above 10 * pow(1.01,1); and below 10 * pow(1.01,2);
The 1.01 can also be a number of variables, (percentage scaled point and figure charting), why I need the Whole number only of the percentage differences (1 box = 1 percentage change from the box above or below)
Thanks much all, I've battled with this issue in many different ways including x all price data points for 250 percentage changed into an array, that is fast, except to build the array becomes the slow issue. if else is the current solution but for 2500 price points on 250 charts = 2 seconds just to find a plot point, considering I'm doing 10's of millions of charts daily, 2 seconds = a lot of time accumulated.
Have you tried using log? It's the reverse of the pow function.
$orig = floor(log($var/10,1.01));

Mapping increasing rank to decreasing but non-negative points

I need to create a business logic or php function to compute the following: given some input $rank (which is the alexa ranking) I need to compute some $points in such a way that $points will be high for the top ranking website and will decrease with increasing $rank value.
I imagine something like this:
function($rank)
{
$points = x*$rank;
return $points;
}
How do I get $points in such a way that
if the rank is 1 then the points returned is maximum (e.g. 10000).
if rank is 2 then $points returned will be 9500 or nearby.
if rank is 4 then $points returned will be 6000 or nearby.
if rank is 200 $points returned will be 2 or whatever the function will return.
Rule: if $rank is less then $points should be more. Maximal value of $points is 10000 which is for $rank=1.
Now as the $rank increases the $points value should decrease accordingly.
There are many formulas which might satisfy your requiremements.
Nested powers
One possibility:
$points = 10000 * pow(0.993575964272119, pow($rank, 3.16332422407427) - 1)
This gives you the following results:
f(1) = 10000
f(2) = 9500
f(4) = 6000
f(9) = 12.065
f(10) = 0.84341
f(200) = 0
So the three values you fixed (1, 2 and 4) are all satisfied, but the result for 200 indicates that this might not be exactly what you're looking for. The curve looks like this:
By the way, I found this using python and mpmath, by fixing the form of the formula and determining the numbers with the many digits numerically:
>>> import mpmath
>>> print(mpmath.findroot((lambda a,b: 10000*a**(2**b - 1) - 9500,
... lambda a,b: 10000*a**(4**b - 1) - 6000),
... (0.995, 2.7)))
[0.993575964272119]
[ 3.16332422407427]
If you decide on a different form of the function, this approach might be adapted.
Exp of a polynomial
A possible different form with the desired properties would be this:
$points = exp(9.14265175282929 + $rank*(0.127179575914116 - $rank*0.0594909567672230))
This does not decrease quite as quickly as the one above:
f( 1) = 10000
f( 2) = 9500
f( 4) = 6000
f( 13) = 2.1002
f( 14) = 0.47852
f(200) = 0
It was obtained by solving this system of equations:
a + b + c = log(10000)
a + 2b + 4c = log( 9500)
a + 4b + 16c = log( 6000)
to obtain the coefficients a through c for the polynomial. One can add another degree to match f(200)=2 as well, but in that case, the last coefficient will become positive, which means that points will start to increase with rank for very large ranks.
If you want to match that f(200)=2 as well, you can do so using
$points = exp(max(8.86291000469285 - $rank*0.0408488141206645,
9.14265175282929 + $rank*(0.127179575914116 - $rank*0.0594909567672230)))
although this will result in a bend in your curve.
To compare these alternatives to the above:
function getPoints($rank)
{
$returnValue = -0.005 * $rank * $rank - 0.035 * $rank + 100.040;
if ($returnValue < 0) $returnValue = 0;
return $returnValue;
}
This was my thinking.
Function is not forking for large values:
it should atleast give some small value for large ranks...
like if rank is 2000000 then points will be 2.
Thnx btw

Round integer to nearest multiple of 5 in PHP

Searching for a function ro round numbers to the nearest multiple of 5
22 -> 20
23 -> 25
40 -> 40
46 -> 45
48 -> 50
and so on.
Tried this which always returns the higher value:
5 * ceil($n / 5);
Use round() instead of ceil().
5 * round($n / 5);
ceil() rounds a floating point number up to its next integer in sequence. round() will round to the nearest integer using standard rounding rules.
Back to maths, since round works with decimals, multiply by 5 and divide by 10 and then round, it. Multiply by 5 again to get what u want. (Other answer works as well, just a different way of looking at it)
function round_5($in)
{
return round(($in*2)/10)*5;
}
echo round_5(48);
See if this helps
Well, facing this issue while helping make an POS for a Canadian company, came up with this solution, hope it helps someone. (Canada removed the penny in 2012). Also includes for doing tax included pricing, just pass '1' as second argh.
//calculate price and tax
function calctax($amt,$tax_included = NULL){
$taxa = 'tax rate 1 here';
$taxb = 'tax rate 2 here';
$taxc = ($taxa + $taxb) + 1;
if(is_null($tax_included)){
$p = $amt;
}else{
$p = number_format(round($amt / $taxc,2),2);
}
$ta = round($p * $taxa,2);
$tb = round($p * $taxb,2);
$sp = number_format(round($p+($ta + $tb),2),2);
$tp = number_format(round(($sp*2)/10,2)*5,2);
$ret = array($ta,$tb,$tp);
return $ret;
}

Categories