]> source.dussan.org Git - poi.git/commitdiff
[bug-63842] FractionFormat casts whole part of the value into 'int'
authorPJ Fanning <fanningpj@apache.org>
Mon, 14 Oct 2019 08:19:15 +0000 (08:19 +0000)
committerPJ Fanning <fanningpj@apache.org>
Mon, 14 Oct 2019 08:19:15 +0000 (08:19 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1868425 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/ss/usermodel/FractionFormat.java
src/testcases/org/apache/poi/ss/usermodel/TestFractionFormat.java

index d90d50068b77250376fd40f3db4541f0b1f25fc2..3d95698134f922e45ae1ddb1be4f31572ae4accb 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 package org.apache.poi.ss.usermodel;
+
+import java.math.BigDecimal;
 import java.text.FieldPosition;
 import java.text.Format;
 import java.text.ParsePosition;
@@ -99,14 +101,15 @@ public class FractionFormat extends Format {
 
     public String format(Number num) {
 
-        final double doubleValue = num.doubleValue();
-        
-        final boolean isNeg = (doubleValue < 0.0f) ? true : false;
-        final double absDoubleValue = Math.abs(doubleValue);
+        final BigDecimal doubleValue = new BigDecimal(num.doubleValue());
         
-        final double wholePart = Math.floor(absDoubleValue);
-        final double decPart = absDoubleValue - wholePart;
-        if (wholePart + decPart == 0) {
+        final boolean isNeg = doubleValue.compareTo(BigDecimal.ZERO) < 0;
+
+        final BigDecimal absValue = doubleValue.abs();
+        final BigDecimal wholePart = new BigDecimal(absValue.toBigInteger());
+        final BigDecimal decPart = absValue.remainder(BigDecimal.ONE);
+
+        if (wholePart.add(decPart).compareTo(BigDecimal.ZERO) == 0) {
             return "0";
         }
         
@@ -119,13 +122,13 @@ public class FractionFormat extends Format {
         // }
         
         //this is necessary to prevent overflow in the maxDenom calculation
-        if (Double.compare(decPart, 0) == 0){
+        if (decPart.compareTo(BigDecimal.ZERO) == 0){
             
             StringBuilder sb = new StringBuilder();
             if (isNeg){
                 sb.append("-");
             }
-            sb.append((int)wholePart);
+            sb.append(wholePart);
             return sb.toString();
         }
         
@@ -133,13 +136,13 @@ public class FractionFormat extends Format {
         try{
             //this should be the case because of the constructor
             if (exactDenom > 0){
-                fract = SimpleFraction.buildFractionExactDenominator(decPart, exactDenom);
+                fract = SimpleFraction.buildFractionExactDenominator(decPart.doubleValue(), exactDenom);
             } else {
-                fract = SimpleFraction.buildFractionMaxDenominator(decPart, maxDenom);
+                fract = SimpleFraction.buildFractionMaxDenominator(decPart.doubleValue(), maxDenom);
             }
         } catch (RuntimeException e){
             LOGGER.log(POILogger.WARN, "Can't format fraction", e);
-            return Double.toString(doubleValue);
+            return Double.toString(doubleValue.doubleValue());
         }
 
         StringBuilder sb = new StringBuilder();
@@ -151,23 +154,25 @@ public class FractionFormat extends Format {
         
         //if whole part has to go into the numerator
         if (wholePartFormatString == null || wholePartFormatString.isEmpty()){
-            int trueNum = (fract.getDenominator()*(int)wholePart)+fract.getNumerator();
-            sb.append(trueNum).append("/").append(fract.getDenominator());
+            final int fden = fract.getDenominator();
+            final int fnum = fract.getNumerator();
+            BigDecimal trueNum = wholePart.multiply(new BigDecimal(fden)).add(new BigDecimal(fnum));
+            sb.append(trueNum.toBigInteger()).append("/").append(fden);
             return sb.toString();
         }
         
         
         //short circuit if fraction is 0 or 1
         if (fract.getNumerator() == 0){
-            sb.append(Integer.toString((int)wholePart));
+            sb.append(wholePart);
             return sb.toString();
         } else if (fract.getNumerator() == fract.getDenominator()){
-            sb.append(Integer.toString((int)wholePart+1));
+            sb.append(wholePart.add(BigDecimal.ONE));
             return sb.toString();
         }
        //as mentioned above, this ignores the exact space formatting in Excel
-        if (wholePart > 0){
-            sb.append(Integer.toString((int)wholePart)).append(" ");
+        if (wholePart.compareTo(BigDecimal.ZERO) > 0){
+            sb.append(wholePart).append(" ");
         }
         sb.append(fract.getNumerator()).append("/").append(fract.getDenominator());
         return sb.toString();
index e99c3fe698fecb57f85cefd82688625335398db2..dd08f6d7992fbbbf9a2f4f91484c73671fb9e817 100644 (file)
@@ -41,6 +41,22 @@ public final class TestFractionFormat {
         String ret = f.format(val);
         assertEquals("26027/81", ret);
     }
+    
+    @Test
+    public void testWithBigWholePart() throws Exception {
+        FractionFormat f = new FractionFormat("#", "???/???");
+        
+        assertEquals("10100136259702", f.format(10100136259702d));
+        assertEquals("-10100136259702", f.format(-10100136259702d));
+        
+        // Excel displays fraction: 51/512
+        assertEquals("10100136259702 10/100", f.format(10100136259702.1d));
+        assertEquals("-10100136259702 10/100", f.format(-10100136259702.1d));
+        
+        // Excel displays fraction: 461/512
+        assertEquals("10100136259702 90/100", f.format(10100136259702.9d));
+        assertEquals("-10100136259702 90/100", f.format(-10100136259702.9d));
+    }
      
     @Test
     public void testTruthFile() throws Exception {