简体   繁体   English

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

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

The following post is solved,the problem occurred because of miss interpretation of the formula on http://www.cplusplus.com/reference/random/piecewise_constant_distribution/ The reader is strongly encouraged to consider the page: http://en.cppreference.com/w/cpp/numeric/random/piecewise_constant_distribution 解决了以下问题,由于对http://www.cplusplus.com/reference/random/piecewise_constant_distribution/上的公式的解释不正确而发生了问题,强烈建议读者考虑以下内容: http://en.cppreference .com / w / cpp / numeric / random / piecewise_constant_distribution

I have the following strange phenomenon which puzzles me!: 我有以下奇怪的现象使我感到困惑!:

I have a piecewise constant probability density given as 我有一个分段恒定概率密度,给出为

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());

When I draw n random numbers (radius of sphere in millimeters) from this distribution and compute the mass of the sphere and sum them up like: 当我从此分布中绘制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;
}

I get mass = 4.3283 kg (see LIVE here ) 我的体重为4.3283公斤 (请在此处查看实况)

Doing the EXACT identical thing in Mathematica like: 在Mathematica中执行完全相同的操作,例如:

图形化

Gives the assumably correct value of 4.5287 kg . 给出的正确值为4.5287千克 (see mathematica ) (请参阅mathematica

Which is not the same, also with different seeds , C++ and Mathematica never match! 这是不一样的,种子也不同,C ++和Mathematica永远不匹配! ? Is that numeric inaccuracy, which I doubt it is...? 那是数字不准确吗?我怀疑这是...吗? Question : What the hack is wrong with the sampling in C++? 问题:C ++中的采样有什么问题?

Simple Mathematica Code: 简单的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}]

Update : I did some analysis: 更新 :我做了一些分析:

  1. Read in the numbers (64bit doubles) generated from Mathematica into C++ -> calculated the sum and it gives the same as Mathematica 将Mathematica生成的数字(64位双精度)读入C ++->计算得出的总和与Mathematica相同
    Mass computed by reduction: 4.52528010260687096888432279229 通过减少计算得出的质量:4.52528010260687096888432279229

  2. Read in the numbers generated from C++ (64bit double) into Mathematica -> calculated the sum and it gives the same 4.32402 将C ++(64位双精度 )生成的数字读入Mathematica->计算总和,得出的总和为4.32402

  3. I almost conclude the sampling with std::piecewise_constant_distribution is inaccurate (or as accurate as it gets with 64bit floats) or has a bug... OR there is something wrong with my weights? 我几乎可以得出结论,使用std::piecewise_constant_distribution的采样是不准确的(或与使用64位浮点数所获得的精度一样)或有错误...或者我的权重有问题吗?

  4. Densities are calculated wrongly std::piecewise_constant_distribution in http://coliru.stacked-crooked.com/a/ca171bf600b5148f ===> It seems to be a bug! 密度在http://coliru.stacked-crooked.com/a/ca171bf600b5148f中的 std::piecewise_constant_distribution错误地计算出===>这似乎是一个错误!

Histogramm Plot of CPP Generated values compared to the wanted 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]

The file is generated here: Number generation CPP 在此处生成文件: 数字生成CPP

[The following paragraph was edited for correctness. [为正确起见,以下段落进行了编辑。 --Editor's note] -编者按]

Mathematica may or may not use IEEE 754 floating point numbers. Mathematica可能会或可能不会使用IEEE 754浮点数。 From the Wolfram documentation: 从Wolfram文档中:

The Wolfram Language has sophisticated built-in automatic numerical precision and accuracy control. Wolfram语言具有完善的内置自动数值精度和精度控制。 But for special-purpose optimization of numerical computations, or for studying numerical analysis, the Wolfram Language also allows detailed control over precision and accuracy. 但是,对于特殊用途的数值计算优化或研究数值分析,Wolfram语言还允许对精度和准确性进行详细控制。

and

The Wolfram Language handles both integers and real numbers with any number of digits, automatically tagging numerical precision when appropriate. Wolfram语言可以处理任意位数的整数和实数,并在适当时自动标记数字精度。 The Wolfram Language internally uses several highly optimized number representations, but nevertheless provides a uniform interface for digit and precision manipulation, while allowing numerical analysts to study representation details when desired. Wolfram语言在内部使用了几种高度优化的数字表示形式,但是仍然为数字和精度操纵提供了统一的界面,同时允许数值分析人员在需要时研究表示形式的细节。

It seems that the formula for the probabilities is wrongly written for std::piecewise_constant_distribution on http://www.cplusplus.com/reference/random/piecewise_constant_distribution/ http://www.cplusplus.com/reference/random/piecewise_constant_distribution/上,似乎为std::piecewise_constant_distribution错误地写出了概率公式

The summation of the weights is done without the interval lengths multiplied! 权重的总和不乘以间隔长度!

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

This solves every stupid quirk previously discovered as bug/floating point error and so on! 这解决了以前被发现为错误/浮点错误等的每个愚蠢的怪癖!

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

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