Format money, calculated by multiplying hours * rate (multiple entries in db) - php

I am facing a difficult problem here, and i don't know how to solve it.
I have 2 different tables. A Tasks table and Projects table. The tasks table holds time spent(in seconds), the rate per hour for that specific task, and in which project does that entry belong to. So basically something like this:
{id} - {seconds} - {rate} - {projectId}
Now, i am calculating the billing rate per hour for a specific task like this:
function calc ($Totalseconds, $rate){
$minutes = $Totalseconds/60; //minutes
$money = $rate * ($minutes / 60); //hours
return $money;
}
...
$money = calc($task['seconds'], $task['rate']);
$value = number_format($money,2); //ex. 1,824.69
This of course works well....For example:
task1 is 1,824.69
task2 is 24.33
etc....
As long as a project has only a few tasks, then the total billing rate for that project is correct. But when a project has more than a few tasks under it, then the total value is a bit different than when i am adding them all manually with a calculator...So in another page i am showing the total billing rate for a specific project by calculating all tasks and rates for that specific projec.
I am 'selecting' all tasks from the db for a specific projectId in an array, then do:
//array projArray has the sum of all seconds and rate for every task under a specific project
//for example a project has 10 tasks with rate $12 p/h and 2 task with $10 p/h
//so projArray has 2 arrays. One for the total time in seconds for the 10 tasks + their rate and one for the 2 tasks + their rate.
$total = 0;
foreach($projArray as $value) {
$total += calc($value['TotalTime'], $value['rate']);
}
$Totalvalue = number_format($total,2);
And here is the problem...When i am manually adding all the task's billing rate, for a specific project, with a calculator i get 2,426.91 but this last function returns 2,426.92 instead.
The seconds and rates are correct in both cases. I dont get it why is there a difference with the final value ?
I guess the more tasks i have under a project the bigger the difference ? Right now i am testing things with 1-50 tasks...for each project

Example data:
a: 1,233
b: 1,233
c: 1,233
number_format((a + b + c), 2) = 3,70
number_format(a, 2) + number_format(b, 2) + number_format(c, 2) = 3,69
When you call number_format on each task individually, 0,003 is being rounded off.
Something similar is probably happening in your calculations.

Related

How to get web server average load level in percentages using PHP function sys_getloadavg()?

PHP function sys_getloadavg() returns an array with three values showing average number of processes in the system run-queue over the last 1, 5 and 15 minutes, respectively.
How to convert this production to percentages?
Percentages are relative measurement units. This means that we must know a range or minimum and maximum values of the measured quantity. Function sys_getloadavg() evaluates performance of whole system, not separate CPU load level, or usage of memory, file system or database. It returns float numbers showing how many processes were in run-queue for the last interval of time.
I did some experiment with my MacBook Pro (8 CPU cores) and PHP 7.0 to figure out range of values produced by sys_getloadavg(). I've got average figures between 1.3 and 3.2. When I run video conversion program in parallel, the maximum result jumped up to 18.9. By the way, in all cases I didn't fix substantial losses in web page loading speed. It means that whole system was not overloaded.
Let's take for 100% of system load situation when web page don't load for reasonable time, let say 10 sec. I don't know what values will return sys_getloadavg() in this case, but I think it will be something big.
My solution is very simple. Let's measure system average load level and persistently store results as minimum and maximum values. When system works faster or slower we will update min and max by new values. So, our program will 'learn' the system and becomes more and more precise. The value of the last minute will be compared with stored range and converted to percents like (loadavg - min)/((max - min) / 100):
$performance = sys_getloadavg();
try {
$rangeFile = 'sys_load_level.txt';
$range = file($rangeFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$performance = array_merge($performance, $range);
$min = min($performance);
$max = max($performance);
if ($range[0] > $min || $range[1] < $max)
file_put_contents($rangeFile, [$min.PHP_EOL, $max.PHP_EOL]);
}
catch (Exception $e) {
$min = min($performance);
$max = max($performance);
file_put_contents($rangeFile, [$min.PHP_EOL, $max.PHP_EOL]);
}
$level = intval(($performance[0] - $min) / (($max - $min) / 100.0));

Loop Through results PHP or Jquery

I have been working on this for almost three days with no good result. I am trying to get this done in Laravel. But I am looking for any type of good ideas.
I have a product that has a MSRP price. The price for every product drops 10 percent every single day since the product was posted, to the hour.
But i would like to show the price drop for every day as you can see in the picture posted.
Here are some way i have been trying to do it. None of them seem very clean.
Add 1 extra row to the database and call it price. - write a CRON that will run every hour on the server looking at the all the products and setting the new price in that table. But that will mean that I will be using a lot of resources from the server.
Add 10 extra rows in the database and generate the prices when the product is added. However I am having an issue trying to figure out how to show what day it is and highlighted in red. I am guessing I could do this via jquery. Dont know it well but will that be a way?
Pull the products from that database and then cycle through each one and use this code that will generate the table and prices. But than again if the flow of traffic is huge it will eat a lot of the server.
Any other ideas? Anything will help that can help me streamline this.
Here is the code I was able to come up with for the 3ed options. As i dont know jquery i dont have one for the second one.
$msrp = 29.59;
$dayposted = "2016-1-26";
$cDate = Carbon::parse($dayposted);
$today = $cDate->diffInDays();
$days = [];
$i = 1;
$percent = 0;
for($n=0 ;$n<10; $n++) {
setlocale(LC_MONETARY, 'en_US.UTF-8');
if ($i == $today) {
$day = array_add(['day' => 'Day '.$i], 'price' , number_format( $msrp * ((100-($i*10))/100),2, '.', ''));
$day = array_add($day, 'class', 'today');
$price = number_format( $msrp * ((100-($i*10))/100),2, '.', '');
}
elseif($i == 10) {
$day = array_add(['day' => 'Final'], 'price' , number_format( $msrp * ((100-($i*10))/100),2, '.', ''));
$day = array_add($day, 'class', '');
}
else{
$day = array_add(['day' => 'Day '.$i], 'price' , number_format( $msrp * ((100-($i*10))/100),2, '.', ''));
$day = array_add($day, 'class', '');
}
array_push ($days, $day);
$i++;
}
Also here is what I am looking to get done.
Press here to see the image
The answer is it depends on when you want the work to be done (the calculation).
I agree that doing the calculation every time a user requests the information if you don't have to is an obvious waste of resources. However, mathematical calculations are not very intensive so long as you're not doing a lot of iterating, querying or worst of all counting things in the database.
That being said, if you really want to make sure these calculations don't bog down your server the solution I'd suggest is to do it on the client.
You return the raw data to the client and calculate the pricing on the browser, this way the calculation is done off the server and only when requested. This may not be an option, however, because you may not want to expose your pricing method to the client. Still, a simple javascript function that just calculates the % reduction based on a difference between now and the date posted would be easiest.
Regardless, this might be a case of micro-optimization. If you're concerned, do some benchmarks and see how your server handles it under load. That's the only way to know for sure if this optimization is necessary or not.

Using round() to get exact value - PHP

Hey guy's I am working on a project of mine which involves the use of money. I am trying to not use round anymore because, it's rounding things to nearest tenth and I need exact numbers. One reason I was using it, was because it was giving a whole number.
The way I am working my number system is that 100 = $1, 2000 = $20, etc.. I was currently using the round function because it would get rid of the decimal point for me and give me a whole number, lets say: 223 which in turn would = $2.23.
Here is what I am using:
$amount += round(($amount / 29) + 30);
Here are the numbers:
Lets say we have a charge of 100 and we add 125 which equal 225 (USD $2.25). Now we add taxes and processing: + 2.9% + $.30. After multiplying 2.25 by 2.9% and adding .30 the amount would be: 0.36525 - this is the amount that should be added than to the $2.25 which than would be 261 = $2.61
The issue is because of the rounding, when I look in my Stripe panel (I am using Stripe API for payments) I see a charge of $2.63. So my question is, how would I go about making it exact without having any rounding and decimal places.
UPDATE:
Here is the above example more explained:
Lets say we have a charge of 100 and we add 125 which equal 225 (USD $2.25). Now we add taxes and processing: + 2.9% + $.30. After multiplying 2.25 by 2.9% and adding .30 the amount would be: 0.36525 - this is the amount that should be added than to the $2.25 which than would be 261 = $2.61
So now with that the actual value of amount that should be charged is $2.61 but instead when using the round it gives me 263 which also means $2.63. The above example is the simple math that is correct.
In order to avoid calculation hiccups like that, only round the final result. Keep all other calculations as accurate as possible:
$original = 100;
$original += 125;
$tax = $original * 2.9 / 100; //+2.9%
$tax += 30; //+$.30
$original += $tax; //Add tax.
echo $original; //Result is 261.525. Round as you please.
You can specify precision and rounding method to keep it consistent (PHP round()), then you can deal with the actual values. Doing math tricks like multiplication by a multiple of 10 will only make it more confusing in the long run.
$amount += round(($amount / 29) + 30, 2, PHP_ROUND_HALF_UP);
Will this solve your problem?

Price Filter Grouping Algorithm

I am creating an ecommerce site, and I am having trouble developing a good algorithm to sort a products that are pulled from the database into halfway appropriate groups. I have tried simply dividing the highest price into 4, and basing each group off that. I also tried standard deviations based around the mean. Both could result with price ranges that no product would fall into, which isn't a useful filtering option.
I also tried take quartiles of the products, but my problem is that the price ranges from $1 items to $4,000. The $4,000 almost never sell, and are far less important, but they keep skewing my results.
Any thoughts? I should have paid more attention in stats class ...
Update:
I ended up combining methods a bit. I used the quartile/bucket method, but hacked it a bit by hardcoding certain ranges within which a greater number of price groups would appear.
//Price range algorithm
sort($prices);
//Divide the number of prices into four groups
$quartilelength = count($prices)/4;
//Round to the nearest ...
$simplifier = 10;
//Get the total range of the prices
$range = max($prices)-min($prices);
//Assuming we actually are working with multiple prices
if ($range>0 )
{
// If there is a decent spread in price, and there are a decent number of prices, give more price groups
if ($range>20 && count($prices) > 10)
{
$priceranges[0] = floor($prices[floor($quartilelength)]/$simplifier)*$simplifier;
}
// Always grab the median price
$priceranges[1] = floor($prices[floor($quartilelength*2)]/$simplifier)*$simplifier;
// If there is a decent spread in price, and there are a decent number of prices, give more price groups
if ($range>20 && count($this->data->prices) > 10)
{
$priceranges[2] = floor($prices[floor($quartilelength*3)]/$simplifier)*$simplifier;
}
}
Here is an idea: basically you would sort the price into buckets of 10, each price as the key in the array, the value is a count of how many products are at the given price point:
public function priceBuckets($prices)
{
sort($prices);
$buckets = array(array());
$a = 0;
$c = count($prices);
for($i = 0; $i !== $c; ++$i) {
if(count($buckets[$a]) === 10) {
++$a;
$buckets[$a] = array();
}
if(isset($buckets[$a][$prices[$i]])) {
++$buckets[$a][$prices[$i]];
} else if(isset($buckets[$a - 1][$prices[$i]])) {
++$buckets[$a - 1][$prices[$i]];
} else {
$buckets[$a][$prices[$i]] = 1;
}
}
return $buckets;
}
//TEST CODE
$prices = array();
for($i = 0; $i !== 50; ++$i) {
$prices[] = rand(1, 100);
}
var_dump(priceBuckets($prices));
From the result, you can use reset and end to get the min/max of each bucket
Kinda brute force, but might be useful...
Here is an idea, following the line of thought of my comment:
I assume you have a set of products, each of them tagged by a price and a sales volume estimate (as a percent from the total sales). First, sort all products by their price. Next, start splitting: traverse the ordered list, and accumulate sales volume. Each time you reach about 25%, cut there. If you do so 3 times, it will result in 4 subsets having disjoint price ranges, and a similar sales volume.
What exactly are you looking for as your end result (could you give us an example grouping)? If your only goal is for all groups to have a significant number of important enough products, then, even if you come up with the perfect algorithm that works for your current data set that does not mean it will work with tomorrow's dataset. Depending on the number of sets of groups you need I would simply make arbitrary groups that fit your needs instead of using an algorithm. Ex. ($1 - $25, $25-100, $100+). From a consumer's perspective my mind naturally distributes products into 3 difference price categories (cheap, midrange and expensive).
I think you're thinking too much.
If you know your products, and you like fine grained results, I would simply hard code those price ranges.
If you think $1 to $10 makes sense for what you are selling, put it in, you don't need an algorithm. Just do a check so that you only show ranges that have results.
If you don't know your products, I would just sort all the products by price, and divide it into 4 groups of equal number of products.

How can I get X amount of files per folder with math?

I actually have it done, I did this math equation about 2 years ago and I am having trouble understanding it now.
Basicly I use this so that when users upload photos to my site, I can balance them out with only X amount of photo per folder.
This gives me something like this 1/1 1/2 1/3 1/4 ----1/10 2/1 2/2 2/3 and so on but I need to modify it to go 3 folders deep, each folder should have a limit of the number 1-9 or 1-10 then it will increase that number to the next
So if a large enough number is entered into my function below and the result is 3/10 then when the right number of objects is reached it would bump up to 4/1 then when so many thousands objects go by again it will jump to 4/2. What I am wanting to do is make it 3 numbers/levels deep 3/10/2 would go to 3/10/3 when it got to 3/10/10 it would go 4/1/1 4/1/2 4/1/3 when the third place got to 10 it would make it got to 4/2/1
<?PHP
function uploadfolder($x) {
$dir = floor($x/18001) + 1;
$sdir = ceil($x/2000) % 9;
return "$dir/$sdir";
}
?>
I spent a lot of time 2 years ago to get it to do this with 2 levels deep and I just kind of got lucky and now it is somewhat confusing for me looking back at it
It seems to do roughly this:
It will package 2000 pictures into a subdirectory (0..8) using the line
$sdir = ceil($x/2000) % 9
Spelled out: how many times does 2000 fit into $x. As you limit this to 9 subdirectories using the modulo 9, you would get the 18001rst photo into subdirectory 0 again.
The upper level changes therefore using 18001 as limit. All photos from 1..18000 go into directory 1. (The +1 just shifts the interval to start from 1. That is the line
$dir = floor($x/18001) + 1;
Now you could go about it like this for 3 levels (pseudocode, as I do not know PHP):
function uploadfolder($x) {
$numOfPics = 2000;
$numOfFolders = 9;
$topdir = ceil($x / ($numOfPics * $numOfFolders * $numOfFolders));
$middir = floor($x / ($numOfPics * $numOfFolders)) % $numOfFolders + 1;
$botdir = (floor($x / $numOfPics) % $numOfFolders) + 1;
return "$topdir/$middir/$botdir";
}

Categories