package com.sunxung.factoring.component.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description:实现Excel IRR（内部收益率）计算，NPV:Net Present Value - 净现值
 * @Author:wanxiangZhou
 * @E_mail:303526821@qq.com
 * @Date:2017年5月10日 下午3:33:39
 */
public class IrrUtil {

    /** 最小差异 **/
    private static final double MINDIF = 0.0001;// 该数字越小，差异越小，则进行大额数据计算时候更容易返回Double.NaN
    /** 迭代次数 **/
    private static int LOOPNUM = 2000;
    /** 还款周期，如每隔2月还款一次，则周期为2 **/
    private static int cycle = 0;
    private List<BigDecimal> netCash = new ArrayList<BigDecimal>();

    public static void main(String[] args) {
        List<BigDecimal> list = new ArrayList<BigDecimal>();
        list.add(new BigDecimal("-72"));
        list.add(new BigDecimal("0"));
        list.add(new BigDecimal("0"));
        list.add(new BigDecimal("80"));
        IrrUtil aa = new IrrUtil(list, 5);
        System.out.println(aa.calculateIrr());
    }

    public IrrUtil(List<BigDecimal> netCashArr, int interval){
        super();
        netCash = netCashArr;
        cycle = interval;
    }

    private double NPV(double r) {
        double npv = 0;
        if (netCash.size() != 0) {
            for (int count = 0; count < netCash.size(); count++) {
                npv += Double.valueOf(netCash.get(count).toString()) / Math.pow(1 + r, count);
            }
            return npv;
        }
        return Double.NaN;
    }

    public double calculateIrr() {
        double irr = 0;
        double max = new BigDecimal("0.005").doubleValue();
        double min = new BigDecimal("0").doubleValue();
        double npv1 = NPV(max);
        double npv2 = NPV(min);
        System.out.println(npv1 + "  " + npv2);
        int count = 0;
        while (Math.abs(npv2) > MINDIF && count < LOOPNUM) {
            irr = min - npv2 * (min - max) / (npv2 - npv1);
            max = min;
            min = irr;
            npv1 = npv2;
            npv2 = NPV(min);
            count++;
        }
        if (Math.abs(npv2) < MINDIF && count <= LOOPNUM) {
            // 年华IRR=(1+计算结果)^(12/还款周期)-1，计算结果实际上是还款周期的irr
            // return Math.pow(1 + irr, 12.0/cycle) - 1;
            // 日IRR=(1+计算结果)^(12/还款周期/365)-1，计算结果实际上是还款周期的irr
            // return Math.pow(1 + irr, 365) - 1;
            return irr * 365;// 现在使用的计算日IRR
        } else {
            return Double.NaN;
        }
    }
}
