From 2b20964e2ace3d95b99b3d55c81c1f7a51851940 Mon Sep 17 00:00:00 2001 From: Zbynek Slajchrt <zbynek.slajchrt@oracle.com> Date: Thu, 6 Oct 2016 17:12:02 +0200 Subject: [PATCH] Complex and double numbers can be converted to String via static methods in Complex/DoubleVectorPrinter --- .../base/printer/ComplexVectorPrinter.java | 63 ++++++++++++------- .../base/printer/DoubleVectorPrinter.java | 60 +++++++++++++----- .../printer/ComplexVectorPrinterTest.java | 38 +++++++++++ .../base/printer/DoubleVectorPrinterTest.java | 36 +++++++++++ 4 files changed, 159 insertions(+), 38 deletions(-) create mode 100644 com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java create mode 100644 com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java index 56d6c09685..14a5015037 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java @@ -26,7 +26,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; //Transcribed from GnuR, src/main/printutils.c -final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { +public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { static final ComplexVectorPrinter INSTANCE = new ComplexVectorPrinter(); @@ -74,6 +74,10 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { } static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, PrintParameters pp) { + return formatComplexVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth()); + } + + static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) { int wr; int dr; @@ -129,7 +133,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { } else { /* real part */ - tmp = zprecr(xi, pp.getDigits()); + tmp = zprecr(xi, digits); if (!RRuntime.isFinite(tmp.getRealPart())) { if (RRuntime.isNAorNaN(tmp.getRealPart())) { @@ -143,7 +147,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { if (xi.getRealPart() != 0) { allReZero = false; } - ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), pp); + ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), digits); left = sd.kpower + 1; if (sd.roundingwidens) { @@ -187,7 +191,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { if (xi.getImaginaryPart() != 0) { allImZero = false; } - ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), pp); + ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), digits); left = sd.kpower + 1; if (sd.roundingwidens) { @@ -221,7 +225,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { /* overall format for real part */ - if (pp.getDigits() == 0) { + if (digits == 0) { rt = 0; } if (mxl != RRuntime.INT_MIN_VALUE) { @@ -245,7 +249,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { /* overall format for imaginary part */ - if (pp.getDigits() == 0) { + if (digits == 0) { irt = 0; } if (imxl != RRuntime.INT_MIN_VALUE) { @@ -271,7 +275,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { if (allReZero) { er = dr = 0; wr = wF; - if (iwF <= wi + pp.getScipen()) { + if (iwF <= wi + sciPen) { ei = 0; if (nsmall > irt) { irt = nsmall; @@ -281,7 +285,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { wi = iwF; } } else if (allImZero) { - if (wF <= wr + pp.getScipen()) { + if (wF <= wr + sciPen) { er = 0; if (nsmall > rt) { rt = nsmall; @@ -292,7 +296,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { } ei = di = 0; wi = iwF; - } else if (wF + iwF < wr + wi + 2 * pp.getScipen()) { + } else if (wF + iwF < wr + wi + 2 * sciPen) { er = 0; if (nsmall > rt) { rt = nsmall; @@ -335,8 +339,8 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { /* finally, ensure that there is space for NA */ - if (naflag && wr + wi + 2 < pp.getNaWidth()) { - wr += (pp.getNaWidth() - (wr + wi + 2)); + if (naflag && wr + wi + 2 < naWidth) { + wr += (naWidth - (wr + wi + 2)); } return new ComplexVectorMetrics(wr, dr, er, wi, di, ei); @@ -383,12 +387,29 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { } } - @TruffleBoundary + public static String encodeComplex(RComplex x) { + return encodeComplex(x, 15, 0, RRuntime.STRING_NA); + } + + public static String encodeComplex(RComplex x, int digits) { + return encodeComplex(x, digits, 0, RRuntime.STRING_NA); + } + + public static String encodeComplex(RComplex x, int digits, int sciPen, String naString) { + ComplexVectorMetrics cvm = formatComplexVector(x, 0, 1, 0, digits, sciPen, naString.length()); + return encodeComplex(x, cvm, digits, naString); + } + static String encodeComplex(RComplex x, ComplexVectorMetrics cvm, PrintParameters pp) { + return encodeComplex(x, cvm, pp.getDigits(), pp.getNaString()); + } + + @TruffleBoundary + static String encodeComplex(RComplex x, ComplexVectorMetrics cvm, int digits, String naString) { if (RRuntime.isNA(x.getRealPart()) || RRuntime.isNA(x.getImaginaryPart())) { - return DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, cvm.maxWidth, 0, 0, '.', pp); + return DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, cvm.maxWidth, 0, 0, '.', naString); } else { - String s = encodeComplex(x, cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei, '.', pp); + String s = encodeComplex(x, cvm.wr, cvm.dr, cvm.er, cvm.wi, cvm.di, cvm.ei, '.', digits, naString); int g = cvm.maxWidth - cvm.wr - cvm.wi - 2; if (g > 0) { // fill the remaining space by blanks to fit the maxWidth @@ -399,7 +420,7 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { } } - private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, PrintParameters pp) { + private static String encodeComplex(RComplex x, int wr, int dr, int er, int wi, int di, int ei, char cdec, int digits, String naString) { String buff; String im; String re; @@ -422,27 +443,27 @@ final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVector> { String fmt = "%" + Utils.asBlankArg(g) + "s"; buff = Utils.snprintf(NB, fmt, /* was "%*s%*s", R_print.gap, "", */ - pp.getNaString()); + naString); } else { /* * formatComplex rounded, but this does not, and we need to keep it that way so we don't * get strange trailing zeros. But we do want to avoid printing small exponentials that * are probably garbage. */ - y = zprecr(x, pp.getDigits()); + y = zprecr(x, digits); if (y.getRealPart() == 0.) { - re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, pp); + re = DoubleVectorPrinter.encodeReal(y.getRealPart(), wr, dr, er, cdec, naString); } else { - re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, pp); + re = DoubleVectorPrinter.encodeReal(xr, wr, dr, er, cdec, naString); } flagNegIm = xi < 0; if (flagNegIm) { xi = -xi; } if (y.getImaginaryPart() == 0.) { - im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, pp); + im = DoubleVectorPrinter.encodeReal(y.getImaginaryPart(), wi, di, ei, cdec, naString); } else { - im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, pp); + im = DoubleVectorPrinter.encodeReal(xi, wi, di, ei, cdec, naString); } buff = snprintf(NB, "%s%s%si", re, flagNegIm ? "-" : "+", im); } 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 9acc68d1a2..d01049d173 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 @@ -19,11 +19,12 @@ import java.text.DecimalFormat; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; //Transcribed from GnuR, src/main/format.c -final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { +public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { static final DoubleVectorPrinter INSTANCE = new DoubleVectorPrinter(); @@ -71,6 +72,10 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { } static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, PrintParameters pp) { + return formatDoubleVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth()); + } + + static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) { int left; int right; int sleft; @@ -116,7 +121,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { neginf = true; } } else { - ScientificDouble sd = scientific(xi, pp); + ScientificDouble sd = scientific(xi, digits); sgn = sd.sgn; nsig = sd.nsig; kpower = sd.kpower; @@ -167,7 +172,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { /*-- These 'mxsl' & 'rgt' are used in F Format * AND in the ____ if(.) "F" else "E" ___ below: */ - if (pp.getDigits() == 0) { + if (digits == 0) { rgt = 0; } if (mxl < 0) { @@ -185,7 +190,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { if (mxns != RRuntime.INT_MIN_VALUE) { d = mxns - 1; w = neg + (d != 0 ? 1 : 1) + d + 4 + e; /* width for E format */ - if (wF <= w + pp.getScipen()) { /* Fixpoint if it needs less space */ + if (wF <= w + sciPen) { /* Fixpoint if it needs less space */ e = 0; if (nsmall > rgt) { rgt = nsmall; @@ -199,8 +204,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { d = 0; e = 0; } - if (naflag && w < pp.getNaWidth()) { - w = pp.getNaWidth(); + if (naflag && w < naWidth) { + w = naWidth; } if (nanflag && w < 3) { w = 3; @@ -244,6 +249,10 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { } public static ScientificDouble scientific(double x, PrintParameters pp) { + return scientific(x, pp.getDigits()); + } + + public static ScientificDouble scientific(double x, int digits) { /* * for a number x , determine sgn = 1_{x < 0} {0/1} kpower = Exponent of 10; nsig = * min(R_print.digits, #{significant digits of alpha}) roundingwidens = 1 if rounding causes @@ -277,7 +286,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { r = x; } - if (pp.getDigits() >= DBL_DIG + 1) { + if (digits >= DBL_DIG + 1) { // TODO: // format_via_sprintf(r, pp.getDigits(), kpower, nsig); roundingwidens = false; @@ -285,8 +294,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { throw new UnsupportedOperationException(); } - kp = (int) Math.floor(Math.log10(r)) - pp.getDigits() + 1; // r = |x|; - // 10^(kp + digits - 1) <= r + kp = (int) Math.floor(Math.log10(r)) - digits + 1; // r = |x|; + // 10^(kp + digits - 1) <= r double rPrec = r; /* use exact scaling factor in double precision, if possible */ @@ -307,7 +316,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { } else { rPrec /= Math.pow(10, kp); } - if (rPrec < tbl[pp.getDigits()]) { + if (rPrec < tbl[digits]) { rPrec *= 10.0; kp--; } @@ -317,8 +326,8 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { */ alpha = Math.round(rPrec); - nsig = pp.getDigits(); - for (j = 1; j <= pp.getDigits(); j++) { + nsig = digits; + for (j = 1; j <= digits; j++) { alpha /= 10.0; if (alpha == Math.floor(alpha)) { nsig--; @@ -326,11 +335,11 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { break; } } - if (nsig == 0 && pp.getDigits() > 0) { + if (nsig == 0 && digits > 0) { nsig = 1; kp += 1; } - kpower = kp + pp.getDigits() - 1; + kpower = kp + digits - 1; /* * Scientific format may do more rounding than fixed format, e.g. 9996 with 3 digits is @@ -339,7 +348,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { * decimal place that will be cut off by rounding */ - int rgt = pp.getDigits() - kpower; + int rgt = digits - kpower; /* bound rgt by 0 and KP_MAX */ rgt = rgt < 0 ? 0 : rgt > KP_MAX ? KP_MAX : rgt; double fuzz = 0.5 / tbl[1 + rgt]; @@ -351,12 +360,29 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { return new ScientificDouble(sgn, kpower, nsig, roundingwidens); } + public static String encodeReal(double x) { + return encodeReal(x, 15, '.', 0, RRuntime.STRING_NA); + } + + public static String encodeReal(double x, int digits) { + return encodeReal(x, digits, '.', 0, RRuntime.STRING_NA); + } + + public static String encodeReal(double x, int digits, char cdec, int sciPen, String naString) { + DoubleVectorMetrics dm = formatDoubleVector(RDataFactory.createDoubleVectorFromScalar(x), 0, 1, 0, digits, sciPen, naString.length()); + return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString); + } + + static String encodeReal(double initialX, int w, int d, int e, char cdec, PrintParameters pp) { + return encodeReal(initialX, w, d, e, cdec, pp.getNaString()); + } + static String encodeReal(double x, DoubleVectorMetrics dm, PrintParameters pp) { return encodeReal(x, dm.maxWidth, dm.d, dm.e, '.', pp); } @TruffleBoundary - static String encodeReal(double initialX, int w, int d, int e, char cdec, PrintParameters pp) { + static String encodeReal(double initialX, int w, int d, int e, char cdec, String naString) { final String buff; String fmt; @@ -367,7 +393,7 @@ final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVector> { int numBlanks = Math.min(w, (NB - 1)); String naFmt = "%" + Utils.asBlankArg(numBlanks) + "s"; if (RRuntime.isNA(x)) { - buff = snprintf(NB, naFmt, pp.getNaString()); + buff = snprintf(NB, naFmt, naString); } else if (RRuntime.isNAorNaN(x)) { buff = snprintf(NB, naFmt, "NaN"); } else if (x > 0) { diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java new file mode 100644 index 0000000000..f95c7b59a4 --- /dev/null +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinterTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import org.junit.Test; + +import com.oracle.truffle.r.runtime.data.RDataFactory; + +import static org.junit.Assert.*; + +public class ComplexVectorPrinterTest { + + @Test + public void testEncodeComplex() { + assertEquals("3.14159265358979e-05+3.1415926535898e-06i", ComplexVectorPrinter.encodeComplex(RDataFactory.createComplex(Math.PI / 100000, Math.PI / 1000000))); + } + +} diff --git a/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java new file mode 100644 index 0000000000..4dcf54e8d8 --- /dev/null +++ b/com.oracle.truffle.r.nodes.test/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinterTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base.printer; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DoubleVectorPrinterTest { + + @Test + public void testEncodeReal() { + assertEquals("3.14159265358979e-06", DoubleVectorPrinter.encodeReal(Math.PI / 1000000)); + } + +} -- GitLab