提问
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,极速登录

内部收益率函数【IRR】

迈达斯之手 番薯互助团队 互助砖家
发表于 2017-6-2 09:58:12 | 显示全部楼层 |取消关注该作者的回复
本帖最后由 迈达斯之手 于 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. }
复制代码



看代码吧~
4.jpg

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

有问题加Q:452020655或群:367705354

评分

参与人数 1F豆 +1 收起 理由
xiaoxian + 1 赞一个!

查看全部评分

此帖共有 89 位番薯登录后查看
回复

使用道具 举报

星痕 社区微信达人番薯互助团队 文档共创团队 互助叫兽、助理编辑、VIP1
发表于 2017-6-2 10:22:21 | 显示全部楼层 |取消关注该作者的回复
师傅溜溜溜
  收起(1)
  • 传说哥 传说哥
    你怎么不为你师傅提名精华帖?
    2017-06-02 14:11 评论
  • 评论

回复 支持 反对

使用道具 举报

xiaoxian  初学乍练(Lv1)
发表于 2017-6-3 08:20:39 | 显示全部楼层 |取消关注该作者的回复
支持下,大师啊
  • 评论

回复 支持 反对

使用道具 举报

孤陌 社区微信达人番薯互助团队 互助叫兽
发表于 2017-6-3 14:50:59 | 显示全部楼层 |取消关注该作者的回复
大神辛苦了 6666
  • 评论

回复 支持 反对

使用道具 举报

YaphetS 帆软员工 初学乍练(Lv1)
发表于 2018-10-4 10:03:25 | 显示全部楼层 |取消关注该作者的回复
这个在60个月的净现金流的时候界面好久都不出数咋办。。
  收起(4)
  • 迈达斯之手 迈达斯之手 : 额~那估计是涉及太多次的运算了~尝试减少运算次数吧~或者降低精度(上面写1000次的地方,可以用excel那种20次的,可以大量提高计算速度)
    2018-10-08 15:36 评论
  • YaphetS YaphetS : 我把16改到2,然后100改到20也还是挺慢的,而且计算的结果值没办法填到数据库里面,需要做什么修改么?
    2018-10-08 15:41 评论
  • YaphetS YaphetS : 评论 迈达斯之手 :而且改完之后出的数也还是16位小数。。。
    2018-10-08 15:41 评论
  • 迈达斯之手 迈达斯之手 : 评论 YaphetS :配置公式的时候选择填报不要保留公式重新计算~
    2018-10-08 16:32 评论
  • 评论

回复 支持 反对

使用道具 举报

guandaxin1  初学乍练(Lv1)
发表于 2018-10-5 20:21:18 | 显示全部楼层 |取消关注该作者的回复
这个厉害了,有用
  • 评论

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册  

本版积分规则

what a fine day
任务进行中

联系管理员@兔子酱|联系帆软|免责声明|手机版|帆软社区|Copyright © 帆软软件有限公司 ( 苏ICP备14031611号-3 )

GMT+8, 2018-12-12 05:14 , Processed in 0.408047 second(s), 148 queries , Gzip On.

返回顶部 返回列表