亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java POI FormulaEvaluator 給出意外的浮點值

Java POI FormulaEvaluator 給出意外的浮點值

桃花長相依 2024-01-28 16:11:35
這是《Java 哲學》一書中的示例(請記住 FancyToy 擴展了 Toy):Class<FancyToy> ftClass = FancyToy.class;Class<? super FancyToy> up = ftClass.getSuperclass(); //compilesClass<Toy> up = ftClass.getSuperclass(); //doesn't compile 在IDEA中嘗試了很多次,只是出現“不兼容類型”的消息。請給我一個提示,為什么我們不能僅使用泛型類型玩具?我正在使用 Java POI 庫讀取 Excel 文件,然后將其顯示在 HTML 表格中。Excel 文件非常簡單,只有 1 行 3 列:A1 單元格= 21.7 B1 單元格= 20.0 C1 單元格是一個公式單元格,其公式為 =(A1-B1)/B1,它具有自定義格式“百分比”,小數點后 0 位。Excel 將其值顯示為 9%。這是因為 1.7/20 在計算器上給出的結果是 0.085;當它轉換為“百分比”格式時,它會變成 8.5%,并且因為格式顯示包含 0 位小數,所以它會四舍五入到 9%,這就是 Excel 顯示的內容。都好。然而,POI 將該值顯示為 8%。我觀察到 1.7/20 的計算結果是 0.084999999。由于上面應用的百分比格式,它會轉換為 8.4999999%,并且由于小數點后 0 位,它會向下舍入為 8%。如何讓 POI 返還 9% 而不是 8%?這是代碼片段:String myFormat="0%";CreationHelper helper = wbWrapper.getWb().getCreationHelper();CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT,helper.createDataFormat().getFormat(myFormat));String val = dataFormatter.formatCellValue(cell, evaluator);這里 evaluator 是 org.apache.poi.ss.usermodel.FormulaEvaluator 的實例,dataFormatter 是 org.apache.poi.ss.usermodel.DataFormatter 的實例當我打印變量“val”時,它返回 8%,而不是 Excel 中顯示的值 (9%)。
查看完整描述

1 回答

?
茅侃侃

TA貢獻1842條經驗 獲得超21個贊

你的觀察是正確的。該問題的出現是因為一般的浮點問題??梢院唵蔚乇硎緸椋?/p>


...

System.out.println(1.7/20.0); //0.08499999999999999

System.out.println((21.7-20.0)/20.0); //0.08499999999999996

...

如您所見,雙精度值 1.7 除以雙精度值 20.0 得到 0.08499999999999999。這很好,因為使用 時該值將被視為 0.085 DecimalFormat。但更復雜的方程 (21.7-20.0)/20.0 結果為 0.08499999999999996。這顯然低于 0.085。


Excel嘗試通過浮點值的附加規則來解決這些問題。它始終僅使用浮點值的 15 位有效十進制數字。類似的事情也是如此Excel:


...

BigDecimal bd = new BigDecimal((21.7-20.0)/20.0);

System.out.println(bd.round(new MathContext(15)).doubleValue()); //0.085

...

apache poi's FormulaEvaluator和 it's 的DataFormatter行為都不像這Excel一點。這就是差異的原因。


人們可以擁有一個自己的,與/org/apache/poi/ss/usermodel/DataFormatter.javaMyDataFormatter的唯一區別是:


...

    private String getFormattedNumberString(Cell cell, ConditionalFormattingEvaluator cfEvaluator) {

        if (cell == null) {

            return null;

        }

        Format numberFormat = getFormat(cell, cfEvaluator);


        double d = cell.getNumericCellValue();

        java.math.BigDecimal bd = new java.math.BigDecimal(d);

        d = bd.round(new java.math.MathContext(15)).doubleValue();


        if (numberFormat == null) {

            return String.valueOf(d);

        }

        String formatted = numberFormat.format(Double.valueOf(d));

        return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation

    }

...

然后使用 thatMyDataFormatter而不是DataFormatter會更符合 的Excel行為。


例子:


import java.io.FileOutputStream;


import org.apache.poi.ss.usermodel.*;

import org.apache.poi.ss.util.*;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;


class CreateExcelEvaluateFormula {


 public static void main(String[] args) throws Exception {


  Workbook workbook  = new XSSFWorkbook();

  CreationHelper creationHelper = workbook.getCreationHelper();

  FormulaEvaluator formulaEvaluator = creationHelper.createFormulaEvaluator();


  Sheet sheet = workbook.createSheet();

  Row row = sheet.createRow(0);

  Cell cell = row.createCell(0); cell.setCellValue(21.7);

  cell = row.createCell(1); cell.setCellValue(20.0);


  cell = row.createCell(2); cell.setCellFormula("(A1-B1)/B1");

  formulaEvaluator.evaluateFormulaCell(cell); 

  double d = cell.getNumericCellValue();

System.out.println(d); //0.08499999999999996


  MyDataFormatter dataFormatter = new MyDataFormatter();


  String myFormat="0%";

  CellUtil.setCellStyleProperty(cell, CellUtil.DATA_FORMAT, creationHelper.createDataFormat().getFormat(myFormat));

  String val = dataFormatter.formatCellValue(cell, formulaEvaluator);

  System.out.println(val); //9%


  FileOutputStream out = new FileOutputStream("Excel.xlsx");

  workbook.write(out);

  out.close();

  workbook.close();


 }

}


查看完整回答
反對 回復 2024-01-28
  • 1 回答
  • 0 關注
  • 318 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號