繁体   English   中英

与Mathematica相比,C ++中的浮点数学舍入很奇怪

[英]Floating point math rounding weird in C++ compared to mathematica

解决了以下问题,由于对http://www.cplusplus.com/reference/random/piecewise_constant_distribution/上的公式的解释不正确而发生了问题,强烈建议读者考虑以下内容: http://en.cppreference .com / w / cpp / numeric / random / piecewise_constant_distribution

我有以下奇怪的现象使我感到困惑!:

我有一个分段恒定概率密度,给出为

using RandomGenType = std::mt19937_64;
RandomGenType gen(51651651651);

using PREC = long double;
std::array<PREC,5> intervals {0.59, 0.7, 0.85, 1, 1.18};
std::array<PREC,4> weights {1.36814, 1.99139, 0.29116, 0.039562};

 // integral over the pdf to normalize:
PREC normalization =0;
for(unsigned int i=0;i<4;i++){
    normalization += weights[i]*(intervals[i+1]-intervals[i]);
}
std::cout << std::setprecision(30) << "Normalization: " << normalization << std::endl;
// normalize all weights (such that the integral gives 1)!
for(auto & w : weights){
    w /= normalization;
}

std::piecewise_constant_distribution<PREC>
distribution (intervals.begin(),intervals.end(),weights.begin());

当我从此分布中绘制n随机数(球半径以毫米为单位)并计算球的质量并将其求和时,如下所示:

unsigned int n = 1000000;
double density = 2400;
double mass = 0;

for(int i=0;i<n;i++){
    auto d = 2* distribution(gen) * 1e-3;
    mass += d*d*d/3.0*M_PI_2*density;
}

我的体重为4.3283公斤 (请在此处查看实况)

在Mathematica中执行完全相同的操作,例如:

图形化

给出的正确值为4.5287千克 (请参阅mathematica

这是不一样的,种子也不同,C ++和Mathematica永远不匹配! 那是数字不准确吗?我怀疑这是...吗? 问题:C ++中的采样有什么问题?

简单的Mathematica代码:

pdf[r_] = 2*Piecewise[{{0, r < 0.59}, {1.36814, 0.59 <= r <= 0.7}, 
           {1.99139, Inequality[0.7, Less, r, LessEqual, 0.85]}, 
           {0.29116, Inequality[0.85, Less, r, LessEqual, 1]}, 
           {0.039562, Inequality[1, Less, r, LessEqual, 1.18]}, 
           {0, r > 1.18}}];

pdfr[r_] = pdf[r] / Integrate[pdf[r], {r, 0, 3}];(*normalize*)

Plot[pdf[r], {r, 0.4, 1.3}, Filling -> Axis]

PDFr = ProbabilityDistribution[pdfr[r], {r, 0, 1.18}]; 
(*if you put 1.18=2 then we dont get 4.52??*)

SeedRandom[100, Method -> "MersenneTwister"]
dataR = RandomVariate[PDFr, 1000000, WorkingPrecision -> MachinePrecision];
Fold[#1 + (2*#2*10^-3)^3  Pi/6 2400 &, 0, dataR] 

(*Analytical Solution*)

PDFr = ProbabilityDistribution[pdfr[r], {r, 0, 3}];
1000000 Integrate[ 2400 (2 InverseCDF[PDFr, p] 10^-3)^3 Pi/6, {p, 0, 1}]

更新 :我做了一些分析:

  1. 将Mathematica生成的数字(64位双精度)读入C ++->计算得出的总和与Mathematica相同
    通过减少计算得出的质量:4.52528010260687096888432279229

  2. 将C ++(64位双精度 )生成的数字读入Mathematica->计算总和,得出的总和为4.32402

  3. 我几乎可以得出结论,使用std::piecewise_constant_distribution的采样是不准确的(或与使用64位浮点数所获得的精度一样)或有错误...或者我的权重有问题吗?

  4. 密度在http://coliru.stacked-crooked.com/a/ca171bf600b5148f中的 std::piecewise_constant_distribution错误地计算出===>这似乎是一个错误!

CPP生成值与所需分布的直方图图: 直方图

file = NotebookDirectory[] <> "numbersCpp.bin";
dataCPP = BinaryReadList[file, "Real64"];
Hpdf = HistogramDistribution[dataCPP];
h = DiscretePlot[  PDF[ Hpdf, x], {x, 0.4, 1.2, 0.001}, 
   PlotStyle -> Red];
Show[h, p, PlotRange -> All]

在此处生成文件: 数字生成CPP

[为正确起见,以下段落进行了编辑。 -编者按]

Mathematica可能会或可能不会使用IEEE 754浮点数。 从Wolfram文档中:

Wolfram语言具有完善的内置自动数值精度和精度控制。 但是,对于特殊用途的数值计算优化或研究数值分析,Wolfram语言还允许对精度和准确性进行详细控制。

Wolfram语言可以处理任意位数的整数和实数,并在适当时自动标记数字精度。 Wolfram语言在内部使用了几种高度优化的数字表示形式,但是仍然为数字和精度操纵提供了统一的界面,同时允许数值分析人员在需要时研究表示形式的细节。

http://www.cplusplus.com/reference/random/piecewise_constant_distribution/上,似乎为std::piecewise_constant_distribution错误地写出了概率公式

权重的总和不乘以间隔长度!

正确的公式是: http : //en.cppreference.com/w/cpp/numeric/random/piecewise_constant_distribution

这解决了以前被发现为错误/浮点错误等的每个愚蠢的怪癖!

暂无
暂无

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

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