R舍入错误与C ++舍入错误

时间:2014-06-25 22:00:14

标签: c++ r rcpp

我在R中编写了一个代码,它使用两个数字向量(值和权重)作为输入,并产生加权基尼,加权方差和两个加权平均值的差异(第一种是数据行小于或等于修订版本和人口2是大于修订版的数据行。这反过来坐在一个运行100,000次的循环中。这很慢。所以我决定尝试使用Rcpp来代替使用C ++代码来执行此任务。下面是我在RStudio中创建的.cpp文件,它定义了该函数。

我有另一个代码来测试它。它使用简单的输入向量进行现场工作。但是当我使用更大的输入向量时,它不起作用。我相信当输入向量变大时,问题与舍入错误有关。如果是这样,我该如何处理这个问题呢?我能相信我比较我的功能的R功能吗?提前感谢任何想法。

我将.cpp文件和测试文件包含在下面。

.cpp程序:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector GetMeasures(const std::vector<double>& Frequency, 
                const std::vector<double>& Value, int Revision) {

long double WeightedSum = std::inner_product(Frequency.begin(), Frequency.end(), Value.begin(), 0);
int N = std::accumulate(Frequency.begin(),Frequency.end(),0);
long double mu = WeightedSum / N;

long double sumOfDifferences=0;
for(int j=0; j<Value.size(); ++j){
  for(int i=0; i<Value.size(); ++i){
    sumOfDifferences=sumOfDifferences+abs(Value[i]-Value[j])*Frequency[i]*Frequency[j];
  }
}
long double M = sumOfDifferences / pow(N,2);
long double Gini = M / (2 * mu);

double SumOfSquares = 0;
for(int i=0; i<Value.size(); ++i){
    SumOfSquares=SumOfSquares+(pow((Value[i]-mu),2)*Frequency[i]);
  }
double Variance = SumOfSquares / (N - 1);

double WeightedSum1 = std::inner_product(Frequency.begin(), Frequency.begin()+Revision, Value.begin(), 0);
int N1 = std::accumulate(Frequency.begin(),Frequency.begin()+Revision,0);
double mu1 = WeightedSum1 / N1;
double WeightedSum2 = std::inner_product(Frequency.begin()+Revision, Frequency.end(), Value.begin()+Revision, 0);
double N2 = std::accumulate(Frequency.begin()+Revision,Frequency.end(),0);
double mu2 = WeightedSum2 / N2;
double Difference = mu1 - mu2;

Rcpp::NumericVector output(3);
output[0]=Gini;
output[1]=Variance;
output[2]=Difference;
return output;
}

测试程序:

library(Hmisc)
library(ineq)

a=c(1,2,3,4)
b=c(5,6,7,8)

with(Lc(a,b), abs(1 - sum(diff(p) * (L[-1] + L[-length(L)]))))
wtd.var(b,weights=b)
wtd.mean(a[1:2],b[1:2])-wtd.mean(a[3:4],b[3:4])

GetMeasures(a,b,2)

a=c(0.07418378, 0.07426745, 0.07435280, 0.07443986, 0.07452865, 0.07461923, 0.07471161, 0.07480584,
0.07490196, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000,
0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000,
0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000,
0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000)

b=seq(from=1400, to=1400/40, by=-1400/40)

with(Lc(a,b), abs(1 - sum(diff(p) * (L[-1] + L[-length(L)]))))
wtd.var(a,weights=b)
wtd.mean(a[1:10],b[1:10])-wtd.mean(a[11:40],b[11:40])

GetMeasures(a,b,10)

测试代码输出:

> a=c(1,2,3,4)
> b=c(5,6,7,8)
> 
> with(Lc(a,b), abs(1 - sum(diff(p) * (L[-1] + L[-length(L)]))))
[1] 0.2274725
> wtd.var(b,weights=b)
[1] 1.261538
> wtd.mean(a[1:2],b[1:2])-wtd.mean(a[3:4],b[3:4])
[1] -1.987879
> 
> GetMeasures(a,b,2)
[1]  0.2274725  1.2615385 -1.9878788
> a=c(0.07418378, 0.07426745, 0.07435280, 0.07443986, 0.07452865, 0.07461923, 0.07471161, 0.07480584,
+ 0.07490196, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000,
+ 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000,
+ 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000,
+ 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000, 0.07500000)
> 
> b=seq(from=1400, to=1400/40, by=-1400/40)
> with(Lc(a,b), abs(1 - sum(diff(p) * (L[-1] + L[-length(L)]))))
[1] 0.001816041
> wtd.var(a,weights=b)
[1] 7.659737e-08
> wtd.mean(a[1:10],b[1:10])-wtd.mean(a[11:40],b[11:40])
[1] -0.0004399504
> GetMeasures(a,b,10)
[1]  0.000000e+00  5.638678e-07 -1.185608e-04

2 个答案:

答案 0 :(得分:0)

我还不能添加评论,所以我把它写成答案,但它更像是评论。

我不明白所有的代码,但我看到你使用了一些整数,我不确定它们是否应该总是整数,或者是否在这里发生了一些舍入。

考虑到在c ++中整数总是四舍五入到底部。舍入到最近的一个简单技巧是在将double / float转换为整数之前加0.5:

int a = num_to_round + .5;

答案 1 :(得分:0)

这两个组成部分有点怀疑:

std::vector<double> Frequency; // the declaration
int N = std::accumulate(Frequency.begin(),Frequency.end(),0);

0是C ++中的整数文字,因此看起来你试图通过将双精度转换为整数来填充整数,然后将它们加起来。

最好写一下:

int N = static_cast<int>(std::accumulate(Frequency.begin(), Frequency.end(), 0.0);

只是要非常清楚地表明您正在将double s的总和转换为int

那就是说,你为什么要N为整数?如果你要加起来double并且它们想要加起来一些整数值,你可能想要显式舍入到最接近的值 - int施法总是向下舍入,这可能会非常令人惊讶如果求和的结果是5.99999991587151

相关问题