php - withdraw exp from the user - php

I need a calculation to finish, since I already have the calculation to give the appropriate level according to EXP, now I need to remove this EXP, example:
If the user has 1050 of EXP, the calculation must remove all values equal to 100, which means that he withdraws the 1000 and leaves the 50.
My code is:
$limit_exp = 100;
$player_exp = selectplayerexp($db);
//this variable calculate the according lvl, ex: 1000/100 = lvl 10
$levelup = (int) ($player_exp / $limit_exp);
//this one have to withdraw exp equal to 100, ex 1150, stay with 50exp
$withdraw = (int) ( ?????????????? );
Please, What should I do?

You can use the modulo (%) operator for this. This will give you the remainder of a division.
If you want to find the amount remaining, it's:
$player_exp % $limit_exp
It looks like you're trying to find an amount to subtract from what you have stored in the database, so you can subtract that amount from the total.
$withdraw = $player_exp - $player_exp % $limit_exp;
There should be no need for an (int) cast on that calculation, as the % expression will evaluate to an integer.

Related

Get the percentage between 2 numbers

I am trying to figure out if there is a way to find the percentage between 2 numbers.
It's a progress / ranking system.
I want to find the percentage the $current_exp is between the $current_min and the $current_max values, is there a way to achieve this in PHP? So far I've got to this, but it doesn't work as you progress in ranks, it doesn't treat the $current_min as 0 so when you rank up, it says you are like 75% into your next rank progression when you're in fact 0. Does this make sense?
$currentProg = ($current_exp * 100) / $current_max;
Say the current minimum is 18750 and the current maximum is 25100, the current exp is 22000... What percentage from the min to the max is the current exp? This will change each rank as the $current_min and $current_max variables get set depending on the exp of the user.
The next rank is Current min is 25100 Current max is 34230
Currently, when you are at 26000 exp, the output is saying 75.956763073327% which is not correct, it should be like 1 or 2%?
Thanks in advance 🙏
Not a good mathematician, but it looks like it should be:
(Difference of rank - minimum) / (Difference of maximum - minimum) * 100
<?php
$x = 25100;
$z = 34230;
$y = 26000;
echo ($y - $x + 1) / ($z - $x + 1) * 100; // outputs 9.8674843938232 %
Online Demo
Note: + 1 is added to both numerator and denominator to avoid divide by zero errors.

wrong unique number length

I generate an unique security code with this every time user login:
$code = substr(str_shuffle(str_repeat("0123456789", 4)), 0, 4);
it seems works but sometimes it generate 3 number instead of 4. also this problem occurred with rand() in past, then i decide to use str_shuffle + str_repeat.
also i insert this code in db with integer data type and length is 6.
what did i wrong or missed?
or is it a bug?
While I can't immediately say why your code sometimes returns only 3 digits, I find myself wondering why you don't create this 4-digit (call it a PIN?) code through the more numerically appropriate rand? For example, since you are going for a 4-digit PIN (between 0000 and 9999), I might write it like:
$code = rand(0, 9999);
$code = substr("000$code", -4);
That is much clearer as to its purpose (generate a random number, guarantee it's 4 digits), and less esoteric than str_repeat/str_shuffle.
EDIT (after learning $code is inserted into an integer DB field)
Why is your random string of 4 digits sometimes turning into 3 digits? Because you are inserting the value into an integer column. Either the DB or the DB Driver will attempt the moral equivalent of:
$code_to_insert = (int)$code;
at which point, if the number is less than 1000, you would get three digits.
Further, if you run your code enough times as it currently stands, you should get PIN lengths of 2 and 1 as well:
0 - 9 = ( 10 / 10000) -> 0.1% of the time
10 - 99 = ( 90 / 10000) -> 0.9% of the time
100 - 999 = ( 900 / 10000) -> 9.0% of the time
1000 - 9999 = (9000 / 10000) -> 90.0% of the time
A possible fix, given the current setup of your code and DB, might be to ensure the PIN length when you pull it out of the DB. You could use the same trick as above:
$sql = "SELECT code FROM ...";
...
$code = $row['code'];
$code = substr("000$code", -4);
Since you're storing the result in an integer field, it's not being stored as separate digits, just as a number. So it doesn't know anything about leading zeroes.
When you later retrieve the value, you can convert it to a string with leading zeroes using the str_pad function:
$code = str_pad($num, 4, '0', STR_PAD_LEFT);
The other option would be to change the datatype in the database to CHAR(4) instead of INT.
Try this:
$code = str_pad($num, 4, '0', STR_PAD_LEFT);

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

Generate a fictitious stock option price variation

What I do
I am making graph of fictitious stock options.
The price is updated each second, with this function
function stockVariation($price,$max_up,$max_down)
{
// Price > 1
if($price > 1)
{
// Calculate
$ratio=(mt_rand(0,$max_up/2)-mt_rand(0,$max_down/2))/1000;
$price+=$ratio;
}
// Price <=1 (we don't want 0 or negative price...)
else
$price+=mt_rand(1,$max_up)/1000;
return round($price,3);
}
I use a max_up and max_down values (from 10 to 100) to make the price change progressively and simulate some volatility.
For example, with max_up : 40 and max_down : 45, the price will progressively go down.
My question
But the problem, is that prices generated are too much volatile, even if max_up = max_down.
The result is "non-natural". (for example +10 points in one day for a base price of 15,000).
Result of price evolution per hour in 24 hour
Perhaps making round($price,4) and divisions by 10 000 instead of 1 000, will be better ?
If anyone have an idea or an advice to generate "natural" prices evolution, thanks in advance.
There are 86400 seconds in a day, so you'll need to divide by a much larger number. And rather than adding and subtracting, you may want to multiply the current price by a factor that's slightly larger or smaller than 1. That would simulate a percentage increase or decrease, rather than an absolute gain or loss.
function stockVariation($price, $max_up, $max_down)
{
// Convert up/down to fractions of the current price.
// These will be very small positive numbers.
$random_up = mt_rand(0, $max_up) / $price;
$random_down = mt_rand(0, $max_down) / $price;
// Increase the price based on $max_up and decrease based on $max_down.
// This calculates the daily change that would result, which is slightly
// larger or smaller than 1.
$daily_change = (1 + $random_up) / (1 + $random_down);
// Since we're calling this function every second, we need to convert
// from change-per-day to change-per-second. This will make only a
// tiny change to $price.
$price = $price * $daily_change / 86400;
return round($price, 3);
}
Building upon the idea, you could use an actual volatility number. If you want e.g. a volatility of 35%/year, you can find the volatility per second. In pseudocode:
vol_yr = 0.35
vol_month = vol_yr * sqrt(1.0/12)
vol_second = vol_yr * sqrt(1.0/(252 * 86400)) # or 365 * 86400
Then, every second, you "flip a coin" and either multiply or divide current stock price by (1 + vol_second). This is the principle of how binomial trees are created to evaluate exotic stock options.

Categories