Why does this simple subtraction does not work? - php

So this will be very specific question, but I am losing my sanity as I was staring at this for the better part of the day. So here I wrote this function to calculate the price dependent commission:
function commision($amount, $commision_arg = 0){
// $temp_amount = 0;
// $commision = 0;
if($amount > 999){
$temp_amount = $amount - 999;
$commision_arg += $temp_amount/100*1;
return commision(999, $commision_arg);
}else if($amount>249&&$amount<=999){
$temp_amount = $amount - 249;
$commision_arg += $temp_amount/100*3;
return commision(249, $commision_arg);
}else if($amount>49 && $amount<=249){
$temp_amount = $amount - 49;
$commision_arg += $temp_amount/100*5;
return commision(49, $commision_arg);
}else if($amount <= 49){
return number_format($commision_arg + 3.5, 2);
}
}
Basically if $amount is less then 49 then it is just flat 3.5 rate, if $amount is 49 to 249 then it is flat rate 3.5 + 5% of anything in 49-249 range.
I am not sure if this is good way to do this or not, but it works. However there is issue with another method that uses this function:
public function amountPayable(){
$amount = $this->uri->segment(3);
echo $amount - commision($amount);
}
This is just a function in codeigniter controller, that is called by AJAX request, and it should be returning the amount payable by the customer, which is then injected into DOM.
And this is where the problem lies.
Basically if I pass the $amount that equal to 100.000, what I get back from amountPayable is 99.999, whereas it should be: 98973.9. if I change echo $amount - commision($amount); to echo commision($amount); then I get back 1026.1. So the commision() function returns the correct number. But for some reason $amount - commision($amount); (where $amount = 100000) evaluates to 1.
How can this be?

Related

How to display number in percentage

I wanted to know how I present a percentage, here is the code
//The number taken from the database
$minos = $ud['bnk']['gold'];
The number that is supposed to be in percent through the database (the database has a number and not a percentage for example 2)
$plus= $ud['bnk']['ent_level'];
And here is a simple calculation of X + 2% = Y
$sava = $minos + $plus;
I tried to do this, according to an internet guide, but it doesn't work for me, I want the number to be a percentage and not successful
function get_percentage($total, $number)
{
if ( $total > 0 ) {
return round($number / ($total / 100),$ud['bnk']['ent_level']);
} else {
return 0;
}
}
$minos = $ud['bnk']['gold'];
$plus = get_percentage(100,$ud['bnk']['ent_level']).'%';
$sava = $minos + $plus;
I solved the equation with what you gave me, thank you very much, the way is:
$minos = $ud['bnk']['gold'];
$plus = ($minos / 100) * $ud['bnk']['ent_level'];
$sava = $plus;
Thanks so much to everyone who helped

Calculating event happening from percent

I couldn't find any answers, so I am asking here.
How can I calculate whether an event should be triggered or not based on percent?
Let me explain.
Let say an event has a 30% probability of occurring.
When I run the script (call a function) how can I know if that event falls into that 30% or not?
Basically, in the end, I have to return true or false from a function.
Hopefully, you understand what I mean.
I have my own solution, but I believe it isn't correct:
$evasion_percent = 30;
$did_evasion = false;
$my_evasion_number = mt_rand(0,100);
if ($my_evasion_number <= $evasion_percent) {
$did_evasion = true;
}
return $did_evasion;
Thanks.
Your solution is fine.
$evasion_percent will be greater than or equal to a random integer 30% of the time as there are 30/100 numbers (excluding 0) that will make your function return true.
ie. (30 desirable outcomes that make this function return true / sample space of 100) ~ 30%.
You need to get random from 1 to 100, not from 0 to 100, the rest looks fine.
<?php
function trigger_event($percent) {
$did_evasion = false;
$my_evasion_number = mt_rand(1, 100);
if ($my_evasion_number <= $percent) {
$did_evasion = true;
}
return $did_evasion;
}
You can also try it with large number of calls (1000, 100000 or even more) and see how part of triggered events is closed to your percentage:
$evasion_percent = 30;
$m = 0;
for($n = 1; $n <= 1000; $n++) {
$m += trigger_event($evasion_percent) ? 1 : 0;
}
echo $m / $n * 100;

php division results in zero (updated - issue was elsewhere)

UPDATE - the problem was actually completely out of the rounding function. It seems as though $price (used in woo commerce) is a string and for some reason I can't use it in a calculation. If I simply return $price, no problem. All of this was fine when I was simply returning the value of the other function.
function xa_only_sale_price($price, $product)
{
error_log ("price in the beginning is " . $price);
if(!is_cart() && !is_checkout() && !is_ajax()){
if ($product->is_type('simple') || $product->is_type('variation')) {
$price = regularPriceHTML_for_simple_and_variation_product($price, $product);
$val = (float)$price;
error_log( "ceiling = " . ceil($val* 2) / 2); // 0 printed to log
return ceil($val* 2) / 2; this returns 0
// return roundNum(regularPriceHTML_for_simple_and_variation_product($price, $product));
}
}
error_log ("price before call is " . $price); // this returns 0
// return roundNum($price); //this is never in use
}
--------------- original post-----------------------------
I am new to php - thank you for all of the help in advance. I am assuming that this issue has something to do with data types but I haven't been able to figure this one out.
In this example $num is the price of a woocommerce product. If I simply return $num I see the price that I am expecting to see. I am simply trying to round the value in this function (I simplified the function for the sake of the question).
function roundNum($num){
$nearest = 0.50;
return ($num / $nearest) ;
This returns 0 to the browser. However, forcing the value of $num results in a valid calculation and return.
function roundNum($num){
$num = 100.0;
$nearest = 0.50;
return ($num / $nearest) ;
The simplest solution is to typecast your input. A small example in your case is:
function roundNum($num){
$nearest = 0.50;
$result = (float) $num/ (float) $nearest;
return $result;
}
Read more about typecasting here
EDIT:
As it turns out your $num is a string. You can change this to a type float and make your calculations, like so:
$num = "48.2";
$float = (float)$num;
echo ceil($float * 2) / 2;
In this example your number is always rounded up by 0.5, so in this case to 48.5
Demo

Optimal way of cycling through 1000's of values

I need to find the value of x where the variance of two results (which take x into account) is the closest to 0. The problem is, the only way to do this is to cycle through all possible values of x. The equation uses currency, so I have to check in increments of 1 cent.
This might make it easier:
$previous_var = null;
$high_amount = 50;
for ($i = 0.01; $i <= $high_amount; $i += 0.01) {
$val1 = find_out_1($i);
$val2 = find_out_2();
$var = variance($val1, $val2);
if ($previous_var == null) {
$previous_var = $var;
}
// If this variance is larger, it means the previous one was the closest to
// 0 as the variance has now started increasing
if ($var > $previous_var) {
$l_s -= 0.01;
break;
}
}
$optimal_monetary_value = $i;
I feel like there is a mathematical formula that would make the "cycling through every cent" more optimal? It works fine for small values, but if you start using 1000's as the $high_amount it takes quite a few seconds to calculate.
Based on the comment in your code, it sounds like you want something similar to bisection search, but a little bit different:
function calculate_variance($i) {
$val1 = find_out_1($i);
$val2 = find_out_2();
return variance($val1, $val2);
}
function search($lo, $loVar, $hi, $hiVar) {
// find the midpoint between the hi and lo values
$mid = round($lo + ($hi - $lo) / 2, 2);
if ($mid == $hi || $mid == $lo) {
// we have converged, so pick the better value and be done
return ($hiVar > $loVar) ? $lo : $hi;
}
$midVar = calculate_variance($mid);
if ($midVar >= $loVar) {
// the optimal point must be in the lower interval
return search($lo, $loVar, $mid, $midVar);
} elseif ($midVar >= $hiVar) {
// the optimal point must be in the higher interval
return search($mid, $midVar, $hi, $hiVar);
} else {
// we don't know where the optimal point is for sure, so check
// the lower interval first
$loBest = search($lo, $loVar, $mid, $midVar);
if ($loBest == $mid) {
// we can't be sure this is the best answer, so check the hi
// interval to be sure
return search($mid, $midVar, $hi, $hiVar);
} else {
// we know this is the best answer
return $loBest;
}
}
}
$optimal_monetary_value = search(0.01, calculate_variance(0.01), 50.0, calculate_variance(50.0));
This assumes that the variance is monotonically increasing when moving away from the optimal point. In other words, if the optimal value is O, then for all X < Y < O, calculate_variance(X) >= calculate_variance(Y) >= calculate_variance(O) (and the same with all > and < flipped). The comment in your code and the way have you have it written make it seem like this is true. If this isn't true, then you can't really do much better than what you have.
Be aware that this is not as good as bisection search. There are some pathological inputs that will make it take linear time instead of logarithmic time (e.g., if the variance is the same for all values). If you can improve the requirement that calculate_variance(X) >= calculate_variance(Y) >= calculate_variance(O) to be calculate_variance(X) > calculate_variance(Y) > calculate_variance(O), you can improve this to be logarithmic in all cases by checking to see how the variance for $mid compares the the variance for $mid + 0.01 and using that to decide which interval to check.
Also, you may want to be careful about doing math with currency. You probably either want to use integers (i.e., do all math in cents instead of dollars) or use exact precision numbers.
If you known nothing at all about the behavior of the objective function, there is no other way than trying all possible values.
On the opposite if you have a guarantee that the minimum is unique, the Golden section method will converge very quickly. This is a variant of the Fibonacci search, which is known to be optimal (require the minimum number of function evaluations).
Your function may have different properties which call for other algorithms.
Why not implementing binary search ?
<?php
$high_amount = 50;
// computed val2 is placed outside the loop
// no need te recalculate it each time
$val2 = find_out_2();
$previous_var = variance(find_out_1(0.01), $val2);
$start = 0;
$end = $high_amount * 100;
$closest_variance = NULL;
while ($start <= $end) {
$section = intval(($start + $end)/2);
$cursor = $section / 100;
$val1 = find_out_1($cursor);
$variance = variance($val1, $val2);
if ($variance <= $previous_var) {
$start = $section;
}
else {
$closest_variance = $cursor;
$end = $section;
}
}
if (!is_null($closest_variance)) {
$closest_variance -= 0.01;
}

Boolean Tick Box Not Changing Overall Cost (PHP)

I have parsed over the variable $museum from another page under the name 'm'. If a check box was ticked on the page I parsed it from then on this new receipt page it will add 5 to the cost, or add 0. Cost is then echoed. But either way it is returning 0. First time poster and PHP beginner so sorry if I got something wrong or was not specific enough. Here is the code from the receipt page.
<?php
$cost = 0;
if(isset($_GET['m']))
{
$museum = $_GET['m'];
if($museum==false){
$cost + 0;
}else{
$cost + 5;
}
}
echo $cost;
?>
You are not using the return value of the operation. Try
$cost += 5;
instead of
$cost + 5;
Try this:
if($museum==false){
$cost = $cost + 0;
}else{
$cost = $cost + 5;
}

Categories