how to do XIRR calculation in php? - php

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";

Related

Php Price calculation based on given table

using this price table we are calculating price of the given input measurement
example:
(1) width = 30; , height =56 ; Price=?
so
(width>25){ new_width=50; }
(height<100){ new_height=100; }
so price = 20;
(2) width =12; height=267;
(width<25){ new_width=25; }
(height>250){ new_height=300; }
so price= 30;
I wrote a function for to calculate price based on the given value, and this function help to get the new_width , and height based on the table , But I don't know how to get price based on this table.
function calculate_price($width,$height ){
if($width<25){
$new_width=25;
}elseif($width>25 && $width<50 ){
$new_width=50;
}else{
$new_width=50;
}
if($width<100){
$new_width=100;
}elseif($width>100 && $width<150 ){
$new_width=150;
}elseif($width>150 && $width<200 ){
$new_width=200;
}elseif($width>200 && $width<250 ){
$new_width=250;
}elseif($width>250 && $width<300 ){
$new_width=300;
}
else{
$new_width=300;
}
$price=needed forumula [ based on new_width & new_height ];
return $price ;
}
You can use ceil to round up the width and height this function
You can use array to store the price with key height_width for simplicity.
function calculate_price($width, $height) {
$price = array(
"100_25" => 10,
"100_50" => 20,
"150_25" => 15,
"150_50" => 25,
"200_25" => 18,
"200_50" => 31,
"250_25" => 24,
"250_50" => 42,
"300_25" => 20,
"300_50" => 45,
);
$newWidth = ceil($width / 25) * 25; //Round up by 25
$newHeight = ceil($height / 50) * 50; //Round up by 50
return $price[ $newHeight . "_" . $newWidth ];
}
You can call
echo calculate_price( 30, 56 ); /* width and height parameters */
This will result to
20
Base on the info you provided, you have two logical paths. The first, is the width less than or equal to 25 or is the width greater then 25. Then you have to reason out the height.
Consider the following:
function calculate_price($width, $height){
$price = false;
if($width > 25){
switch(true){
case $height <= 100:
$price = 20;
break;
case $height <= 150:
$price = 25;
break;
case $height <= 200:
$price = 31;
break;
case $height <= 250:
$price = 42;
break;
case $height <= 300:
$price = 45;
break;
}
} else {
switch(true){
case $height <= 100:
$price = 10;
break;
case $height <= 150:
$price = 15;
break;
case $height <= 200:
$price = 18;
break;
case $height <= 250:
$price = 24;
break;
case $height <= 300:
$price = 30;
break;
}
}
return $price;
}
With the following input: echo calculate_price(30, 56); we would have an output of: 20.
Running the following:
echo calculate_price(30, 56) . "<br />";
echo calculate_price(12, 267) . "<br />";
echo calculate_price(25, 249) . "<br />";
I get:
20
30
24
Format as needed (E.G.: echo sprintf("$%d.00", calculate_price(30, 56));)
Full Test
<?php
function calculate_price($width, $height){
$price = false;
if(!is_int($width) || !is_int($height)){
return $price;
}
if($width > 25){
switch(true){
case $height <= 100:
$price = 20;
break;
case $height <= 150:
$price = 25;
break;
case $height <= 200:
$price = 31;
break;
case $height <= 250:
$price = 42;
break;
case $height <= 300:
$price = 45;
break;
}
} else {
switch(true){
case $height <= 100:
$price = 10;
break;
case $height <= 150:
$price = 15;
break;
case $height <= 200:
$price = 18;
break;
case $height <= 250:
$price = 24;
break;
case $height <= 300:
$price = 30;
break;
}
}
return $price;
}
echo sprintf("$%d.00", calculate_price(30, 56)) . "<br />";
echo sprintf("$%d.00", calculate_price(12, 267)) . "<br />";
echo sprintf("$%d.00", calculate_price(25, 249)) . "<br />";
echo sprintf("$%d.00", calculate_price(-1, 'a')) . "<br />";
?>
Results:
$20.00
$30.00
$24.00
$0.00
You can use Multidimensional Array
$x = "300";
$y = "50";
$multi = array();
$multi["100"]["25"] = "10";
$multi["100"]["50"] = "20";
$multi["200"]["25"] = "30";
$multi["300"]["50"] = "40";
echo $multi[$x][$y];
Based of your code, if you don't have database to get those $price, I think you can try somehting like this :
function calculate_price($width,$height ){
// Your $new_width according to your $width
if($width<=25){
$new_width=25;
}else
$new_width=50;
}
// Your $new_height according to your $height
if($height<=100){
$new_height=100;
}elseif($height>100 && $height<=150 ){
$new_height=150;
}elseif($height>150 && $height<=200 ){
$new_height=200;
}elseif($height>200 && $height<=250 ){
$new_height=250;
}elseif($height>250){
$new_height=300;
}
// Now, according to your new value you will find the price with some test :
if ($new_width == 25) {
switch($new_height) {
case 100 : $price = 10; break;
case 150 : $price = 15; break;
case 200 : $price = 18; break;
case 250 : $price = 24; break;
case 300 : $price = 30; break;
}
} else {
switch($new_height) {
case 100 : $price = 20; break;
case 150 : $price = 25; break;
case 200 : $price = 31; break;
case 250 : $price = 42; break;
case 300 : $price = 45; break;
}
}
return $price ;
}
But I think you can find other way to achieve it too as suggested in other anwser !
Is this what you are looking for? It's not very flexible since you don't use database to get those value but it should work

Multi-dimensional table (excelsheet) as an php array. Or any other ideas?

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);

Mandelbrot set won't render correctly

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

Php financial XIRR not giving strange results

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)

Rounding to the Nearest Ending Digits

I have the following function that rounds a number to the nearest number ending with the digits of $nearest, and I was wondering if there is a more elegant way of doing the same.
/**
* Rounds the number to the nearest digit(s).
*
* #param int $number
* #param int $nearest
* #return int
*/
function roundNearest($number, $nearest, $type = null)
{
$result = abs(intval($number));
$nearest = abs(intval($nearest));
if ($result <= $nearest)
{
$result = $nearest;
}
else
{
$ceil = $nearest - substr($result, strlen($result) - strlen($nearest));
$floor = $nearest - substr($result, strlen($result) - strlen($nearest)) - pow(10, strlen($nearest));
switch ($type)
{
case 'ceil':
$result += $ceil;
break;
case 'floor':
$result += $floor;
break;
default:
$result += (abs($ceil) <= abs($floor)) ? $ceil : $floor;
break;
}
}
if ($number < 0)
{
$result *= -1;
}
return $result;
}
Some examples:
roundNearest(86, 9); // 89
roundNearest(97, 9); // 99
roundNearest(97, 9, 'floor'); // 89
Thanks in advance!
PS: This question is not about rounding to the nearest multiple.
This works for me:
function roundToDigits($num, $suffix, $type = 'round') {
$pow = pow(10, floor(log($suffix, 10) + 1));
return $type(($num - $suffix) / $pow) * $pow + $suffix;
};
$type should be either "ceil", "floor", or "round"
I think this should work, and it's more elegant to me, at least:
function roundNearest($number, $nearest, $type = null)
{
if($number < 0)
return -roundNearest(-$number, $nearest, $type);
$nearest = abs($nearest);
if($number < $nearest)
return $nearest;
$len = strlen($nearest);
$pow = pow(10, $len);
$diff = $pow - $nearest;
if($type == 'ciel')
$adj = 0.5;
else if($type == 'floor')
$adj = -0.5;
else
$adj = 0;
return round(($number + $diff)/$pow + $adj)*$pow - $diff;
}
Edit: Added what I think you want from negative inputs.

Categories