在mooc看概率统计教学视频的时候看到了一个课后思考题:抽奖骗局,总觉得这个能行,于是把它用代码实现了出来。
一开始我准备使用cuda在设备端上并行模拟抽奖来快速实现这个题目,但可惜设备端上不能使用随机函数,于是我只能放弃,后面如果我能实现并行的话会在后面更新的。
目前实现代码的思路:
实现后的代码:
#include <windows.h>
#include <stdio.h>
#include<stdlib.h>
#define size 10000//抽奖的次数
#define A 10
#define B 5
int main() {
int b[11][2] = { {50,0},{55,0},{60,0},{65,0},{70,0},{75,0},{80,0},{85,0},{90,0},{95,0},{100,0}};
int a[size][21];
DWORD seed = GetTickCount64();
srand(seed);
for (int i = 0; i < size; i++) {
int A_num = 10;
int B_num = 10;
for (int j = 0; j < 20; j++) {
if (rand(seed) % 2 == 0)
{
A_num--;
if(A_num>=0)
a[i][j] = A;
else
{
a[i][j] = B;
}
}
else
{
B_num--;
if (B_num >= 0)
a[i][j] = B;
else
{
a[i][j] = A;
}
}
a[i][20] = 0;
}
}
//for (int i = 0; i < size; i++) {
// for (int j = 0; j < 20; j++) {
// printf("%d ",a[i][j]);
// }
// printf("\n");
//}
DWORD seed2 = GetTickCount64();
srand(seed2);
for (int i = 0; i < size; i++) {
int flag = 20;
for (int j = 0; j < 10; j++) {
int n=(rand() % flag);//随机出来的数.
// printf("%d ", n);
a[i][20] += a[i][n];
flag--;
for (int x = n; x < 20; x++) {
a[i][x] = a[i][x + 1];
}
}
//printf("%d \n", a[i][20]);
for (int j = 0; j < 10; j++) {
if (a[i][20] == b[j][0])
{
b[j][1]++;
}
}
}
for (int j = 0; j < 10; j++) {
printf("抽奖结果是%d的次数是:%d\n", b[j][0], b[j][1]);
}
return 0;
}
用10000次模拟抽奖的结果如下:
脸特别黑,模拟了好几十次只抽中过一次50分的情况,所以是天上不会掉馅饼滴!
3月9日 更新了并行化的计算结果,并行优化效果并不明显,而且计算结果和串行比较起来明显是错误的
#include <windows.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include<stdlib.h>
#include <stdio.h>
#include<time.h>
//guesss what am I doing now,is any sense of it?
//*cought
//this game living is will be much fun to me:)
#define A 10
#define B 5
#define size 12000
struct Balls {
int score[20];//球上面的分值
int result;
int number[20];//在host端计算好10个随机数,在设备端直接使用
//为了保证概率,随机数每次最大值为20,19,18……;
};
__global__ void draw(Balls* p, int* b) {
int tid = threadIdx.x + blockDim.x * blockIdx.x;
// printf("blockDim.x=%d blockIdx.x=%d threadIdx.x=%d\n", blockDim.x, blockIdx.x, threadIdx.x);
for (int i = 0; i < 10; i++) {
p[tid].result += p[tid].score[p[tid].number[i]];
for (int x = p[tid].number[i]; x < 20; x++) {
p[i].score[x] = p[i].score[x + 1];
}
}
// printf("%d ", p[tid].result);
for (int j = 0; j < 11; j++)
{
if (b[j] == p[tid].result)
atomicAdd(&b[j + 11], 1);
}
}
int chuanxing() {
int b[11][2] = { {50,0},{55,0},{60,0},{65,0},{70,0},{75,0},{80,0},{85,0},{90,0},{95,0},{100,0} };
int a[size][21];
DWORD seed = GetTickCount64();
srand(seed);
for (int i = 0; i < size; i++) {
int A_num = 10;
int B_num = 10;
for (int j = 0; j < 20; j++) {
if (rand() % 2 == 0)
{
A_num--;
if (A_num >= 0)
a[i][j] = A;
else
{
a[i][j] = B;
}
}
else
{
B_num--;
if (B_num >= 0)
a[i][j] = B;
else
{
a[i][j] = A;
}
}
a[i][20] = 0;
}
}
//for (int i = 0; i < size; i++) {
// for (int j = 0; j < 20; j++) {
// printf("%d ",a[i][j]);
// }
// printf("\n");
//}
DWORD seed2 = GetTickCount64();
srand(seed2);
for (int i = 0; i < size; i++) {
int flag = 20;
for (int j = 0; j < 10; j++) {
int n = (rand() % flag);//随机出来的数.
// printf("%d ", n);
// printf("%d \n", a[i][n]);
a[i][20] += a[i][n];
flag--;
for (int x = n; x < 20; x++) {
a[i][x] = a[i][x + 1];
}
}
//printf("%d \n", a[i][20]);
for (int j = 0; j < 10; j++) {
if (a[i][20] == b[j][0])
{
b[j][1]++;
}
}
}
for (int j = 0; j < 10; j++) {
printf("抽奖结果是%d的次数是:%d\n", b[j][0], b[j][1]);
}
return 0;
}
int bingxing() {
cudaEvent_t stop, start;
cudaEventCreate(&start);
cudaEventCreate(&stop);
float elapsedTime = 0;
cudaEventRecord(start, 0);
Balls* p = (Balls*)malloc(sizeof(Balls) * size);
//格式:
//p[0].score[0] = 0;
DWORD seed = GetTickCount64();
srand(seed);
for (int i = 0; i < size; i++) {
int A_num = 10;
int B_num = 10;
int flag = 20;
for (int j = 0; j < 20; j++) {
int n = (rand() % flag);//随机出来的数.
// printf("%d ", n);
flag--;
p[i].number[j] = n;
if (rand() % 2 == 0)
{
A_num--;
if (A_num >= 0)
p[i].score[j] = A;
else
{
p[i].score[j] = B;
}
}
else
{
B_num--;
if (B_num >= 0)
p[i].score[j] = B;
else
{
p[i].score[j] = A;
}
}
}
p[i].result = 0;
// printf("\n");
}
int block_num = 1024;
int grid_num = (size + block_num - 1) / block_num;
// printf("%d", grid_num);
int* b;
b = (int*)malloc(sizeof(int) * 25);
for (int i = 0; i < 11; i++) {
b[i] = 50 + i * 5;
b[i + 11] = 0;
}
Balls* d_p;
int* d_b;
cudaMalloc((void**)&d_b, sizeof(int) * 25);
cudaMemcpy(d_b, b, sizeof(int) * 25, cudaMemcpyHostToDevice);
cudaMalloc((Balls**)&d_p, sizeof(Balls) * size);
cudaMemcpy(d_p, p, sizeof(Balls) * size, cudaMemcpyHostToDevice);
//grid_num必须要大于block!!!
draw << <grid_num, block_num,0 >> > (d_p, d_b);
cudaDeviceSynchronize();
cudaMemcpy(p, d_p, sizeof(Balls) * size, cudaMemcpyDeviceToHost);
cudaMemcpy(b, d_b, sizeof(int) * 25, cudaMemcpyDeviceToHost);
for (int j = 0; j < 11; j++) {
printf("抽奖结果是%d的次数是:%d\n", b[j], b[j + 11]);
}
cudaFree(d_b);
cudaFree(d_p);
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&elapsedTime, start, stop);
// printf("串行使用的时间是:%lf\n", elapsedTime);
return 0;
}
void main() {
time_t t_start, t_end;
t_start = time(NULL);
chuanxing();
t_end = time(NULL);
printf("串行时间是: %.0f s\n", difftime(t_end, t_start));
time_t t_start2, t_end2;
t_start2 = time(NULL);
bingxing();
t_end2 = time(NULL);
printf("并行时间是: %.0f s\n", difftime(t_end2, t_start2));
}