From acd3101b82a31261db190983b90160d4a631ac77 Mon Sep 17 00:00:00 2001 From: Yegor Kozlov Date: Sat, 4 Sep 2010 12:33:09 +0000 Subject: [PATCH] change cell type to error when setting Double.NaN or Infinities, see Bugzilla 49761 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@992591 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../apache/poi/hssf/usermodel/HSSFCell.java | 41 ++++++++------ .../apache/poi/xssf/usermodel/XSSFCell.java | 9 ++- .../poi/hssf/usermodel/TestHSSFCell.java | 2 + .../apache/poi/ss/usermodel/BaseTestCell.java | 55 +++++++++++++++++++ 5 files changed, 90 insertions(+), 18 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index ecd28631b..a4ffb0468 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 49761 - change cell type to error when setting Double.NaN or Infinities 49833 - ensure that CTNumPr is included in poi-ooxml-schemas.jar 49841 - fixed LEFT and RIGHT to return #VALUE! when called with a negative operand 49783 - fixed evaluation of XSSF workbooks containing formulas with reference errors (#REF!) diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java index 35d09c6b6..2862a0d03 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java @@ -46,11 +46,7 @@ import org.apache.poi.hssf.record.common.UnicodeString; import org.apache.poi.hssf.record.formula.ExpPtg; import org.apache.poi.hssf.record.formula.Ptg; import org.apache.poi.hssf.record.formula.eval.ErrorEval; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.Hyperlink; -import org.apache.poi.ss.usermodel.RichTextString; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.NumberToTextConverter; @@ -464,20 +460,31 @@ public class HSSFCell implements Cell { * will change the cell to a numeric cell and set its value. */ public void setCellValue(double value) { - int row=_record.getRow(); - short col=_record.getColumn(); - short styleIndex=_record.getXFIndex(); + if(Double.isInfinite(value)) { + // Excel does not support positive/negative infinities, + // rather, it gives a #DIV/0! error in these cases. + setCellErrorValue(FormulaError.DIV0.getCode()); + } else if (Double.isNaN(value)){ + // Excel does not support Not-a-Number (NaN), + // instead it immediately generates a #NUM! error. + setCellErrorValue(FormulaError.NUM.getCode()); + } else { + int row=_record.getRow(); + short col=_record.getColumn(); + short styleIndex=_record.getXFIndex(); - switch (_cellType) { - default: - setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex); - case CELL_TYPE_NUMERIC: - (( NumberRecord ) _record).setValue(value); - break; - case CELL_TYPE_FORMULA: - ((FormulaRecordAggregate)_record).setCachedDoubleResult(value); - break; + switch (_cellType) { + default: + setCellType(CELL_TYPE_NUMERIC, false, row, col, styleIndex); + case CELL_TYPE_NUMERIC: + (( NumberRecord ) _record).setValue(value); + break; + case CELL_TYPE_FORMULA: + ((FormulaRecordAggregate)_record).setCachedDoubleResult(value); + break; + } } + } /** diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java index 374c6b00d..cee581daf 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java @@ -218,7 +218,14 @@ public final class XSSFCell implements Cell { * will change the cell to a numeric cell and set its value. */ public void setCellValue(double value) { - if(Double.isInfinite(value) || Double.isNaN(value)) { + if(Double.isInfinite(value)) { + // Excel does not support positive/negative infinities, + // rather, it gives a #DIV/0! error in these cases. + _cell.setT(STCellType.E); + _cell.setV(FormulaError.DIV0.getString()); + } else if (Double.isNaN(value)){ + // Excel does not support Not-a-Number (NaN), + // instead it immediately generates an #NUM! error. _cell.setT(STCellType.E); _cell.setV(FormulaError.NUM.getString()); } else { diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java index 77e95c622..76f53c9c3 100644 --- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java +++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFCell.java @@ -320,4 +320,6 @@ public final class TestHSSFCell extends BaseTestCell { assertEquals("The maximum length of cell contents (text) is 32,767 characters", e.getMessage()); } } + + } diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java index 39d21dd85..dbbad380d 100644 --- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java +++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestCell.java @@ -489,4 +489,59 @@ public abstract class BaseTestCell extends TestCase { int i2 = cell.getCellStyle().getIndex(); assertEquals(i1, i2); } + + /** + * Excel's implementation of floating number arithmetic does not fully adhere to IEEE 754: + * + * From http://support.microsoft.com/kb/78113: + * + *
    + *
  • Positive/Negative Infinities: + * Infinities occur when you divide by 0. Excel does not support infinities, rather, + * it gives a #DIV/0! error in these cases. + *
  • + *
  • + * Not-a-Number (NaN): + * NaN is used to represent invalid operations (such as infinity/infinity, + * infinity-infinity, or the square root of -1). NaNs allow a program to + * continue past an invalid operation. Excel instead immediately generates + * an error such as #NUM! or #DIV/0!. + *
  • + *
+ */ + public void testNanAndInfinity() { + Workbook wb = _testDataProvider.createWorkbook(); + Sheet workSheet = wb.createSheet("Sheet1"); + Row row = workSheet.createRow(0); + + Cell cell0 = row.createCell(0); + cell0.setCellValue(Double.NaN); + assertEquals("Double.NaN should change cell type to CELL_TYPE_ERROR", Cell.CELL_TYPE_ERROR, cell0.getCellType()); + assertEquals("Double.NaN should change cell value to #NUM!", ErrorConstants.ERROR_NUM, cell0.getErrorCellValue()); + + Cell cell1 = row.createCell(1); + cell1.setCellValue(Double.POSITIVE_INFINITY); + assertEquals("Double.POSITIVE_INFINITY should change cell type to CELL_TYPE_ERROR", Cell.CELL_TYPE_ERROR, cell1.getCellType()); + assertEquals("Double.POSITIVE_INFINITY should change cell value to #DIV/0!", ErrorConstants.ERROR_DIV_0, cell1.getErrorCellValue()); + + Cell cell2 = row.createCell(2); + cell2.setCellValue(Double.NEGATIVE_INFINITY); + assertEquals("Double.NEGATIVE_INFINITY should change cell type to CELL_TYPE_ERROR", Cell.CELL_TYPE_ERROR, cell2.getCellType()); + assertEquals("Double.NEGATIVE_INFINITY should change cell value to #DIV/0!", ErrorConstants.ERROR_DIV_0, cell2.getErrorCellValue()); + + wb = _testDataProvider.writeOutAndReadBack(wb); + row = wb.getSheetAt(0).getRow(0); + + cell0 = row.getCell(0); + assertEquals(Cell.CELL_TYPE_ERROR, cell0.getCellType()); + assertEquals(ErrorConstants.ERROR_NUM, cell0.getErrorCellValue()); + + cell1 = row.getCell(1); + assertEquals(Cell.CELL_TYPE_ERROR, cell1.getCellType()); + assertEquals(ErrorConstants.ERROR_DIV_0, cell1.getErrorCellValue()); + + cell2 = row.getCell(2); + assertEquals(Cell.CELL_TYPE_ERROR, cell2.getCellType()); + assertEquals(ErrorConstants.ERROR_DIV_0, cell2.getErrorCellValue()); + } }