Rcpp y valor NA int64


8

¿Cómo puedo pasar un valor de NA de Rcpp a R en un vector de 64 bits?

Mi primer enfoque sería:

// [[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;
}

Pero rinde

#> foo()
integer64
[1] 1234567890123456789 9218868437227407266

Necesito conseguir

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

No se puede usar NA_REALdespués de memcpyporque el patrón de bits es en ese punto el de a int64.
Dirk Eddelbuettel

También editaría el título. El valor predeterminado de NA de 64 bits no es de lo NA_realque se trata su pregunta.
Dirk Eddelbuettel

Pero la memoria copia solo 64 bits ( sizeof(double)) ¿verdad? Entonces res[0]obtiene 64 bits valy luego la configuración res[1] = ...usa los siguientes 64 bits. Estoy de acuerdo con el resultado, pero realmente no sigo tu primer comentario.
David

1
El punto es que el contenido del vector es poco a poco y int64_tque simplemente está "estacionado" dentro de un doublevector (también conocido como NumericVector). No hay una copia de lógica mágica. Jems está haciendo todo el trabajo duro a mano. Incluyendo mapeo de NAs.
Dirk Eddelbuettel

1
Ese. Es. Qué. Yo tengo. Estado. Molesto. A. Explique. Mire, por ejemplo, la fuente R para las definiciones de NA existentes. Mira algunos paquetes usando int64y mira lo que hacen.
Dirk Eddelbuettel

Respuestas:


6

Muy bien, creo que encontré una respuesta ... (no es hermosa, pero funciona).

Respuesta corta:

// [[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;
}

lo que resulta en

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

Respuesta larga

Inspeccionar cómo bit64almacena unNA

# 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"

Creado el 23 de abril de 2020 por el paquete reprex (v0.3.0)

vemos que es a 10000.... Esto se puede recrear Rcppcon int64_t val = 1ULL << 63;. ¡Usar en memcpy()lugar de una simple asignación con =asegura que no se cambien bits!


1
Si. Si observa algunos paquetes fuente, verá la #definedeclaración correspondiente para declarar que un patrón de bit (a menudo mino max) es el valor de NA.
Dirk Eddelbuettel

6

Es realmente mucho, mucho más simple. Tenemos el comportamiento de un int64in R ofrecido por (varios) paquetes de complementos, el mejor de los cuales es bit64darnos la integer64clase S3 y el comportamiento asociado.

Y define la NA internamente de la siguiente manera:

#define NA_INTEGER64 LLONG_MIN

Y eso es todo lo que hay. R y sus paquetes son el código C más importante, LLONG_MINexiste allí y se remonta (casi) hasta los padres fundadores.

Hay dos lecciones aquí. La primera es la extensión de IEEE que define NaN e Inf para valores de coma flotante . R en realidad va mucho más allá y agrega NApara cada uno de sus tipos . Más o menos en la forma anterior: reservando un patrón de bits particular. (Que, en un caso, es el cumpleaños de uno de los dos creadores originales de R.)

El otro es admirar la tonelada métrica de trabajo que Jens hizo con el bit64paquete y todas las funciones de conversión y operador requeridas. Convertir sin problemas todos los valores posibles, incluidos NA, NaN, Inf, ... no es tarea fácil.

Y es un tema interesante que no mucha gente conoce. Me alegra que hayas hecho la pregunta porque ahora tenemos un registro aquí.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.