内部收益率函数【IRR】

楼主
我是社区第55902位番薯,欢迎点我头像关注我哦~
本帖最后由 迈达斯之手 于 2017-6-2 10:05 编辑
  1. package com.midas.function.excel;

  2. import java.math.BigDecimal;

  3. import com.fr.general.FArray;
  4. import com.fr.general.GeneralUtils;
  5. import com.fr.script.AbstractFunction;

  6. public class IRR extends AbstractFunction {
  7.         
  8.         private static final long serialVersionUID = 7634415917398642321L;
  9.         private static final String ERROR_VALUE = "#NUM!";
  10.         
  11.         
  12.         @Override
  13.         public Object run(Object[] args) {
  14.                 try{
  15.                         if(1 == args.length){
  16.                                 return run( transArr( (FArray) args[0] ) );
  17.                         }else if(2 == args.length){
  18.                                 return run( transArr( (FArray) args[0] ), trans( args[1] ) );
  19.                         }
  20.                 }catch(Exception e){
  21.                         System.out.println(e);
  22.                 }
  23.                 return ERROR_VALUE;
  24.         }
  25.         
  26.         /**
  27.          * 将其他类型的数字转换为大数(保证精度)
  28.          * @param ele
  29.          * @return
  30.          */
  31.         private static BigDecimal trans(Object ele){
  32.                 try{
  33.                         String val = GeneralUtils.objectToString(ele);
  34.                         return new BigDecimal(val);
  35.                 }catch(Exception e){
  36.                         
  37.                 }
  38.                 return (BigDecimal) ele;
  39.         }
  40.         
  41.         /**
  42.          * 将数组转换为大数数组
  43.          * @param in
  44.          * @return
  45.          */
  46.         private static FArray<BigDecimal> transArr(FArray in){
  47.                 FArray<BigDecimal> rt = new FArray<BigDecimal>();
  48.                 for(int i=0;i<in.length();i++){
  49.                         Object ele = in.elementAt(i);
  50.                         rt.add(trans(ele));
  51.                 }
  52.                 return rt;
  53.         }
  54.         
  55.         
  56.         private static BigDecimal run(FArray<BigDecimal> cashflow){
  57.                 return run( cashflow, new BigDecimal(0.1d) );
  58.         }
  59.         
  60.         private static BigDecimal run(FArray<BigDecimal> cashflow,BigDecimal guess){
  61.                 BigDecimal maxrate = initRateMax(cashflow,guess);
  62.                 BigDecimal minrate = initRateMin(cashflow,guess);
  63.                 for( int i=0; i<Init_Max_Loop; i++ ){
  64.                         BigDecimal testrate = minrate.add(maxrate).divide( new BigDecimal(2d) );
  65.                         BigDecimal npv = NPV( cashflow, testrate );
  66.                         if( npv.abs().compareTo(Accuracy) == LESS ){
  67.                                 guess = testrate;
  68.                                 break;
  69.                         }else if( npv.compareTo(ZERO) == LESS ){
  70.                                 minrate = testrate;
  71.                         }else{
  72.                                 maxrate = testrate;
  73.                         }
  74.                 }
  75.                 //保留16位小数(足够精度)
  76.                 return guess.setScale(16,BigDecimal.ROUND_HALF_UP);
  77.         }
  78.         
  79.         //最小精度
  80.         private static final BigDecimal Accuracy = new BigDecimal(0.00000001d);
  81.         //最大循环次数,excel用的是20次,不过精度只到小数点后两位,而且不一定一定能算出值,为了尽可能保证算出结果,我增加到100次,
  82.         private static final int Init_Max_Loop = 100;
  83.         
  84.         private static final BigDecimal ZERO = new BigDecimal(0);
  85.         private static final BigDecimal ONE = new BigDecimal(1);
  86.         private static final BigDecimal Z005 = new BigDecimal(0.005d);
  87.         private static final BigDecimal Z2 = new BigDecimal(0.2d);
  88.         
  89.         private static final int GREATER = 1;
  90.         private static final int LESS = -1;
  91.         
  92.         /**
  93.          * 生成一个使NPV为负数的R作为内部收益率下限值
  94.          * @param cashflow
  95.          * @param guess
  96.          * @return
  97.          */
  98.         private static BigDecimal initRateMin(FArray<BigDecimal> cashflow,BigDecimal guess){
  99.                 for( int i=0; i<Init_Max_Loop; i++ ){
  100.                         BigDecimal npv = NPV( cashflow, guess );
  101.                         
  102.                         if( npv.compareTo(ZERO) == LESS ){
  103.                                 return guess;
  104.                         }
  105.                         BigDecimal step = guess.abs().multiply( Z2 );
  106.                         guess = guess.add( step.compareTo( Z005 ) == LESS ? Z005 : step );
  107.                 }
  108.                 return guess;
  109.         }
  110.         
  111.         /**
  112.          * 生成一个使NPV为正数的R作为内部收益率的上限制
  113.          * @param cashflow
  114.          * @param guess
  115.          * @return
  116.          */
  117.         private static BigDecimal initRateMax(FArray<BigDecimal> cashflow,BigDecimal guess){
  118.                 for( int i=0; i<Init_Max_Loop; i++ ){
  119.                         BigDecimal npv = NPV( cashflow, guess );
  120.                         
  121.                         if( npv.compareTo(ZERO) == GREATER ){
  122.                                 return guess;
  123.                         }
  124.                         BigDecimal step = guess.abs().multiply( Z2 );
  125.                         guess = guess.subtract( step.compareTo( Z005 ) == LESS ? Z005 : step );
  126.                 }
  127.                 return guess;
  128.         }
  129.         
  130.         /**
  131.          * 算NPV
  132.          * @param cashflow
  133.          * @param rate
  134.          * @return
  135.          */
  136.         private static BigDecimal NPV(FArray<BigDecimal> cashflow,BigDecimal rate){
  137.                 BigDecimal npv = ZERO;
  138.                 BigDecimal rpowj = ONE;//(1+r)^0
  139.                 BigDecimal radd1 = rate.add(ONE);//1+r
  140.                 for( int j=0; j<cashflow.length(); j++ ){
  141.                         BigDecimal valuej = cashflow.elementAt(j);
  142.                         npv = npv.add( valuej.divide( rpowj, 10, BigDecimal.ROUND_HALF_DOWN ) );// vj / (1+r)^j
  143.                         rpowj = rpowj.multiply(radd1); // (1+r)^j
  144.                         //npv += cashflow.elementAt(j) / Math.pow( 1+rate, j );
  145.                 }
  146.                 return npv;
  147.         }
  148.         
  149. }
复制代码



看代码吧~




如果要导出保留公式,自己实现导出前值处理的接口,不然FR导出的时候单元格不是D1:D13这种形式,而是D1,D2,D3...,D13这样导出来公式就识别不了了

有问题加Q:452020655或群:367705354

分享扩散:
参与人数 +1 F豆 +1 理由
xiaoxian + 1 赞一个!

查看全部评分

沙发
发表于 2017-6-2 10:22:21
师傅溜溜溜
板凳
发表于 2017-6-3 08:20:39
支持下,大师啊
地板
发表于 2017-6-3 14:50:59
大神辛苦了 6666
5楼
发表于 2018-10-4 10:03:25
这个在60个月的净现金流的时候界面好久都不出数咋办。。
6楼
发表于 2018-10-5 20:21:18
这个厉害了,有用
7楼
发表于 2018-12-21 13:29:19
这个点金手 牛逼
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

15回帖数 1关注人数 4070浏览人数
最后回复于:2018-12-21 13:29

返回顶部 返回列表