R和C++中相同的计算返回不同的结果

Same calculations in R and C++ return different results?

本文关键字:返回 结果 计算 C++      更新时间:2023-10-16

因此,我有一些R代码,我正在将其转换为C++。它读取一个文件,解析字符,计算大量的平均值和标准偏差,并返回它们,以及每个字符出现的数量。

现在,R产生的结果和C++产生的结果的十进制值略有不同。在计数矩阵中,由于它们是整数,所以数字完全相同。然而,在平均值矩阵中,值直到第一百位都是相同的,而且它们之间的差异超过了第一百位。有了标准偏差矩阵,数值的差异甚至更大——相差十分之几。

是什么原因造成的?我假设R和C++处理带小数的数字的方式存在某种精度差异。我知道计算机一开始并不是最擅长表示浮点数的,但我该如何判断哪种输出更好?

我尝试过的一件事是在Windows 7中的R、C++和Calculator中执行计算sqrt(41111.5/4252(。它们都产生了相同的结果。那么,当在运行时遇到完全相同的计算时,为什么它们会不同呢?在运行时输出中,C++与Calculator一致,R是奇数。我还注意到,当执行这些大量计算时,后期输出的变化比早期输出稍大。R只是在做这么多计算时感到疲劳并开始搞砸吗?怎么回事?

以下是平均值的输出:

C++:

38.6068 39.0122 38.633 38.5914 0
38.6159 38.7874 38.5053 38.7195 0
38.5205 38.7352 38.3694 38.5388 0
38.6331 38.7408 38.4588 38.5283 0
38.7503 38.6933 38.4173 38.6808 0
38.7637 38.7978 38.4967 38.603 0
38.7616 38.7384 38.4728 38.6946 0
38.6227 38.7689 38.4016 38.5352 0
38.5993 38.7334 38.3206 38.5514 0
38.6395 38.6598 38.43 38.4887 0
38.6414 38.746 38.4353 38.4908 0
38.4353 38.6767 38.3158 38.4694 0
38.35 38.5801 38.1486 38.3528 0
38.4122 38.6267 38.1731 38.3447 0
38.3751 38.5353 38.1782 38.2229 0
38.3373 38.6117 37.8952 38.2017 4.12443
38.332 38.4991 38.027 38.1984 0
38.2005 38.4417 38.0192 38.0446 4.12443
38.1719 38.4435 37.9727 38.0385 0
38.1346 38.3878 37.8634 37.9746 0
37.8505 38.2289 37.6202 37.6986 0
38.0932 38.142 37.7865 37.815 4.12443
37.9176 38.1381 37.5577 37.7273 0
37.7346 38.0934 37.4874 37.6546 0
37.6961 37.897 37.3342 37.4844 0
37.5534 37.9234 37.3341 37.3369 0
37.4914 37.7409 37.094 37.3211 0
37.2179 37.6653 36.9031 37.2592 0
37.0682 37.5625 36.6972 37.0218 4.12443
36.9713 37.4819 36.5387 36.8767 4.12443
36.8284 37.2411 36.223 36.6869 4.12443
36.7396 36.9682 36.0171 36.4556 4.12443
36.7874 36.9482 36.1641 36.5667 4.12443
36.695 36.9307 36.1856 36.3638 0
36.7224 36.9455 36.2212 36.695 4.12443
36.8983 37.1286 36.2652 36.8055 0
36.7835 36.8905 35.9562 36.4745 0
36.5364 36.9037 36.0927 36.4888 0
36.3959 36.6637 35.7378 36.323 0
35.9372 36.2034 35.452 35.6974 0

R:

            A        C        G        T N
[1,] 38.60573 39.01141 38.63195 38.59036 0
[2,] 38.61464 38.78523 38.50391 38.71826 0
[3,] 38.51908 38.73228 38.36774 38.53731 0
[4,] 38.63182 38.73834 38.45730 38.52657 0
[5,] 38.74903 38.69083 38.41585 38.67933 0
[6,] 38.76250 38.79534 38.49556 38.60156 0
[7,] 38.76039 38.73632 38.47145 38.69319 0
[8,] 38.62123 38.76703 38.40030 38.53354 0
[9,] 38.59810 38.73163 38.31917 38.55015 0
[10,] 38.63819 38.65792 38.42873 38.48740 0
[11,] 38.64002 38.74333 38.43387 38.48920 0
[12,] 38.43359 38.67401 38.31414 38.46783 0
[13,] 38.34827 38.57804 38.14686 38.35125 0
[14,] 38.41038 38.62463 38.17138 38.34302 0
[15,] 38.37329 38.53267 38.17653 38.22097 0
[16,] 38.33555 38.60949 37.89278 38.19956 4
[17,] 38.33024 38.49720 38.02496 38.19627 0
[18,] 38.19842 38.43880 38.01730 38.04205 4
[19,] 38.16998 38.44113 37.97058 38.03598 0
[20,] 38.13242 38.38488 37.86108 37.97245 0
[21,] 37.84771 38.22579 37.61745 37.69546 0
[22,] 38.09113 38.13806 37.78409 37.81250 4
[23,] 37.91487 38.13428 37.55473 37.72422 0
[24,] 37.73137 38.09007 37.48473 37.65181 0
[25,] 37.69295 37.89276 37.33098 37.48131 0
[26,] 37.54974 37.91984 37.33063 37.33263 0
[27,] 37.48773 37.73676 37.09027 37.31701 0
[28,] 37.21365 37.66051 36.89896 37.25519 0
[29,] 37.06418 37.55768 36.69254 37.01714 4
[30,] 36.96674 37.47745 36.53390 36.87150 4
[31,] 36.82324 37.23622 36.21721 36.68085 4
[32,] 36.73433 36.96207 36.01076 36.44930 4
[33,] 36.78201 36.94274 36.15842 36.56135 4
[34,] 36.68991 36.92524 36.17984 36.35769 0
[35,] 36.71720 36.94031 36.21548 36.68985 4
[36,] 36.89332 37.12322 36.25921 36.80057 0
[37,] 36.77870 36.88471 35.94958 36.46900 0
[38,] 36.53080 36.89801 36.08650 36.48348 0
[39,] 36.38996 36.65730 35.73058 36.31767 0
[40,] 35.93152 36.19707 35.44496 35.69141 0

毫无疑问,任何数量的事情都可能发生。因此,我只能假设一个奇异的可能原因。

一种可能性是R以最小化浮点误差的方式执行计算;除非你更清楚,否则你不一定会在C++或手工计算中做到这一点。特别是,在计算总和之前,您应该按照指数的递增顺序对值进行排序(这应该是任何精确平均过程的第一步(。原因是浮点运算不是关联的(除非您使用任意精度库,我认为情况并非如此(。由于四舍五入,如果a>>b,c,(a+b(+c可以等于c,而a+(b+c(将给出大于a的结果(假设a,b,c>0(。如果R将其工作并行化,这尤其可能,在这种情况下,您可以合理地期望每次都会得到略有不同的结果

其他不那么奇特的可能性包括:R和C++代码以某种微妙但有意义的方式存在差异(可能其中一个代码中有错误,它错过了第72个元素,或者你在一个中使用n-1计算STDEV,在另一个中则使用n,等等(;R和C++之间的运行时存在差异,这从根本上导致了这种差异(不同的精度-双精度与浮点与长双精度,等等,不同的库实现,等等(

我不知道这是否适用于你的问题,但如果没有其他人,如果他们很难理解为什么浮点运算不能给出一致的结果,他们可能会觉得这很有用。

我要检查的几件事:

  • 这可能是使用CCD_ 1和CCD_。如果您使用double,则可能是R使用float。如果在两者之间切换很容易,请尝试使用float
  • 检查编译器(例如VC2010(中设置的浮点精度模式,然后尝试不同的设置
  • 确保C++中的所有计算都正确地转换为double/foat。例如,此代码:

     double Test = 1.0 + 3/2;
    

    结果是2而不是2.5。R可能会以不同的方式表达这些表达式,从而导致您的结果出现差异。

  • 仔细检查R和C++中的函数是否相同。例如,R中的cos()可能需要度,而C++中的CCD_7是弧度。如果有疑问,请在两者中进行快速测试以确认
  • 如果所有其他操作都失败,则在R和C++应用程序中进行一次特定的计算并记录/输出详细的诊断。在某个时刻,你应该开始看到差异,并追溯到它的起源。用一个较小的样本试试,看看你是否可以用6/60个样本而不是6000个样本来复制这种行为

我刚刚注意到的一件事是,在结果的最后一列中,C++给出4.12443,而R给出4。除非这只是一个显示问题,否则看看为什么会出现这种情况。可能是R中的某些内容被舍入/强制转换为整数,但C++中没有。

好吧,我只想使用C++值,这主要归功于uesp对最后一列的深入了解——R可能在某个中间步骤中被强制转换为整数,并失去了一些精度。我在C++中的每一步都使用doubles,所以我更信任它(……更不用说我一开始就很自然地不信任解释语言,哈哈(