【问题标题】:Apache POI rate formula not working if data is big如果数据很大,Apache POI 率公式不起作用
【发布时间】:2017-11-09 04:53:47
【问题描述】:

对于大值,费率公式无法按预期工作......

  1. RATE(85.77534246575343, -1589.0, -18664.0, 5855586.0) 在物理文件中返回 0.05819488005

  2. 如果我们尝试通过 POI 设置的相同公式返回 0.009056339275922086..

    1. 即使我们尝试保存 excel 并打开相同的 0.009056339275922086 也会返回..

用于在 POI 中设置的代码:

XSSFWorkbook workbook = new XSSFWorkbook(); 
XSSFRow  row = sheet.createRow(1);
XSSFCell  cell = row.createCell(1);
cell.setCellType(CellType.NUMERIC);
cell.setCellFormula("RATE(85.77534246575343, -1589.0, -18664.0, 5855586.0)");
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
evaluator.evaluateInCell(cell);
cell.getNumericCellValue();

【问题讨论】:

    标签: function apache-poi rate


    【解决方案1】:

    apache poiRate 函数声明它“// 通过牛顿正割法求根”。这是无稽之谈,因为Secant method 只是一种准牛顿方法。还有“If the initial values are not close enough to the root, then there is no guarantee that the secant method converges.”。

    所以0.1 的默认guess 似乎不够“接近”,所以如果我们使用cell.setCellFormula("RATE(85.77534246575343, -1589.0, -18664.0, 5855586.0, 0, 0.06)"); - 请注意typeguess 属性的显式设置并具有guess 属性“足够接近”到0.05819488005- 的结果,然后公式计算正确。

    如果apache poi 真的会使用Newton's method,那么该函数也会使用0.1 的默认guess 正确评估。牛顿方法的缺点是它需要在每一步都评估f 及其导数f′。所以在某些情况下它可能比割线法慢。

    例子:

    import java.io.FileOutputStream;
    
    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    
    public class ExcelRATEFunction {
    
     private static double calculateRateNewton(double nper, double pmt, double pv, double fv, double type, double guess) {
    
      int FINANCIAL_MAX_ITERATIONS = 20;
      double FINANCIAL_PRECISION = 0.0000001;
    
      double y, y1, xN = 0, f = 0, i = 0;
    
      double rate = guess;
    
      //find root by Newtons method (https://en.wikipedia.org/wiki/Newton%27s_method), not secant method!
      //Formula see: https://wiki.openoffice.org/wiki/Documentation/How_Tos/Calc:_Derivation_of_Financial_Formulas#PV.2C_FV.2C_PMT.2C_NPER.2C_RATE
    
      f = Math.pow(1 + rate, nper);
      y = pv * f + pmt * ((f - 1) / rate) * (1 + rate * type) + fv;
    
      //first derivative:
      //y1 = (pmt * nper * type * Math.pow(rate,2) * f - pmt * f - pmt * rate * f + pmt * nper * rate * f + pmt * rate + pmt + nper * pv * Math.pow(rate,2) * f) / (Math.pow(rate,2) * (rate+1));
      y1 = (f * ((pmt * nper * type + nper * pv) * Math.pow(rate,2) + (pmt * nper - pmt) * rate - pmt) + pmt * rate + pmt) / (Math.pow(rate,3) + Math.pow(rate,2));
    
      xN = rate - y/y1;
    
      while ((Math.abs(rate - xN) > FINANCIAL_PRECISION) && (i < FINANCIAL_MAX_ITERATIONS)) {
    
       rate = xN;
    
       f = Math.pow(1 + rate, nper);
       y = pv * f + pmt * ((f - 1) / rate) * (1 + rate * type) + fv;
    
       //first derivative:
       //y1 = (pmt * nper * type * Math.pow(rate,2) * f - pmt * f - pmt * rate * f + pmt * nper * rate * f + pmt * rate + pmt + nper * pv * Math.pow(rate,2) * f) / (Math.pow(rate,2) * (rate+1));
       y1 = (f * ((pmt * nper * type + nper * pv) * Math.pow(rate,2) + (pmt * nper - pmt) * rate - pmt) + pmt * rate + pmt) / (Math.pow(rate,3) + Math.pow(rate,2));
    
       xN = rate - y/y1;
       ++i;
    
       System.out.println(rate+", "+xN+", "+y+", "+y1);
      }
    
      rate = xN;    
      return rate;
    
     }
    
     public static void main(String[] args) throws Exception {
    
      Workbook workbook = new XSSFWorkbook();
      Sheet sheet = workbook.createSheet();
      Row  row = sheet.createRow(1);
      Cell  cell = row.createCell(1);
    
      cell.setCellFormula("RATE(85.77534246575343, -1589.0, -18664.0, 5855586.0, 0, 0.06)");
      FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
      CellType celltype = evaluator.evaluateFormulaCellEnum(cell);
    
      double value = 0.0;
      if (celltype == CellType.NUMERIC) {
       value = cell.getNumericCellValue();
       System.out.println(value);
      }
    
      workbook.setForceFormulaRecalculation(true);
    
      value = calculateRateNewton(85.77534246575343, -1589.0, -18664.0, 5855586.0, 0, 0.1);
      System.out.println(value);
    
      workbook.write(new FileOutputStream("ExcelRATEFunction.xlsx"));
      workbook.close();
    
     }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多