Tim Hesterberg
2012-Jun-06 22:53 UTC
[Rd] suggest that as.double( something double ) not make a copy
I've been playing with passing arguments to .C(), and found that replacing as.double(x) with if(is.double(x)) x else as.double(x) saves time and avoids one copy, in the case that x is already double. I suggest modifying as.double to avoid the extra copy and just return x, when x is already double. Similarly for as.integer, etc. [[alternative HTML version deleted]]
Simon Urbanek
2012-Jun-07 00:15 UTC
[Rd] suggest that as.double( something double ) not make a copy
On Jun 6, 2012, at 6:53 PM, Tim Hesterberg wrote:> I've been playing with passing arguments to .C(), and found that replacing > as.double(x) > with > if(is.double(x)) x else as.double(x) > saves time and avoids one copy, in the case that x is already double. >No, it doesn't:> x=rnorm(10) > tracemem(x)[1] "<0x100c59cb0>"> invisible(.C("foo",x))tracemem[0x100c59cb0 -> 0x100c59c30]: .C tracemem[0x100c59c30 -> 0x100ca4298]: .C> x=rnorm(10) > tracemem(x)[1] "<0x100ca41f0>"> invisible(.C("foo",as.double(x)))tracemem[0x100ca41f0 -> 0x102cdc980]: .C tracemem[0x102cdc980 -> 0x102cdca00]: .C or rather more easily:> x=rnorm(10) > tracemem(x)[1] "<0x102ae0ff0>"> as.double(x)[1] -0.1027767 0.4018732 -1.3412045 0.8153615 1.8245356 -0.2147280 [7] 1.1298404 1.1026897 -1.1340612 -0.2346464 as.double(x) is not stupid and doesn't copy if not needed. However, it is a very common mistake to forget about the fact that as.double() has to strip attributes, so if you pass a matrix, you are always forcing a copy:> x=matrix(0,2,2) > tracemem(x)[1] "<0x100b0f098>"> as.double(x)tracemem[0x100b0f098 -> 0x1008b52c8]: [1] 0 0 0 0 That is not the fault of as.double() but rather of the user since you don't really need to strip attributes when calling .C as it doesn't care. As usual, I can only say don't use .C() ... ;) Cheers, Simon> I suggest modifying as.double to avoid the extra copy and just > return x, when x is already double. Similarly for as.integer, etc.
Matthew Dowle
2012-Jun-07 01:12 UTC
[Rd] suggest that as.double( something double ) not make a copy
Tim Hesterberg <timhesterberg <at> gmail.com> writes:> I've been playing with passing arguments to .C(), and found that replacing > as.double(x) > with > if(is.double(x)) x else as.double(x) > saves time and avoids one copy, in the case that x is already double. > > I suggest modifying as.double to avoid the extra copy and just > return x, when x is already double. Similarly for as.integer, etc. >But as.double() already doesn't copy if its argument is already double. Unless, your double has attributes?>From coerce.c :if(TYPEOF(x) == type) { if(ATTRIB(x) == R_NilValue) return x; ans = NAMED(x) ? duplicate(x) : x; CLEAR_ATTRIB(ans); return ans; } quick test :> x=1 > .Internal(inspect(x))@0000000003E23620 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 1> .Internal(inspect(as.double(x))) # no copy@0000000003E23620 14 REALSXP g0c1 [NAM(2)] (len=1, tl=0) 1> x=c(foo=1) # give x some attributes, say names > xfoo 1> .Internal(inspect(x))@0000000003E234D0 14 REALSXP g0c1 [NAM(1),ATT] (len=1, tl=0) 1 ATTRIB: @0000000003D54910 02 LISTSXP g0c0 [] TAG: @0000000000380088 01 SYMSXP g0c0 [MARK,gp=0x4000] "names" @0000000003E234A0 16 STRSXP g0c1 [NAM(2)] (len=1, tl=0) @0000000003E23560 09 CHARSXP g0c1 [gp=0x21] "foo"> .Internal(inspect(as.double(x))) # strips attribs returning new obj@0000000003E233B0 14 REALSXP g0c1 [] (len=1, tl=0) 1> as.double(x)[1] 1>Attribute stripping is documented in ?as.double. Rather than as.double() on the R side, you could use coerceVector() on the C side, which might be easier to use via .Call than .C since it takes an SEXP. Looking at coerceVector in coerce.c its first line returns immediately if type is already the desired type, with no attribute stripping, so that seems like the way to go? If your double has no attributes then I'm barking up the wrong tree. Matthew