From 78cdd1164119d1878855d37672b8a22275cf0179 Mon Sep 17 00:00:00 2001
From: Lukas Stadler <lukas.stadler@oracle.com>
Date: Wed, 15 Nov 2017 15:51:23 +0100
Subject: [PATCH] Fix scientific formatting of very small numbers

---
 .../base/printer/DoubleVectorPrinter.java     | 24 +++++++++++--------
 .../truffle/r/test/ExpectedTestOutput.test    |  8 +++++++
 .../r/test/builtins/TestBuiltin_format.java   |  3 +++
 3 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
index b86ea1637e..1c3df1c59f 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java
@@ -214,7 +214,7 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
         return new DoubleVectorMetrics(w, d, e);
     }
 
-    private static final int DBL_DIG = 15;
+    @SuppressWarnings("unused") private static final int DBL_DIG = 15;
 
     private static final double[] tbl = {
                     1e-1,
@@ -282,13 +282,14 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
                 r = x;
             }
 
-            if (digits >= DBL_DIG + 1) {
-                // TODO:
-                // format_via_sprintf(r, pp.getDigits(), kpower, nsig);
-                roundingwidens = false;
-                // return;
-                throw new UnsupportedOperationException();
-            }
+            // we ignore this special case for the time being:
+            // if (digits >= DBL_DIG + 1) {
+            // // TODO:
+            // // format_via_sprintf(r, pp.getDigits(), kpower, nsig);
+            // roundingwidens = false;
+            // // return;
+            // throw new UnsupportedOperationException();
+            // }
 
             kp = (int) Math.floor(Math.log10(r)) - digits + 1; // r = |x|;
                                                                // 10^(kp + digits - 1) <= r
@@ -434,9 +435,12 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
                 if (x == 0) {
                     log10 = 0;
                 } else {
-                    if (x < 1e-300) {
+                    if (x < 1e-200) {
+                        // if we're close to the smallest double numbers, the loop that calculates
+                        // digits will produce errors
                         shifted = true;
                         x *= 1e100;
+                        assert Math.abs(Math.log10(x)) >= 100 : "should not shift into 2-digit exponents";
                     }
                     log10 = (int) Math.log10(x);
                     if (DECIMAL_WEIGHTS[log10 + DECIMAL_SHIFT] > x) {
@@ -553,7 +557,7 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect
 
     private static double appendDigit(double x, int digit, StringBuilder str) {
         int c = (int) (x / DECIMAL_WEIGHTS[digit + DECIMAL_SHIFT]);
-        assert c >= 0 && c <= 9;
+        assert c >= 0 && c <= 9 : c;
         str.append((char) ('0' + c));
         return x - DECIMAL_VALUES[digit + DECIMAL_SHIFT][c];
     }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 6a51fbf92d..f61ac6982f 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -26383,6 +26383,10 @@ Error in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L,  :
 #format(1.6011095, digits=7)
 [1] "1.601109"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_format.testFormat#
+#format(2147483647 / 1.7976931348623157E308, digits =15)
+[1] "1.19457743112785e-299"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_format.testFormat#
 #format(4.125e-04, digits=3)
 [1] "0.000412"
@@ -26424,6 +26428,10 @@ Error in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L,  :
 #format(c(9.99951, 13.1), digits=4)
 [1] "10.0" "13.1"
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_format.testFormat#
+#substr(format(2147483647 / 1.7976931348623157E308, digits =22), 1,16+1)
+[1] "1.194577431127851"
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_format.testformat1#Output.IgnoreErrorMessage#
 #argv <- list(structure(c(0, 72.7, 56.4, 72.7, 0, 63.3, 56.4, 63.3, 0), .Dim = c(3L, 3L), .Dimnames = list(c('Girth', 'Height', 'Volume'), c('Girth', 'Height', 'Volume'))), FALSE, 7L, 0L, NULL, 3L, TRUE, NA, "."); .Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]], argv[[7]], argv[[8]], argv[[9]], , argv[[9]]))
 Error in .Internal(format(argv[[1]], argv[[2]], argv[[3]], argv[[4]],  :
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java
index a05621fb9d..a4a0dc9e2b 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_format.java
@@ -309,5 +309,8 @@ public class TestBuiltin_format extends TestBase {
         assertEval("format(4.135e-04, digits=3)");
         assertEval("format(9.999999999995, digits=13); format(9.999999999995, digits=11)");
         assertEval("format(9.999999995, digits=10)");
+        assertEval("format(2147483647 / 1.7976931348623157E308, digits =15)");
+        // only the first 16 decimal digits (53 bits) contain useful information (+ decimal point)
+        assertEval("substr(format(2147483647 / 1.7976931348623157E308, digits =22), 1,16+1)");
     }
 }
-- 
GitLab