I have this code here...
$remaining = 0;
foreach($clientArrayInvoice as $key=>$row){
$remaining = $remaining + $row['total'];
}
What it does, it takes the values of total and adds them up...but when I have values that are negatives, it adds them up as well for an example when I have -51.75 and -17.85 I get -69.60 which it should be -33.90 how do I fix this?
`-33.901 is the value I am expecting because when its two negatives I would like to subtract, not add
Thanks,
J
This might help:
(-51.75) + (-17.85) = -69.60
(-51.75) - (-17.85) = -33.90
Assuming you always need to add the second number regardless of it's sign, you need to take the absolute value by using the PHP abs function with $row['total']:
$remaining = 0;
foreach($clientArrayInvoice as $key=>$row){
$remaining = $remaining + abs($row['total']);
}
In response to what you updated in your question:
-33.90 is the value I am expecting because when its two negatives I would like to subtract, not add
This is pretty much what using the abs function does. I could rewrite the above code snippet as:
$remaining = 0;
foreach($clientArrayInvoice as $key=>$row) {
if ($remaining >= 0) {
$remaining = $remaining + abs($row['total']);
}
else {
$remaining = $remaining - abs($row['total']);
}
}
However, this does the exact same thing as simply using the PHP abs function, since you are always adding the magnitude of $row['total'] to $remaining.
again --> see php's abs() function if you want to add things and ignore the sign.
I am not sure what your question is exactly, but this would keep adding the absolute values if $remaining is negative until it is positive again.
$remaining = $remaining + ($remaining < 0 && $row['remainingbalance']
< 0 ? -1 : 1) * $row['remainingbalance']);
This works for your example, it would be 0 - 51.75 + 17.85 = -33.9. But I am not sure if it's the behavior you want in the bigger picture.
Related
I am trying to find the difference of two numbers in percentage. The actual scenario is iam getting a total value of user data for this week and for last week. Now i need to see the performance difference in percentage with this weeks data and last weeks data. Following is my code which i am trying. But at times either any of the data will be zero and am getting an error "Division by zero". How to handle that?
$this_week_cust=$row["cust_count_new"];
$last_week_cust=$row["cust_count_old"];
$percentChange = (1 - $last_week_cust / $this_week_cust) * 100;
You can check if $this_week_cust is zero and just set the change to 100%
$this_week_cust=$row["cust_count_new"];
$last_week_cust=$row["cust_count_old"];
if ( $this_week_cust == 0 ) {
$percentChange = -100;
}
else {
$percentChange = (1 - $last_week_cust / $this_week_cust) * 100;
}
Altough the change would be 0 if $last_week_cust was also 0, so perhaps
if ( $this_week_cust == 0 ) {
$percentChange = ($last_week_cust==0)?0:-100;
}
I think this will help you.
$original= 1000;
$current = 5;
$diff = $current - $original;
$more_less = $diff > 0 ? "More" : "Less";
$diff = abs($diff);
$percentChange = ($diff/$original)*100;
echo "$percentChange% $more_less agaist $original";
try this
if $this_week_cust!=0 that time only calculation will perform otherwise not do anything
$this_week_cust=$row["cust_count_new"];
$last_week_cust=$row["cust_count_old"];
if($this_week_cust!=0){
$percentChange = (1 - $last_week_cust / $this_week_cust) * 100;
}
You can get the desired result by checking $this_week_cust, if is it return zero, null or empty set $this_week_cust to 100;
$percentChange=100;
I have two variables:
$points - could be positive or negative
$time_elapsed -is always positive
I'm trying to proportionally decrease $points based on $time_elapsed. I can't use subtraction because it's not "proportional" the way I need it. I need something similar to division, but that always decreases $points (division increases the number if it's negative) so that I get the following result:
$points = -12;
$time_elapsed = 4;
$points/time_elapsed = -48;
$points = 12;
$time_elapsed = 4;
$points/time_elapsed = 3;
I cannot use abs() because it would return -3 when points is -12, when really I need it to return -48 (I always need something that is $time_elapsed times smaller than $points).
I cannot use if conditions or anything similar. Is this even possible?
This will work. No conditionals!
Fiddle here
function getPoints($points, $time_elapsed)
{
$is_positive = $points > 0;
$converters = [
true => function($points, $time_elapsed) {
return $points / $time_elapsed;
},
false => function($points, $time_elapsed) {
return $points * $time_elapsed;
}
];
return $converters[$is_positive]($points, $time_elapsed);
}
echo getPoints(-12, 4), PHP_EOL;
echo getPoints(12, 4), PHP_EOL;
You can extract sign bit and use it to avoid conditional operators (while this restriction is weird idea):
$sgn = ($points >> 31) & 1 //(for 32-bit variables)
return $points * $sgn * $time + $points * (1 - $sgn) / $time
//returns $points * $time for negative and $points / $time for positive
How to solve nth degree equations in PHP
Example:
1/(1+i)+1/(1+i)2+...1/(1+i)n=k
While k is the constant,I'd like to find value of i.
How can I achieve this in PHP?
First of all, your expression on the left is a geometric sum, so you can rewrite it as (using x=1+i)
1/x*(1+...+1/x^(n-1)) = 1/x * (1-1/x^n)/(1-1/x) = (1-x^(-n))/(x-1)
and consequently the equation can be rewritten as
(1 - pow( 1+i, -n))/i = k
Now from the original expression one knows that the left side as a sum of convex monotonically decreasing functions is equally so, thus any of bisection, regula falsi variants or secant method will work sufficiently well.
Use
(1+i)^(-n)=1 - n*i + (n*(n+1))/2*i^2 +...
to get the approximative equation and first approximation
1-(n+1)/2*i = k/n <=> i = (1-k/n)*2/(n+1)
so that you can start bracketing method with the interval from 0 to twice this i.
Try something like this....
$n = 5;
$i = 2;
$k = null;
for ($x = 1; $x <= $n; $x++) {
$k += 1 / pow((1 + $i), $x);
}
echo $k; //Answer --> 0.49794238683128
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;
}
i feel a little bit stupid, but let's imagine, that i have a set of unix timestamps:
1375110404
1374660925
1374482694
1374242337
1373793867
1373632889
1373187141
1373021668
1372754021
1372599890
What i'm trying to achieve is simple: I just want to calculate the average time difference between these 10 timestamps. I just can't find the proper way for the calculation.
What i just tried was
1375110404 - 1374660925 = 449479
1374482694 - 1374242337 = 240357
1373793867 - 1373632889 = 160978
1373187141 - 1373021668 = 165473
1372754021 - 1372599890 = 154131
449479 + 240357 + 160978 + 165473 + 154131 = 1170418
1170418 / 5 = 234083,6
but that looks illogical to me. Any advice is greatly appreciated.
EDIT:
All these stamps come from a php array.
EDIT:
Thanks to Orangepill for pointing me to the right direction. Here's the final solution:
for($cnt = count($array), $res = 0, $i = 1; $i < $cnt; $i++) {
$res += $array[$i-1] - $array[$i];
}
echo $res/$cnt;
This calculates
1375110404 - 1374660925 = 449479
1374660925 - 1374482694 = 178231
1374482694 - 1374242337 = 240357
1374242337 - 1373793867 = 448470
1373793867 - 1373632889 = 160978
1373632889 - 1373187141 = 445748
1373187141 - 1373021668 = 165473
1373021668 - 1372754021 = 267647
1372754021 - 1372599890 = 154131
449479 + 178231 + 240357 + 448470 + 160978 + 445748 + 165473 + 267647 + 154131 = 2510514
2510514 / 10 = 251051.4
which looks correct to me.
The most straight forward way it to do it like you described.
$res =0;
for($x = 1, $num = count($array); $x < $num; $x++){
$res =+ $array[$x] - $array[$x-1];
}
echo $res/($num-1);
The current accepted answer will give incorrect results if the the timestamps are not in strict chronological order. That is, negative values will skew your average. I may be wrong, but I imagine that you don't want to count any time difference as a negative value, after all, you can't run 100m in -12 seconds!
I provide this answer as an alternative that will always give an average based on positive time differences regardless of the order of the times in the passed array:-
function array_average_diff(array $array)
{
$diff = 0;
for($i = 1; $i < count($array); $i++){
$diff += abs($array[$i] - $array[$i - 1]);
}
return $diff/count($array);
}
See it working