简体   繁体   English

从R翻译的随机生成代码在C ++中失败

[英]Random generation code translated from R fails in C++

I am working on code implementing random generation algorithm for sampling from tails of normal distribution proposed by Christian Robert . 我正在研究实现随机生成算法的代码,用于从Christian Robert提出的正态分布尾部进行采样。 The problem is that while code in R worked properly, then after translating it to C++ if fails. 问题是,虽然R中的代码工作正常,但如果失败则将其转换为C ++。 I can't see any reason for that and I'd be grateful for explaining me what went wrong and why. 我看不出任何理由,我会很感激地向我解释出了什么问题以及原因。

Notice that the code below is far from elegant and efficient, it is simplified to make reproducible example. 请注意,下面的代码远非优雅和高效,它简化为可重复的示例。

Here is the function in R: 这是R中的函数:

rtnormR <- function(mean = 0, sd = 1, lower = -Inf, upper = Inf) {
  lower <- (lower - mean) / sd 
  upper <- (upper - mean) / sd

  if (lower < upper && lower >= 0) {
    while (TRUE) {
      astar <- (lower + sqrt(lower^2 + 4)) / 2
      z <- rexp(1, astar) + lower
      u <- runif(1)
      if ((u <= exp(-(z - astar)^2 / 2)) && (z <= upper)) break
    }
  } else {
    z <- NaN
  }
  z*sd + mean
}

and here C++ version: 这里是C ++版本:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]

double rtnormCpp(double mean, double sd, double lower, double upper) {
  double z_lower = (lower - mean) / sd;
  double z_upper = (upper - mean) / sd;
  bool stop = false;
  double astar, z, u;

  if (z_lower < z_upper && z_lower >= 0) {
    while (!stop) {
      astar = (z_lower + std::sqrt(std::pow(z_lower, 2) + 4)) / 2;
      z = R::exp_rand() * astar + z_lower;
      u = R::unif_rand();
      if ((u <= std::exp(-std::pow(z-astar, 2) / 2)) && (z <= z_upper))
        stop = true;
    }
  } else {
    z = NAN;
  }
  return z*sd + mean;
}

Now compare the samples obtained using both functions (they are compared to dtnorm function from msm library): 现在比较使用这两个函数获得的样本(它们与来自msm库的dtnorm函数进行比较):

xx = seq(-6, 6, by = 0.001)
hist(replicate(5000, rtnormR(mean = 0, sd = 1, lower = 3, upper = 5)), freq= FALSE, ylab = "", xlab = "", main = "rtnormR")
lines(xx, msm::dtnorm(xx, mean = 0, sd = 1, lower = 3, upper = 5), col = "red")
hist(replicate(5000, rtnormCpp(mean = 0, sd = 1, lower = 3, upper = 5)), freq= FALSE, ylab = "", xlab = "", main = "rtnormCpp")
lines(xx, msm::dtnorm(xx, mean = 0, sd = 1, lower = 3, upper = 5), col = "red")

在此输入图像描述

As you can see, rtnormCpp returns biased samples. 如您所见, rtnormCpp返回有偏差的样本。 Do you have any ideas why? 你有什么想法吗?

While one can use either scale or rate in rexp() , the default parameterization is rate - so rexp(1,astar) has a mean of 1/astar , not astar . 虽然可以在rexp()使用scalerate ,但默认参数化是rate - 所以rexp(1,astar)的平均值为1/astar ,而不是astar

If you change the relevant line of C++ code to 如果您将相关的C ++代码行更改为

z = R::exp_rand() / astar + z_lower;

everything seems to work fine. 一切似乎都很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM