Giá trị Rcpp và int64 NA


8

Làm cách nào tôi có thể chuyển một giá trị NA từ Rcpp sang R trong một vectơ 64 bit?

Cách tiếp cận đầu tiên của tôi sẽ là:

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

Nhưng nó mang lại

#> foo()
integer64
[1] 1234567890123456789 9218868437227407266

tôi cần lấy

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

Bạn không thể sử dụng NA_REALsau memcpybởi vì mẫu bit tại thời điểm đó là một trong số a int64.
Dirk Eddelbuettel

Tôi cũng sẽ chỉnh sửa tiêu đề. Các mặc định 64 bit NA chỉ là NA_realđó không phải là những gì câu hỏi của bạn là về.
Dirk Eddelbuettel

Nhưng các bản sao memcpy chỉ có 64 bit ( sizeof(double)) phải không? Vì vậy, res[0]nhận 64 bit từ valvà sau đó cài đặt res[1] = ...sử dụng 64 bit tiếp theo. Tôi đồng ý với kết quả này, nhưng không thực sự làm theo bình luận đầu tiên của bạn.
David

1
Toàn bộ vấn đề là nội dung của vectơ sau đó từng chút một int64_tchỉ đơn thuần là "đậu" bên trong một doublevectơ (aka NumericVector). Không có bản sao logic ma thuật. Jems đang làm tất cả các công việc khó khăn bằng tay. Bao gồm các NA ánh xạ.
Dirk Eddelbuettel

1
Cái đó. Là. Gì. Tôi có. Đã. Cố gắng. Đến. Giải thích. Nhìn vào ví dụ nguồn R cho NA hiện có. Nhìn vào một số gói sử dụng int64và xem những gì họ làm.
Dirk Eddelbuettel

Câu trả lời:


6

Được rồi, tôi nghĩ rằng tôi đã tìm thấy một câu trả lời ... (không đẹp, nhưng làm việc).

Câu trả lời ngắn:

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

kết quả là

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

Câu trả lời dài hơn

Kiểm tra cách bit64lưu trữ mộtNA

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

Được tạo vào ngày 2020-04-23 bởi gói reprex (v0.3.0)

chúng tôi thấy rằng nó là một 10000.... Điều này có thể được tạo lại Rcppvới int64_t val = 1ULL << 63;. Sử dụng memcpy()thay vì gán đơn giản với =đảm bảo rằng không có bit nào được thay đổi!


1
Đúng. Nếu bạn nhìn vào một số gói nguồn, bạn sẽ thấy #definecâu lệnh tương ứng để khai báo một mẫu bit (thường là minhoặc max) là giá trị NA.
Dirk Eddelbuettel

6

Nó thực sự rất nhiều, đơn giản hơn nhiều. Chúng tôi có hành vi của một gói int64R được cung cấp bởi (một số) gói bổ trợ tốt nhất trong số đó là bit64cung cấp cho chúng tôi integer64lớp S3 và hành vi liên quan.

Và nó định nghĩa NA trong nội bộ như sau:

#define NA_INTEGER64 LLONG_MIN

Và đó là tất cả những gì có. R và các gói của nó là mã C quan trọng nhất, và LLONG_MINtồn tại ở đó và quay trở lại (gần như) tất cả các cách để thành lập cha.

Có hai bài học ở đây. Đầu tiên là phần mở rộng của IEEE xác định NaN và Inf cho các giá trị dấu phẩy động . R thực sự đi xa hơn và thêm NAcho từng loại của nó . Theo cách khá nhiều ở trên: bằng cách đặt trước một mẫu bit cụ thể. (Trong một trường hợp, đó là ngày sinh nhật của một trong hai người tạo R gốc.)

Hai là để ngưỡng mộ tấn công mà Jens đã làm với bit64gói và tất cả các chức năng chuyển đổi và vận hành cần thiết. Chuyển đổi liền mạch tất cả các giá trị có thể, bao gồm NA, NaN, Inf, ... là nhiệm vụ không hề nhỏ.

Và đó là một chủ đề gọn gàng mà không quá nhiều người biết. Tôi rất vui vì bạn đã đặt câu hỏi bởi vì bây giờ chúng tôi có một hồ sơ ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.