rrcppnabit64

Rcpp and int64 NA value


How can I pass an NA value from Rcpp to R in a 64 bit vector?

My first approach would be:

// [[Rcpp::export]]                                     
Rcpp::NumericVector foo() {
  Rcpp::NumericVector res(2);

  int64_t val = 1234567890123456789;
  std::memcpy(&(res[0]), &(val), sizeof(double));
  res[1] = NA_REAL;

  res.attr("class") = "integer64";
  return res;
}

But it yields

#> foo()
integer64
[1] 1234567890123456789 9218868437227407266

I need to get

#> foo()
integer64
[1] 1234567890123456789 <NA>

Solution

  • Alright, I think I found an answer... (not beautiful, but working).

    Short Answer:

    // [[Rcpp::export]]                                     
    Rcpp::NumericVector foo() {
      Rcpp::NumericVector res(2);
    
      int64_t val = 1234567890123456789;
      std::memcpy(&(res[0]), &(val), sizeof(double));
    
      # This is the magic:
      int64_t v = 1ULL << 63;
      std::memcpy(&(res[1]), &(v), sizeof(double));
    
      res.attr("class") = "integer64";
      return res;
    }
    

    which results in

    #> foo()
    integer64
    [1] 1234567890123456789 <NA>
    

    Longer Answer

    Inspecting how bit64 stores an NA

    # the last value is the max value of a 64 bit number
    a <- bit64::as.integer64(c(1, 2, NA, 9223372036854775807))
    a
    #> integer64
    #> [1] 1    2    <NA> <NA>
    bit64::as.bitstring(a[3])
    #> [1] "1000000000000000000000000000000000000000000000000000000000000000"
    bit64::as.bitstring(a[4])
    #> [1] "1000000000000000000000000000000000000000000000000000000000000000"
    

    Created on 2020-04-23 by the reprex package (v0.3.0)

    we see that it is a 10000.... This can be recreated in Rcpp with int64_t val = 1ULL << 63;. Using memcpy() instead of a simple assign with = ensures that no bits are changed!