使用 TRNG 随机生成
Random generation with TRNG
对于以下为 Monte Carlo 模拟生成随机数的代码,我需要接收每个 运行 的确切总和,但这不会发生,尽管我已经修复了种子。如果有人能指出此代码的问题,我将不胜感激
#include <cmath>
#include <random>
#include <iostream>
#include <chrono>
#include <cfloat>
#include <iomanip>
#include <cstdlib>
#include <omp.h>
#include <trng/yarn2.hpp>
#include <trng/mt19937_64.hpp>
#include <trng/uniform01_dist.hpp>
using namespace std;
using namespace chrono;
const double landa = 1;
const double exact_solution = landa / (pow(landa, 2) + 1);
double function(double x) {
return cos(x) / landa;
}
int main() {
int rank;
const int N = 1000000;
double sum = 0.0;
trng::yarn2 r[6];
for (int i = 0; i <6; i++)
{
r[i].seed(0);
}
for (int i = 0; i < 6; i++)
{
r[i].split(6,i);
}
trng::uniform01_dist<double> u;
auto start = high_resolution_clock::now();
#pragma omp parallel num_threads(6)
{
rank=omp_get_thread_num();
#pragma omp for reduction (+: sum)
for (int i = 0; i<N; ++i) {
//double x = distribution(g);
double x= u(r[rank]);
x = (-1.0 / landa) * log(1.0 - x);
sum = sum+function(x);
}
}
double app = sum / static_cast<double> (N);
auto end = high_resolution_clock::now();
auto diff=duration_cast<milliseconds>(end-start);
cout << "Approximation is: " <<setprecision(17) << app << "\t"<<"Time: "<< setprecision(17) << diff.count()<<" Error: "<<(app-exact_solution)<< endl;
return 0;
}
TL;DR 问题有两个:
- 浮点加法是非关联的;
- 您正在为每个线程生成不同的随机数。
I need to receive the exact sum for each run, but this will not
happen, although I have fixed the seed. I would appreciate it if
anyone could point out the problem with this code
首先,你在 rank=omp_get_thread_num();
上有一个 race-condition,变量 rank
在所有线程之间共享,为了修复你可以声明并行区域内的变量 rank
,因此,它对每个线程都是私有的。
#pragma omp parallel num_threads(6)
{
int rank=omp_get_thread_num();
...
}
在您的代码中,您不应期望 sum
的值对于不同数量的线程是相同的。为什么?
因为您要并行添加 doubles
double sum = 0.0;
...
#pragma omp for reduction (+: sum)
for (int i = 0; i<N; ++i) {
//double x = distribution(g);
double x= u(r[rank]);
x = (-1.0 / landa) * log(1.0 - x);
sum = sum+function(x);
}
来自 每个计算机科学家都应该知道的关于浮动的知识
点算术 可读:
Another grey area concerns the interpretation of parentheses. Due to roundoff errors, the associative laws of algebra do not necessarily hold for floating-point numbers. For example, the
expression (x+y)+z has a totally different answer than x+(y+z) when
x = 1e30, y = -1e30 and z = 1 (it is 1 in the former case, 0 in the
latter).
因此,您由此得出结论,浮点加法不是
关联,以及为什么对于不同数量的线程你可能有不同的 sum
值的原因。
您正在为每个线程生成不同的随机值:
for (int i = 0; i < 6; i++)
{
r[i].split(6,i);
}
因此,对于不同数量的线程,变量sum
也会得到不同的结果。
正如 jérôme-richard 在评论中指出的那样:
Note that more precise algorithm like the Kahan summation can
significantly reduces the rounding issue while being still relatively
fast.
对于以下为 Monte Carlo 模拟生成随机数的代码,我需要接收每个 运行 的确切总和,但这不会发生,尽管我已经修复了种子。如果有人能指出此代码的问题,我将不胜感激
#include <cmath>
#include <random>
#include <iostream>
#include <chrono>
#include <cfloat>
#include <iomanip>
#include <cstdlib>
#include <omp.h>
#include <trng/yarn2.hpp>
#include <trng/mt19937_64.hpp>
#include <trng/uniform01_dist.hpp>
using namespace std;
using namespace chrono;
const double landa = 1;
const double exact_solution = landa / (pow(landa, 2) + 1);
double function(double x) {
return cos(x) / landa;
}
int main() {
int rank;
const int N = 1000000;
double sum = 0.0;
trng::yarn2 r[6];
for (int i = 0; i <6; i++)
{
r[i].seed(0);
}
for (int i = 0; i < 6; i++)
{
r[i].split(6,i);
}
trng::uniform01_dist<double> u;
auto start = high_resolution_clock::now();
#pragma omp parallel num_threads(6)
{
rank=omp_get_thread_num();
#pragma omp for reduction (+: sum)
for (int i = 0; i<N; ++i) {
//double x = distribution(g);
double x= u(r[rank]);
x = (-1.0 / landa) * log(1.0 - x);
sum = sum+function(x);
}
}
double app = sum / static_cast<double> (N);
auto end = high_resolution_clock::now();
auto diff=duration_cast<milliseconds>(end-start);
cout << "Approximation is: " <<setprecision(17) << app << "\t"<<"Time: "<< setprecision(17) << diff.count()<<" Error: "<<(app-exact_solution)<< endl;
return 0;
}
TL;DR 问题有两个:
- 浮点加法是非关联的;
- 您正在为每个线程生成不同的随机数。
I need to receive the exact sum for each run, but this will not happen, although I have fixed the seed. I would appreciate it if anyone could point out the problem with this code
首先,你在 rank=omp_get_thread_num();
上有一个 race-condition,变量 rank
在所有线程之间共享,为了修复你可以声明并行区域内的变量 rank
,因此,它对每个线程都是私有的。
#pragma omp parallel num_threads(6)
{
int rank=omp_get_thread_num();
...
}
在您的代码中,您不应期望 sum
的值对于不同数量的线程是相同的。为什么?
因为您要并行添加
doubles
double sum = 0.0; ... #pragma omp for reduction (+: sum) for (int i = 0; i<N; ++i) { //double x = distribution(g); double x= u(r[rank]); x = (-1.0 / landa) * log(1.0 - x); sum = sum+function(x); }
来自 每个计算机科学家都应该知道的关于浮动的知识 点算术 可读:
Another grey area concerns the interpretation of parentheses. Due to roundoff errors, the associative laws of algebra do not necessarily hold for floating-point numbers. For example, the expression (x+y)+z has a totally different answer than x+(y+z) when x = 1e30, y = -1e30 and z = 1 (it is 1 in the former case, 0 in the latter).
因此,您由此得出结论,浮点加法不是 关联,以及为什么对于不同数量的线程你可能有不同的
sum
值的原因。您正在为每个线程生成不同的随机值:
for (int i = 0; i < 6; i++) { r[i].split(6,i); }
因此,对于不同数量的线程,变量
sum
也会得到不同的结果。
正如 jérôme-richard 在评论中指出的那样:
Note that more precise algorithm like the Kahan summation can significantly reduces the rounding issue while being still relatively fast.