Example #1
0
 /**
  * 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();
 }