/** * XNPV * * Returns the net present value for a schedule of cash flows that is not necessarily periodic. * To calculate the net present value for a series of cash flows that is periodic, use the NPV function. * * Excel Function: * =XNPV(rate,values,dates) * * @param float $rate The discount rate to apply to the cash flows. * @param array of float $values A series of cash flows that corresponds to a schedule of payments in dates. * The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. * If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. * The series of values must contain at least one positive value and one negative value. * @param array of mixed $dates A schedule of payment dates that corresponds to the cash flow payments. * The first payment date indicates the beginning of the schedule of payments. * All other dates must be later than this date, but they may occur in any order. * @return float */ public static function XNPV($rate, $values, $dates) { $rate = Functions::flattenSingleValue($rate); if (!is_numeric($rate)) { return Functions::VALUE(); } if (!is_array($values) || !is_array($dates)) { return Functions::VALUE(); } $values = Functions::flattenArray($values); $dates = Functions::flattenArray($dates); $valCount = count($values); if ($valCount != count($dates)) { return Functions::NAN(); } if (min($values) > 0 || max($values) < 0) { return Functions::VALUE(); } $xnpv = 0.0; for ($i = 0; $i < $valCount; ++$i) { if (!is_numeric($values[$i])) { return Functions::VALUE(); } $xnpv += $values[$i] / pow(1 + $rate, DateTime::DATEDIF($dates[0], $dates[$i], 'd') / 365); } return is_finite($xnpv) ? $xnpv : Functions::VALUE(); }