I am using JRI and want to get a numeric value from R as primitive long into java. The class org.rosuda.REngine.REXP only provides the methods asDouble() and asInteger(). Both are not working as expected. It seems to be an overflow problem.
There are two unit tests: The first one uses the method asDouble(), the second one uses asString() (and could be expanded to use BigInteger.longValue()).
@Test
public final void testWithDouble() throws Exception {
REngine engine;
engine = REngine.engineForClass("org.rosuda.REngine.JRI.JRIEngine");
engine.parseAndEval("rm(list=ls(all=TRUE))");
engine.assign("a", new int[] { 100000 });
engine.parseAndEval("b <- a * a");
REXP exp = engine.parseAndEval("b", null, true);
double b = exp.asDouble();
System.out.println(b); // prints -2.147483648E9
Assert.assertEquals(1e10, b, 1.0);
}
@Test
public final void testWithBigInteger() throws Exception {
REngine engine;
engine = REngine.engineForClass("org.rosuda.REngine.JRI.JRIEngine");
engine.parseAndEval("rm(list=ls(all=TRUE))");
engine.assign("a", new int[] { 100000 });
engine.parseAndEval("b <- a * a");
REXP exp = engine.parseAndEval("options(scipen=99); toString(b)", null, true);
String b = exp.asString();
System.out.println(b); // prints "NA"
Assert.assertEquals("10000000000", b);
// Now, this can be used to create a BigInteger and then the method longValue() helps.
}
There is the following section in my pom.xml:
<dependency>
<groupId>com.github.lucarosellini.rJava</groupId>
<artifactId>JRIEngine</artifactId>
<version>0.9-7</version>
</dependency>
Can anybody help me getting the correct long value?
UPDATE 2016-03-17
I added a new version of REngine in pom.xml. For the artifacts JRIEngine and JRI I have not found a newer version than 0.9-7.
<dependency>
<groupId>org.rosuda.REngine</groupId>
<artifactId>REngine</artifactId>
<version>2.1.0</version>
</dependency>
The problems are the same.
Debugging of testWithDouble()
shows that the native method rniExpType(long)
returns INTSXP
and then the native method rniGetIntArray(long)
is called. I think, that this last call causes the overflow.
Your tests don't test anything close to what you're describing, long
is not involved at all. You're simply passing NA_integer_
from R to Java, because the addition overflows 32-bit integers with a warning in R. You can check for that using the isNA()
method. If you want to avoid overflows in arithmetic, use the numeric type in R.