我正在构建一个应用程序,计算regularized incomplete beta function很重.这款应用是用C++编写的,可以调用R::pbeta()
.当我试图将这款应用程序多线程时,来自R::pbeta()
的一些警告消息打破了堆栈.
所以我转到了boost::math::ibeta()
.一切都很好,直到我测量了速度.下面的C++文件whyIsBoostSlower.cpp
使用R::pbeta()
或boost::math::ibeta()
实现正则化的不完全Beta函数.
// [[Rcpp::plugins(cpp17)]]
#include <boost/math/special_functions/beta.hpp>
// [[Rcpp::depends(BH)]]
#include <Rcpp.h>
using namespace Rcpp;
// Compute the regularized incomplete Beta function.
// [[Rcpp::export]]
NumericVector RIBF(NumericVector q, NumericVector a, NumericVector b,
bool useboost = false)
{
NumericVector rst(q.size());
for (int i = 0, iend = q.size(); i < iend; ++i)
{
if (useboost) rst[i] = boost::math::ibeta( a[i], b[i], q[i] );
else rst[i] = R::pbeta( q[i], a[i], b[i], 1, 0 );
}
return rst;
}
在R中,我们测量对随机数调用函数300000次的速度:
Rcpp::sourceCpp("whyIsBoostSlower.cpp")
set.seed(123)
N = 300000L
q = runif(N) # Generate quantiles.
a = runif(N, 0, 10) # Generate a in (0, 10)
b = runif(N, 0, 10) # Generate b in (0, 10)
# Use R's pbeta(). This function calls a C wrapper of toms708.c:
# https://svn.r-project.org/R/trunk/src/nmath/toms708.c
system.time({ Rrst = RIBF(q, a, b, useboost = F) })
# Windows 10 (seconds):
# user system elapsed
# 0.11 0.00 0.11
# RedHat Linux:
# user system elapsed
# 0.097 0.000 0.097
# Use Boost's implementation, which also depends on TOMS 708 by their claim:
# https://www.boost.org/doc/libs/1_41_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html
system.time({ boostRst = RIBF(q, a, b, useboost = T) })
# Windows 10:
# user system elapsed
# 0.52 0.00 0.52
# RedHat Linux:
# user system elapsed
# 0.988 0.001 0.993
range(Rrst - boostRst)
# -1.221245e-15 1.165734e-15
要重现该示例,需要安装R和包Rcpp
.在Windows上,用户还需要安装包含GCC发行版的Rtools
.优化标志默认为-O2
.
R::pbeta()
和boost::math::ibeta()
都基于ACM TOMS 708,但boost::math::ibeta()
在Windows上慢5倍,在Linux上慢10倍.
我认为这可能与在boost::math::ibeta()
中设置Policy
参数有关,但如何呢?
谢谢!
仅供参考,R-4.2.3/src/nmath/pbeta.c
中定义了R::pbeta()
.R::pbeta()
调用在R-4.2.3/src/nmath/toms708.c
中定义的bratio()
,即https://svn.r-project.org/R/trunk/src/nmath/toms708.c.里面的代码是TOMS 708 Fortran代码的C翻译.翻译是由R的核心团队完成的.
相反,Boost则声明"此实现紧密基于"算法708;"不完全贝塔函数比率的有效位数计算",DiDonato和Morris,ACM,1992.在boost::math::ibeta()
上