I have a excelsheet with a table representing the price calculation for a tourplanning system.
You can download the sheet here:
https://www.dropbox.com/s/ctam8iwym9pumjz/Example.xlsx?dl=0
Now, I want to build a PHP function like:
priceCalc($kilometers, $numberOfPersons, $doubleTour)
Example values of parameters:
$kilometers = 130.0; (double)
$numberOfPersons = 4; (integer)
$doubleTour = true; (boolean)
Result has to be with these values = 218.00 € (see excelsheet)
How would you implement it the easiest way (without 3rd-party classes or extensions - pure PHP)?
Got it!
function getEcoPrice($distance, $persons, $doubleTour) {
$distance = ceil($distance); //round up to next integer
$startPrice = 69;
$endprice = $startPrice;
$amountPlusPerson = array(0, 0, 20, 20, 10, 10, 10, 10, 10); //first index is just for setting index = number of persons. value to add, if extra person.
$amountNextDistance = array(0, 10, 10, 10, 10, 10, 10, 10, 10); //first index is just for setting index = number of distance steps. value to add, if next distance is reached.
$amountDoubleTour = array(-20, -20, -20, -20, -20, -20, -20, -20, -20); //value to add, if doubleTour is enabled.
$index = 0;
switch (true) {
case $distance <= 130:
$index = 0;
break;
case $distance <= 160:
$index = 1;
break;
case $distance <= 170:
$index = 2;
break;
case $distance <= 180:
$index = 3;
break;
case $distance <= 190:
$index = 4;
break;
case $distance <= 200:
$index = 5;
break;
case $distance <= 210:
$index = 6;
break;
case $distance <= 220:
$index = 7;
break;
case $distance <= 230:
$index = 8;
break;
case $distance > 230:
return 99999;
break;
}
for($i = 0; $i <= $index; $i++) {
$endprice += $amountNextDistance[$i];
};
for ($i = 0; $i <= $persons; $i++) {
$endprice += $amountPlusPerson[$i];
}
if ($doubleTour) {
$endprice = $endprice * 2 + $amountDoubleTour[$index];
}
return $endprice;
}
function call:
echo getEcoPrice(200.1, 2, false);
Related
I have a PHP pie chart which uses data from Mysql to show the chart. However if one data is missing the whole chart turns to one color. For example for grading if the input is A, B, D and F(pay attention C grade input is missing) then the whole pie chart is in one color like Orange or red.
Can you please help me with this? Thanks
<?php
$show_label = true; // true = show label, false = don't show label.
$show_percent = true; // true = show percentage, false = don't show percentage.
$show_text = true; // true = show text, false = don't show text.
$show_parts = false; // true = show parts, false = don't show parts.
$label_form = 'square'; // 'square' or 'round' label.
$width = 199;
$background_color = 'FFFFFF'; // background-color of the chart...
$text_color = '000000'; // text-color.
$colors = array('0000ff', '006600', 'ffff00','DD7C1D', 'FF3300', 'CC6600','990000','520000','BFBFC1','808080'); // colors of the slices.
$shadow_height = 16; // Height on shadown.
$shadow_dark = true; // true = darker shadow, false = lighter shadow...
// DON'T CHANGE ANYTHING BELOW THIS LINE...
$data = $_GET["data"];
$label = $_GET["label"];
$height = $width/2;
$data = array_filter(explode('*',$data));
if ($label != '') $label = explode('*',$label);
for ($i = 0; $i < count($label); $i++)
{
if ($data[$i]/array_sum($data) < 0.1) $number[$i] = ' '.number_format(($data[$i]/array_sum($data))*100,1,',','.').'%';
else $number[$i] = number_format(($data[$i]/array_sum($data))*100,1,',','.').'%';
if (strlen($label[$i]) > $text_length) $text_length = strlen($label[$i]);
}
if (is_array($label))
{
$antal_label = count($label);
$xtra = (5+15*$antal_label)-($height+ceil($shadow_height));
if ($xtra > 0) $xtra_height = (5+15*$antal_label)-($height+ceil($shadow_height));
$xtra_width = 5;
if ($show_label) $xtra_width += 20;
if ($show_percent) $xtra_width += 45;
if ($show_text) $xtra_width += $text_length*8;
if ($show_parts) $xtra_width += 35;
}
$img = ImageCreateTrueColor($width+$xtra_width, $height+ceil($shadow_height)+$xtra_height);
ImageFill($img, 0, 0, colorHex($img, $background_color));
foreach ($colors as $colorkode)
{
$fill_color[] = colorHex($img, $colorkode);
$shadow_color[] = colorHexshadow($img, $colorkode, $shadow_dark);
}
$label_place = 5;
if (is_array($label))
{
for ($i = 0; $i < count($label); $i++)
{
if ($label_form == 'round' && $show_label)
{
imagefilledellipse($img,$width+11,$label_place+5,10,10,colorHex($img, $colors[$i % count($colors)]));
imageellipse($img,$width+11,$label_place+5,10,10,colorHex($img, $text_color));
}
else if ($label_form == 'square' && $show_label)
{
imagefilledrectangle($img,$width+6,$label_place,$width+16,$label_place+10,colorHex($img, $colors[$i % count($colors)]));
imagerectangle($img,$width+6,$label_place,$width+16,$label_place+10,colorHex($img, $text_color));
}
if ($show_percent) $label_output = $number[$i].' ';
if ($show_text) $label_output = $label_output.$label[$i].' ';
if ($show_parts) $label_output = $label_output.$data[$i];
imagestring($img,'2',$width+20,$label_place,$label_output,colorHex($img, $text_color));
$label_output = '';
$label_place = $label_place + 15;
}
}
$centerX = round($width/2);
$centerY = round($height/2);
$diameterX = $width-4;
$diameterY = $height-4;
$data_sum = array_sum($data);
$start = 270;
for ($i = 0; $i < count($data); $i++)
{
$value += $data[$i];
$end = ceil(($value/$data_sum)*360) + 270;
$slice[] = array($start, $end, $shadow_color[$value_counter % count($shadow_color)], $fill_color[$value_counter % count($fill_color)]);
$start = $end;
$value_counter++;
}
for ($i=$centerY+$shadow_height; $i>$centerY; $i--)
{
for ($j = 0; $j < count($slice); $j++)
{
ImageFilledArc($img, $centerX, $i, $diameterX, $diameterY, $slice[$j][0], $slice[$j][1], $slice[$j][2], IMG_ARC_PIE);
}
}
for ($j = 0; $j < count($slice); $j++)
{
ImageFilledArc($img, $centerX, $centerY, $diameterX, $diameterY, $slice[$j][0], $slice[$j][1], $slice[$j][3], IMG_ARC_PIE);
}
OutputImage($img);
ImageDestroy($img);
function colorHex($img, $HexColorString)
{
$R = hexdec(substr($HexColorString, 0, 2));
$G = hexdec(substr($HexColorString, 2, 2));
$B = hexdec(substr($HexColorString, 4, 2));
return ImageColorAllocate($img, $R, $G, $B);
}
function colorHexshadow($img, $HexColorString, $mork)
{
$R = hexdec(substr($HexColorString, 0, 2));
$G = hexdec(substr($HexColorString, 2, 2));
$B = hexdec(substr($HexColorString, 4, 2));
if ($mork)
{
($R > 99) ? $R -= 100 : $R = 0;
($G > 99) ? $G -= 100 : $G = 0;
($B > 99) ? $B -= 100 : $B = 0;
}
else
{
($R < 220) ? $R += 35 : $R = 255;
($G < 220) ? $G += 35 : $G = 255;
($B < 220) ? $B += 35 : $B = 255;
}
return ImageColorAllocate($img, $R, $G, $B);
}
function OutputImage($img)
{
header('Content-type: image/jpg');
ImageJPEG($img,NULL,100);
}
?>
I have used PHP class from, http://www.phpclasses.org/ but it gives -1571465320791500131898188521929991589462016.00 % this as answer many times(you can take this example, date1= 04/14/2015, date2=08/19/2015(mm/dd/yyyy format), value1=-110,value2=5) Is there any solution for this, any other better go?
This question is asked previously, but there is no satisfactory answer..
-110 14-Apr-15
5 19-Aug-15
--------------------
-0.99986137
Above is what Excel shows,,,
Below is the code from php class
///////////for xirr calc////////////////
function DATEDIFF($datepart, $startdate, $enddate)
{
switch (strtolower($datepart)) {
case 'yy':
case 'yyyy':
case 'year':
$di = getdate($startdate);
$df = getdate($enddate);
return $df['year'] - $di['year'];
break;
case 'q':
case 'qq':
case 'quarter':
die("Unsupported operation");
break;
case 'n':
case 'mi':
case 'minute':
return ceil(($enddate - $startdate) / 60);
break;
case 'hh':
case 'hour':
return ceil(($enddate - $startdate) / 3600);
break;
case 'd':
case 'dd':
case 'day':
return ceil(($enddate - $startdate) / 86400);
break;
case 'wk':
case 'ww':
case 'week':
return ceil(($enddate - $startdate) / 604800);
break;
case 'm':
case 'mm':
case 'month':
$di = getdate($startdate);
$df = getdate($enddate);
return ($df['year'] - $di['year']) * 12 + ($df['mon'] - $di['mon']);
break;
default:
die("Unsupported operation");
}
}
function XNPV($rate, $values, $dates)
{
if ((!is_array($values)) || (!is_array($dates))) return null;
if (count($values) != count($dates)) return null;
$xnpv = 0.0;
for ($i = 0; $i < count($values); $i++)
{
$xnpv += $values[$i] / pow(1 + $rate, $this->DATEDIFF('day', $dates[0], $dates[$i]) / 365);
}
return (is_finite($xnpv) ? $xnpv: null);
}
function XIRR($values, $dates, $guess = 0.1)
{
if ((!is_array($values)) && (!is_array($dates))) return null;
if (count($values) != count($dates)) return null;
// create an initial bracket, with a root somewhere between bot and top
$x1 = 0.0;
$x2 = $guess;
$f1 = $this->XNPV($x1, $values, $dates);
$f2 = $this->XNPV($x2, $values, $dates);
for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; $i++)
{
if (($f1 * $f2) < 0.0) break;
if (abs($f1) < abs($f2)) {
$f1 = $this->XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates);
} else {
$f2 = $this->XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates);
}
}
if (($f1 * $f2) > 0.0) return null;
$f = $this->XNPV($x1, $values, $dates);
if ($f < 0.0) {
$rtb = $x1;
$dx = $x2 - $x1;
} else {
$rtb = $x2;
$dx = $x1 - $x2;
}
for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; $i++)
{
$dx *= 0.5;
$x_mid = $rtb + $dx;
$f_mid = $this->XNPV($x_mid, $values, $dates);
if ($f_mid <= 0.0) $rtb = $x_mid;
if ((abs($f_mid) < FINANCIAL_ACCURACY) || (abs($dx) < FINANCIAL_ACCURACY)) return $x_mid;
}
return null;
}
And We have to call it like this
echo 'XIRR: ' . $f->XIRR(array(-10000,2750,4250,3250,2750), array(
mktime(0,0,0,1,1,2008),
mktime(0,0,0,3,1,2008),
mktime(0,0,0,10,30,2008),
mktime(0,0,0,2,15,2009),
mktime(0,0,0,4,1,2009),
), 0.1) . "\n";
I am currently trying to make an animated Mandelbrot set visualisation. But right now it won't even render a single frame correctly.
I don't know where I made the mistake. I guess there is an error in the math.Will you please have a look at it?
Here is a how it looks right now:
Here is my mandelbrot function:
function mandelbrot($a, $b, $limit) {
$a_orig = $a;
$b_orig = $b;
$count = 0;
while(($count < $limit) && (sqrt(($a * $a) + ($b * $b)) <= 2)) {
$a = ($a * $a) - ($b * $b) + $a_orig;
$b = (2 * $a * $b) + $b_orig;
$count++;
}
return $count;
}
And here is the entire code:
<?php
function HSVtoRGB(array $hsv) {
list($H,$S,$V) = $hsv;
//1
$H *= 6;
//2
$I = floor($H);
$F = $H - $I;
//3
$M = $V * (1 - $S);
$N = $V * (1 - $S * $F);
$K = $V * (1 - $S * (1 - $F));
//4
switch ($I) {
case 0:
list($R,$G,$B) = array($V,$K,$M);
break;
case 1:
list($R,$G,$B) = array($N,$V,$M);
break;
case 2:
list($R,$G,$B) = array($M,$V,$K);
break;
case 3:
list($R,$G,$B) = array($M,$N,$V);
break;
case 4:
list($R,$G,$B) = array($K,$M,$V);
break;
case 5:
case 6: //for when $H=1 is given
list($R,$G,$B) = array($V,$M,$N);
break;
}
return array($R, $G, $B);
}
function mandelbrot($a, $b, $limit) {
$a_orig = $a;
$b_orig = $b;
$count = 0;
while(($count < $limit) && (sqrt(($a * $a) + ($b * $b)) <= 2)) {
$a = ($a * $a) - ($b * $b) + $a_orig;
$b = (2 * $a * $b) + $b_orig;
$count++;
}
return $count;
}
ini_set("max_execution_time", 0);
header ("Content-Type: image/gif");
$num_frames = 60;
$size = 1024;
$points = array($size);
$image = imagecreate($size, $size);
for($j = 0; $j <= $num_frames; $j++) {
$tmp_color = HSVtoRGB(array(($j + 1) / ($num_frames + 1), 1, 1));
$color[$j] = imagecolorallocate($image, $tmp_color[0] * 255, $tmp_color[1] * 255, $tmp_color[2] * 255);
}
for($x = 0; $x < $size; $x++) {
for($y = 0; $y < $size; $y++) {
imagesetpixel($image, $x, $y, $color[mandelbrot(-2 + ($x * 2.7 / ($size - 1)), -1.35 + ($y * 2.7 / ($size - 1)), $num_frames)]);
}
}
imagegif($image);
imagedestroy($image);
?>
Your complex number square is wrong. You are overwriting the old value of a where it is needed again in the computation of b. So save it in a temporary variable.
Also, the bailout value of 60 iterations is rather small, 200 would be more appropriate for this scale, for more detailed images it should be reasonably rapidly increase.
Use a*a+b*b < 4 instead of the unnecessary square root. One could re-use the values of a*a and b*b which would also solve the problem of the temporary variable.
norm=10
while ... and norm < 4
a2=a*a
b2=b*b
norm=a2+b2
b=2*a*b+b_orig
a=a2-b2+a_orig
end
I'm using the XIRR function from the php financial library (http://www.phpclasses.org/package/892-PHP-Financial-functions-with-the-Excel-function-names-.html) but I get strange results with these values (dates are d/m/y):
(01/01/2014, -400) , (01/10/2014, 18)
MS Excel correctly returns 0.98, while the XIRR function returns -1.5714653207915E+40. The code is as follow:
$f->XIRR(array(-400,18), array(
mktime(0,0,0,1,1,2014),
mktime(0,0,0,10,1,2014),
), 0.1);
Can anyone explain me what am I doing wrong? Thanks in advance for any help.
I have written one code from PHP Excel Functions.
I have calculated XIRR and XNPV.
Here is code sample with some dummy data.
Main advantage is that, There is no dependency on any library in this
code.
<?php
$rate = 0.12;
$values = array(-5000,-3000,-8000,25000,-4000);
$dates = array('01-02-2015','05-05-2016','02-03-2018','03-03-2019','05-03-2019');
/** FINANCIAL_MAX_ITERATIONS */
define('FINANCIAL_MAX_ITERATIONS', 128);
/** FINANCIAL_PRECISION */
define('FINANCIAL_PRECISION', 1.0e-08);
$result = XIRR($values,$dates,0.1);
print_r($result);
function XIRR($values, $dates, $guess = 0.1) {
$x1 = 0.0;
$x2 = $guess;
$f1 = XNPV($x1, $values, $dates);
$f2 = XNPV($x2, $values, $dates);
for ($i = 0; $i < 128; ++$i) {
if (($f1 * $f2) < 0.0) break;
if (abs($f1) < abs($f2)) {
$f1 = XNPV($x1 += 1.6 * ($x1 - $x2), $values, $dates);
} else {
$f2 = XNPV($x2 += 1.6 * ($x2 - $x1), $values, $dates);
}
}
$f = XNPV($x1, $values, $dates);
if ($f < 0.0) {
$rtb = $x1;
$dx = $x2 - $x1;
} else {
$rtb = $x2;
$dx = $x1 - $x2;
}
for ($i = 0; $i < FINANCIAL_MAX_ITERATIONS; ++$i) {
$dx *= 0.5;
$x_mid = $rtb + $dx;
$f_mid = XNPV($x_mid, $values, $dates);
if ($f_mid <= 0.0) $rtb = $x_mid;
if ((abs($f_mid) < FINANCIAL_PRECISION) || (abs($dx) < FINANCIAL_PRECISION)) return $x_mid;
}
}
function XNPV($rate, $values, $dates) {
$valCount = count($values);
$xnpv = 0.0;
for ($i = 0; $i < $valCount; ++$i)
{
$datediff = strtotime($dates[$i]) - strtotime($dates[0]);
$datediff = round($datediff / (60 * 60 * 24));
$xnpv += $values[$i] / pow(1 + $rate,$datediff / 365);
}
return $xnpv;
}
?>
The correct XIRR value is -98.417% as shown below
-400 + 18(1+i)^-(273/365) = 0
18(1+i)^-(273/365) = 400
(1+i)^-(273/365) = 400/18
(1+i)^(273/365) = 18/400
(1+i) = (18/400)^(365/273)
1+i = (0.045)^(1.336996337)
i = (0.045)^(1.336996337) - 1
i = -0.984174769
i = -98.417%
Use the American mm/dd/yyyy :
mktime(0,0,0,1,1,2014),
mktime(0,0,0,1,10,2014)
What I'd like here is a working, optimized version of my current code. While my function does return an array with actual results, I don't know if they are correct (I'm not a mathematics guru and I don't know Java code to compare my results against known implementations). Secondly, I'd like the function to be able to accept custom table sizes, but I don't know how to do that. Is table size equivalent to resampling the image? Am I applying the coefficients correctly?
// a lot of processing is required for large images
$image = imagecreatetruecolor(21, 21);
$black = imagecolorallocate($image, 0, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);
imagefilledellipse($image, 10, 10, 15, 15, $white);
print_r(imgDTC($image));
function imgDTC($img, $tableSize){
// m1 = Matrix1, an associative array with pixel data from the image
// m2 = Matrix2, an associative array with DCT Frequencies
// x1, y1 = coordinates in matrix1
// x2, y2 = coordinates in matrix2
$m1 = array();
$m2 = array();
// iw = image width
// ih = image height
$iw = imagesx($img);
$ih = imagesy($img);
// populate matrix1
for ($x1=0; $x1<$iw; $x1++) {
for ($y1=0; $y1<$ih; $y1++) {
$m1[$x1][$y1] = imagecolorat($img, $x1, $y1) & 0xff;
}
}
// populate matrix2
// for each coordinate in matrix2
for ($x2=0;$x2<$iw;$x2++) {
for ($y2=0;$y2<$ih;$y2++) {
// for each coordinate in matrix1
$sum = 1;
for ($x1=0;$x1<$iw;$x1++) {
for ($y1=0;$y1<$ih;$y1++) {
$sum +=
cos(((2*$x1+1)/(2*$iw))*$x2*pi()) *
cos(((2*$y1+1)/(2*$ih))*$y2*pi()) *
$m1[$x1][$y1]
;
}
}
// apply coefficients
$sum *= .25;
if ($x2 == 0 || $y2 == 0) {
$sum *= 1/sqrt(2);
}
$m2[$x2][$y2] = $sum;
}
}
return $m2;
}
My PHP function is a derivitive from this post in Java: Problems with DCT and IDCT algorithm in java. I have rewritten the code for php and readability. Ultimately, I am working on a script which will enable me to compare images and find similarities. The technique is outlined here: http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html.
Thanks!
This is how I performed my DCT what I'm doing here is to perform a 1 dimension DCT on each row. Then I took the result an perform the DTC on each column it's faster.
function dct1D($in) {
$results = array();
$N = count($in);
for ($k = 0; $k < $N; $k++) {
$sum = 0;
for ($n = 0; $n < $N; $n++) {
$sum += $in[$n] * cos($k * pi() * ($n + 0.5) / ($N));
}
$sum *= sqrt(2 / $N);
if ($k == 0) {
$sum *= 1 / sqrt(2);
}
$results[$k] = $sum;
}
return $results;
}
function optimizedImgDTC($img) {
$results = array();
$N1 = imagesx($img);
$N2 = imagesy($img);
$rows = array();
$row = array();
for ($j = 0; $j < $N2; $j++) {
for ($i = 0; $i < $N1; $i++)
$row[$i] = imagecolorat($img, $i, $j);
$rows[$j] = dct1D($row);
}
for ($i = 0; $i < $N1; $i++) {
for ($j = 0; $j < $N2; $j++)
$col[$j] = $rows[$j][$i];
$results[$i] = dct1D($col);
}
return $results;
}
Most algorithm I found on internet assume that the input matrix is 8x8. That's why you multiplyed by 0.25.
In general you should multiply by sqrt(2 / N) a 1D matrix and here we are in 2D so sqrt(2/N1) * sqrt(2/N2). If you do this for N1 = 8 and N2 = 8:
sqrt(2/8)^2 = 2/8 = 1/4 = 0.25
The other thing was to multiply by 1/sqrt(2) X0 it's for 1D matrix here we are in 2D so you multiply when k1 = 0 or k2 = 0. When k1 = 0 and k2 = 0 you have to do it twice.
First you need to test your function so find any working implementation. And compare results from your implementation with the results of the working implementation (with the same input).
If you whant your code to be faster you can look at this paper http://infoscience.epfl.ch/record/34246/files/Vetterli85.pdf (the first 2 parts).
In your case you can't use a custom table size because it should match the image size (can be wrong).