php maths calculations not giving correct results - php

I am trying to do some maths to work out free items in php on my shop checkout.
Here is my code:
$bugofq = $cart_item['quantity'] * get_free_quantity($cart_item['product_id']);
$deal['freequantity'] = 10;
$deal['itemquantity'] = 5;
if($deal['freequantity'] >= 1 && $deal['itemquantity'] >= 1 && $cart_item['quantity'] > $deal['itemquantity']){
$bugofq = $cart_item['quantity'] + $deal['freequantity'];
}
So basically i am querying my database to see if a certain product exists. If it does i am then checking to see if it has any offers applied.
The above example has an offer of "buy 5 products, get 10 free".
My if statement above calculates this correctly so the total products is then 15.
However, if i add 10 products to my cart i should end up with a total of 30 products ( 5+10 + 5+10 = 30), but i end up with 20. This also happens if i add any amount of the 5. So if i add 20 products to my cart i would expect to see 60, the origial 20 and 40 free, Bu ti end up with 30.
Is there anything obviously wrong with my above cal

In your all described cases your if statement condition evaluates to true, so following code $bugofq = $cart_item['quantity'] + $deal['freequantity']; is running and as a result it is adding value of $deal['freequantity'] to $cart_item['quantity'] only once i.e. in your case it will always add 10 to the value that is why for 5 you are getting 15, for 10 you are getting 20 instead of 30, for 20 you are getting 30 instead of 60.
For correct calculation you should calculate the multiplier $c= floor($cart_item['quantity'] / $deal['itemquantity']). $c shows how many times you should apply free items package, hence the result would be $bugofq = $cart_item['quantity'] + ( $c * $deal['freequantity']);.

The formula you have only accounts for one time addition of the free count. To do it correctly you need to see how many times that addition should be applied. This you can do with the following code:
$bugofq = $cart_item['quantity']; // default case
if($deal['itemquantity'] >= 1){ // deal present
$bugofq += $deal['freequantity'] *
intdiv($cart_item['quantity'], $deal['itemquantity']);
}

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.

Shopping cart calculating total

Good day, below is a piece of code that increments the total cost for each product in the session array. My problem is displaying 0 at the end of the total when the last peny = 0.
Example 1, 2.20 + 2.20 = 4.40 but only 4.4 is shown
Example 2, 2.20 + 2.25 = 4.45 and 4.45 is shown
$total = 0;
if (isset($_SESSION['cartItems'])){
foreach ($_SESSION['cartItems'] as $product){
$total += $product['cost'];
}
}
echo $total;
Any advice on how to show/include when a 0 is entered?
This was already answered in a comment by WebCode.ie but here is a detailed answer that may help those facing the same problem:
To customize a number format, you can use the PHP Function string number_format() , that accepts either one, two, or four parameters, this way:
$my_number=25200;
$number_decimals=2;
$dec_separator=".";
$thousands_separator=" ";
echo number_format($my_number , $number_decimals, $dec_separator, $thousands_separator);
// This will output 25 200.00
The number you want to format
The number of decimals
The decimal separator
The thousands separator
Please also note that you can only use 1, 2 or 4 parameters.

Php TAX substract & add back

I have a shop where the client enters the product price with the tax in his country. When i save it i need to remove the tax and keep only the base.
When i calculate the tax back for the clients from the same country in some cases the total price will be different with 0.01 , 0.03 then the original price.
I tried to calculate with 2 to 4 digits but it never works on all cases.
Ex: price with tax = 157, tax is 7.7% => base = 145.78 and tax amount 11.22
When i calculate the tax to the previous price base i get this:
Base: 145.78 , tax is 7.7% => 11.23 = price is 157.01
Php code i use:
$baseprice = round($fullprice / (1+($taxperc/100)),2);
On the frontend:
$tax = round($baseprice * ( $taxperc / 100 ),2);
$total = $tax + $baseprice;
Anyone have a suggestion about how to fix this ?
Thanks!
Update: after some research I found a solution is to use round with PHP_ROUND_HALF_EVEN
Update2: first solution doesnt work. 1-9 works fine, 10 -tax + tax =10.01
Today's solution would be to work on the back with full number of digits ( for base price, tax and total ) and only when display for user to round it. :)
Seems ( not 100% sure yet, i need to test more ) a solution is to use the banker's rounding PHP_ROUND_HALF_EVEN
$baseprice = round($fullprice / (1+($taxperc/100)),2 , PHP_ROUND_HALF_EVEN);
$tax = round($baseprice * ( $taxperc / 100 ),2 , PHP_ROUND_HALF_EVEN);
$total = $tax + $baseprice;

Lowest cost based on case sizes

I'm working on a shipping module for wine, and was wondering if anyone could give me a hand - basically:
The wine can be shipped in cases of 8, 12 or 15 bottles, each with its own price. The module needs to take the total number of bottles in the order, and work out which combination of cases gives the lowest price. Eg in an order of 31 bottles, the lowest price works out to 1 case of 15 and two cases of 8, (rather than 2 cases of 15 and 1 of 8, or 2 of 12 and one of 8). Currently, I have the following, which almost works, but misses a few possible combinations
foreach ($rates as $case_size => $case_price)
{
$price = floor($total_bottles / $case_size) * $case_price;
$rem = $total_bottles % $case_size;
if($rem > 12)
{
//needs to use another case of 15
$price = $price + $rates[15];
}
elseif($rem > 8)
{
//needs an extra case of 12
$price = $price + $rates[12];
}
elseif($rem > 0)
{
//needs an extra case of 8
$price = $price + $rates[8];
}
$quotes[] = $price;
}
return min($quotes);
From your post your saying that the most price-effective system wouldn't just the one that has uses the lowest cost per bottle of the container, but also needs to be the most efficient at filling the containers. However your algorithm is only looking at would use the fewest large boxes possible. You need an algorithm that will completely fill each case possible.
I would do something like this: Use a recursive program to find the combination that would most completely fill each case.
function fit_case($number, $case_size) {
$rem = $number % $case_size;
$next_size=magic_voodo0();
if($rem==0) { //if perfectly fills it you're done
return ($number/$case_size)*$rates[$case_size];
} else if(($rem % $next_size)/$next_size>.5) {
//if over 50% fills the next case add the next smaller case
return floor($number/$case_size)*$rates[$case_size]+fit_case($rem, $next_size);
} else { //otherwise back off 1 of the biggest cases, and fill the rest
return (floor($number/$case_size)-1)*$rates[$case_size]+fit_case($rem, $next_size);
Hope this helps.
Different approach. Use a lookup table that has all combinations of boxes for a specific number of bottles.
1 bottle - 8
...
31 bottle - 15-8-8,15-15-8,8-8-8-8, and so on
and so on
Use another lookup table for the different rates per box per country
In your function
get table row for country prices
get the different combinations for the number of bottles
do a foreach loop on combinations
save the price and combination of first loop to variables
compare the price of the next loop with the saved value
if it is lower, save price and combination/if not, continue
loop through all combinations
return lowest price/box combination

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