在 Rcpp 中,如何获取模板返回的字符串和数字
In Rcpp, how to get a strings and numbers returned with templates
这个问题的延续:
如何获得 return 字符串和数字的 Rcpp 模板,而不是某种类型的 "Vectors"?我正在尝试将其他人的 C 代码移植到 R 中,他们使用各种不同的数据类型(char、unsigned char、short、unsigned short、int、float、long int、long unsigned int、double - 不,真的,所有这些是实际的 header!),我需要将它们 "coerce" 转换为 R 中的字符串和数字。看到来自 "Ralf Stubner" 的评论,我修改了您的示例以生成显示问题的 MWE:
#include <RcppCommon.h>
typedef struct {
char firstname[128];
// long unsigned int big_number;
} HEADER_INFO;
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x);
}
#include <Rcpp.h>
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x) {
Rcpp::CharacterVector firstname(x.firstname, x.firstname + 128);
// Rcpp::Integer big_number(x.big_number);
return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = firstname
// ,Rcpp::Named("big_number") = big_number
));
};
}
// [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
HEADER_INFO header;
strcpy( header.firstname, "Albert" );
// header.big_number = 123456789012345;
return header;
}
/*** R
getHeaderInfo()
*/
当你 运行 在 R:
> getHeaderInfo()
$firstname
[1] "65" "108" "98" "101" "114" "116" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[19] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[37] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[55] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[73] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[91] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[109] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "127" "16"
[127] "72" "-29"
unsigned long 条目被注释掉了,因为我在 Rcpp 命名空间中找不到可以编译的数据类型。 "Rcpp::Integer" 和 "Rcpp::Double" 这样的类型真的不存在吗?如果我必须使用 IntegerVector,那么如何告诉模板我想将 R 中的结果仅作为整数而不是长度为 1 的向量来引用?
我看到 Rcpp::CharacterVector
的基于范围的构造函数令人困惑。这是必要的,因为使用了 char *
数组,即字符串数组。这里我们只有一个字符串(固定的最大长度)。 Rcpp 足够智能,可以将其单独转换为长度为 1 的 CharacterVector
。
大数的情况比较有意思。首先,不清楚什么是unsigned long int
。它被定义为至少 32 位,在 32 位系统(和 64 位 Windows IIRC)上就是这种情况。在 64 位 Linux(和 MacOS?)上使用 64 位整数。现在 R 只知道 int
作为整数类型,它通常是 32 位宽但有符号,因此很小。然而,double
可以表示更大的整数 exactly,这是 R 本身在不同地方使用的技巧。所以在 32 位的系统上 unsigned long int
我们可以使用:
#include <RcppCommon.h>
typedef struct {
char firstname[128];
long unsigned int big_number;
} HEADER_INFO;
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x);
}
#include <Rcpp.h>
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x) {
static_assert(sizeof(long) <= 6, "long is to large");
double big_number = x.big_number;
return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = x.firstname,
Rcpp::Named("big_number") = big_number));
};
}
// [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
HEADER_INFO header;
strcpy( header.firstname, "Albert" );
header.big_number = 4294967295;
return header;
}
/*** R
getHeaderInfo()
*/
输出:
> getHeaderInfo()
$firstname
[1] "Albert"
$big_number
[1] 4294967295
两个列表元素实际上都是长度为 1 的向量。
在 64 位系统 unsigned long int
上,由于 static_assert
,这将无法编译。在这样的系统上,您可以使用与 bit64
包相同的技巧:将 64 位整数的 位模式 复制到 64 位浮点数(即 double
).这可以安全地传输到 R。但是,bit64
包将这些解释为 signed 整数。所以非常大的数字会溢出到负数。参见示例 integer64 and Rcpp compatibility and http://gallery.rcpp.org/articles/creating-integer64-and-nanotime-vectors/。我知道无符号数没有简单的解决方案。我认为您必须查明这些 unsigned long int
中的预期是否存在任何实际限制。
这个问题的延续:
如何获得 return 字符串和数字的 Rcpp 模板,而不是某种类型的 "Vectors"?我正在尝试将其他人的 C 代码移植到 R 中,他们使用各种不同的数据类型(char、unsigned char、short、unsigned short、int、float、long int、long unsigned int、double - 不,真的,所有这些是实际的 header!),我需要将它们 "coerce" 转换为 R 中的字符串和数字。看到来自 "Ralf Stubner" 的评论,我修改了您的示例以生成显示问题的 MWE:
#include <RcppCommon.h>
typedef struct {
char firstname[128];
// long unsigned int big_number;
} HEADER_INFO;
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x);
}
#include <Rcpp.h>
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x) {
Rcpp::CharacterVector firstname(x.firstname, x.firstname + 128);
// Rcpp::Integer big_number(x.big_number);
return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = firstname
// ,Rcpp::Named("big_number") = big_number
));
};
}
// [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
HEADER_INFO header;
strcpy( header.firstname, "Albert" );
// header.big_number = 123456789012345;
return header;
}
/*** R
getHeaderInfo()
*/
当你 运行 在 R:
> getHeaderInfo()
$firstname
[1] "65" "108" "98" "101" "114" "116" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[19] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[37] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[55] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[73] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[91] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0"
[109] "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "0" "127" "16"
[127] "72" "-29"
unsigned long 条目被注释掉了,因为我在 Rcpp 命名空间中找不到可以编译的数据类型。 "Rcpp::Integer" 和 "Rcpp::Double" 这样的类型真的不存在吗?如果我必须使用 IntegerVector,那么如何告诉模板我想将 R 中的结果仅作为整数而不是长度为 1 的向量来引用?
我看到 Rcpp::CharacterVector
的基于范围的构造函数令人困惑。这是必要的,因为使用了 char *
数组,即字符串数组。这里我们只有一个字符串(固定的最大长度)。 Rcpp 足够智能,可以将其单独转换为长度为 1 的 CharacterVector
。
大数的情况比较有意思。首先,不清楚什么是unsigned long int
。它被定义为至少 32 位,在 32 位系统(和 64 位 Windows IIRC)上就是这种情况。在 64 位 Linux(和 MacOS?)上使用 64 位整数。现在 R 只知道 int
作为整数类型,它通常是 32 位宽但有符号,因此很小。然而,double
可以表示更大的整数 exactly,这是 R 本身在不同地方使用的技巧。所以在 32 位的系统上 unsigned long int
我们可以使用:
#include <RcppCommon.h>
typedef struct {
char firstname[128];
long unsigned int big_number;
} HEADER_INFO;
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x);
}
#include <Rcpp.h>
namespace Rcpp {
template <>
SEXP wrap(const HEADER_INFO& x) {
static_assert(sizeof(long) <= 6, "long is to large");
double big_number = x.big_number;
return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = x.firstname,
Rcpp::Named("big_number") = big_number));
};
}
// [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
HEADER_INFO header;
strcpy( header.firstname, "Albert" );
header.big_number = 4294967295;
return header;
}
/*** R
getHeaderInfo()
*/
输出:
> getHeaderInfo()
$firstname
[1] "Albert"
$big_number
[1] 4294967295
两个列表元素实际上都是长度为 1 的向量。
在 64 位系统 unsigned long int
上,由于 static_assert
,这将无法编译。在这样的系统上,您可以使用与 bit64
包相同的技巧:将 64 位整数的 位模式 复制到 64 位浮点数(即 double
).这可以安全地传输到 R。但是,bit64
包将这些解释为 signed 整数。所以非常大的数字会溢出到负数。参见示例 integer64 and Rcpp compatibility and http://gallery.rcpp.org/articles/creating-integer64-and-nanotime-vectors/。我知道无符号数没有简单的解决方案。我认为您必须查明这些 unsigned long int
中的预期是否存在任何实际限制。