基于C语言的产生任意均值与方差的正态分布的随机数,生成的随机数可基于任意范围或指定范围

1.目的

        因为项目需要,需要产生一串随机数,此随机数非均匀分布,而是基于正态分布,同时该随机数需要在指定区间内。

 2.结果展示

        我的项目中,希望产生一个正态分布的随机数,范围在[20,240],那么正态分布的均值就是130((20+240)/2),经过不断调试结果,设置标准差为50。

         上图就是产生的范围在20~240之间的符合正态分布的随机数。

          假如不设置取值范围。见下图:

        改变标准差到100,让其变得更“胖”。效果如下:

        通过上述展示,达到了设计目的。

3.实现

3.1 源码

/*
# THIS FILE IS PART OF RANDN PROJECT
# randn - The core part of the GCC
# THIS PROGRAM IS UNFREE SOFTWARE, IS LICENSED UNDER Ding Zhenjin(dingzj2000@163.com)
# YOU SHOULD HAVE RECEIVED A COPY OF RANDN LICENSE, IF NOT, PLEASE DO NOT USE.
#YOU SHOULD BUY THE COPYRIGHT
# Copyright (c) 1987-2087
# Copyright (c) 2021 Ding Zhenjin(dingzj2000@163.com)
*/

/*
2021.7.9
任意范围的正态分布随机数
环境:Ubuntu32 16.04.1  cairo库实现
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cairo.h>

#include <math.h>
#include <time.h>

#include "randn.h"

/* 采集样本数量 */
#define N 100

/*
背景图标是1300*600
*/

/* 原点坐标 */
#define OriginX    650  //原点居中
#define OriginY    20

/* 坐标转换 */
#define X(n)     ((n)*1.0)
#define Y(n)     ((600-(n))*1.0)

/* 坐标系内位置 */
#define PosX(n)  (X(OriginX+(n)))
#define PosY(n)  (Y(OriginY+(n)))

#define ANGLE(ang)  (ang * 3.1415926 / 180.0)


#define OFFSET    600

struct POS{
	int x;
	int y;
};

cairo_surface_t *image_surface_create_from_png(const char *filename)
{
	cairo_status_t cst;

	cairo_surface_t *image_sf=cairo_image_surface_create_from_png(filename);
	cst = cairo_surface_status (image_sf);
	if (cst!=CAIRO_STATUS_SUCCESS)
	{
		printf(	"failed to cairo_image_surface_create_from_png cairo_status_t is:%d file: %s",cst, filename);
		image_sf = NULL;
		//if (cst == CAIRO_STATUS_NO_MEMORY) {
			//image_sf = cairo_image_surface_create_from_jpeg(filename);
		//}
	}
	return image_sf;
}



void draw_png2surface(cairo_t *cr, double x, double y, cairo_surface_t *surface){
	if(surface != NULL){
		cairo_set_source_surface(cr, surface, x, y);
		cairo_paint(cr);
	}
}

/*
创建背景
*/
void createBackground(cairo_t *cr,char *file)
{
	cairo_surface_t  *g_background;

	if(cr == NULL || file == NULL)
	{
		return;
	}

	/* 背景图 */
	g_background = image_surface_create_from_png(file);
	draw_png2surface(cr, 0, 0, g_background);
}

/*
构建坐标系
*/
void createCoordinate(cairo_t *cr)
{
	char tempbuf[64];

	if(cr == NULL)
	{
		return;
	}

	/* 划线 */
	cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);/* 设置颜色 -黑色 */
	cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
	cairo_set_line_width (cr, 1.0);
	cairo_move_to (cr, X(OriginX-OFFSET), Y(OriginY));//X轴
	cairo_line_to (cr, X(OriginX+OFFSET), Y(OriginY));
	cairo_stroke (cr);

	cairo_move_to (cr, X(OriginX), Y(OriginY));//Y轴
	cairo_line_to (cr, X(OriginX), Y(OriginY+550));
	cairo_stroke (cr);

	/* 量程 */
	cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size (cr, 15.0);
	//原点
	cairo_move_to (cr, X(OriginX-5), Y(OriginY-15));
	cairo_show_text (cr, "0");

	//负X轴
	cairo_move_to (cr, X(OriginX-OFFSET-15), Y(OriginY-15));
	sprintf(tempbuf,"%d",-OFFSET);
	cairo_show_text (cr, tempbuf);
	//正X轴
	cairo_move_to (cr, X(OriginX+OFFSET-15), Y(OriginY-15));
	sprintf(tempbuf,"%d",OFFSET);
	cairo_show_text (cr, tempbuf);


	//Y轴
	cairo_move_to (cr, X(OriginX-10), Y(OriginY+550+5));
	cairo_show_text (cr, "550");
	cairo_stroke (cr);
}


/*
构建坐标点
*/
void createPoints(cairo_t *cr,int x,int y)
{
	char buf[64];

	if(cr == NULL)
	{
		return;
	}

	cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);/* 设置颜色 -蓝色 */
	cairo_set_line_width(cr, 1);
	cairo_arc(cr, PosX(x), PosY(y), 1, ANGLE(0), ANGLE(360));
	cairo_stroke (cr);

	/* 显示坐标 */
	memset(buf,0x00,sizeof(buf));
	sprintf(buf,"(%d,%d)",x,y);
	cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);/* 设置颜色 -黑色 */
	cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
	cairo_set_font_size (cr, 2.0);
	cairo_move_to(cr,PosX(x-8), PosY(y+8));
	cairo_show_text (cr, buf);
	cairo_stroke (cr);
}

/*
构建坐标系Y直线

*/
void createLine(cairo_t *cr,int start_x,int start_y,int end_x,int end_y)
{
	if(cr == NULL)
	{
		return;
	}


	/* 划线 */
	cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);/* 设置颜色 -红色 */
	cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
	cairo_set_line_width (cr, 1.0);
	cairo_move_to (cr, PosX(start_x), PosY(start_y));
	cairo_line_to (cr, PosX(end_x), PosY(end_y));
	cairo_stroke (cr);
}

/*
创建正态分布曲线
*/
void createNormalCurve(cairo_t *cr,int start_x,int start_y,int end_x,int end_y)
{

}

/*
指数和对数函数测试
*/
int mathTest(void)
{
	printf("pow(x,y) x= 10,y=2  value=%lf\n",pow(10.0,2.0));
	printf("powl(x,y) log x=10,y=100  value=%lf\n",powf(100.0,2.0));

	printf("exp(x) e x=1  value=%f\n",exp(1));
	printf("exp(x) e x=2  value=%f\n",exp(2));

	printf("loge=%f\n",log(10)); //以e为底的对数函数
	printf("loge=%f\n",log(2.718282)); //以e为底的对数函数
	printf("log10=%f\n",log10(100)); //以10为底的对数函数

	printf("sqrt=%f\n",sqrt(16));//平方根
}


int main(int argc,char *argv[])
{
	int rand_sum[OFFSET*2+1]={0};
	int i,j,i_randn;

	double u,g,r,o,d_randn,dec;


	/************************ 创建cairo ****************************/
	cairo_surface_t *surface =	cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1300, 600);
	cairo_t *cr = cairo_create (surface);

	/*********************** 创建背景 *****************************/
	createBackground(cr,"background.png");

	/*********************** 构建坐标系 *****************************/
	createCoordinate(cr);


	/**************************** 设置随机数种子 ***************************/
	/* 最同一轮显示效果中,随机数种子应该保持一致!!!! */
	srand(time(0));
	r = rand();
	//r = 5.0;//

	/**************************** 正态分布参数设置 ***************************/
	u = 130.0;//均值
	g = 100;   //标准差

	/**************************** 设置随机数范围 ***************************/
	o = 0.0;  //设置为0,表示为生成的随机数在任意范围,非0,表示产生的随机数在[u-o,u+o]之间

	for(i = 0; i < 12000; i++)
	{
		for(j = 0; j < 5; j++)
		{
			d_randn = randn(u,g,&r);
			printf("%10.7lf ",d_randn);

			//设置随机数范围
			if(o != 0.0)
			{
				if(d_randn < u-o || d_randn > u+o)
				{
					continue;
				}
			}

			i_randn = (int)d_randn;
			dec = d_randn-i_randn;
			if(dec > 0.5)
			{
				i_randn++;
			}

			if(i_randn >= -OFFSET && i_randn  <= OFFSET)
			{
				rand_sum[OFFSET+i_randn] = rand_sum[OFFSET+i_randn]+1;
			}
		}

		printf("\n");
	}

	/************************ 对找出的随机数进行绘点 ****************************/
	for(i = 0; i < sizeof(rand_sum)/sizeof(int); i++)
	{
		if(rand_sum[i] == 0)
		{
			continue;
		}

		createLine(cr,i-OFFSET,0,i-OFFSET,rand_sum[i]);
	}

	/************************ 创建图片 ****************************/
	cairo_surface_write_to_png (surface, "randn.png");

	/************************ 销毁cairo ****************************/
	cairo_destroy (cr);
	cairo_surface_destroy (surface);

	return 0;
}

3.2 cairo库

        基于Linux C编程,图像显示使用cairo库。至于如何使用不在本文论述的重点。详见:

        https://blog.csdn.net/dingzj2000/article/details/103719104

3.3 随机数种子

        谈到随机数,必然有随机数种子,代码里用时间产生种子,是为了每一轮结果(一轮60000个点)产生不同的效果。在我的项目中,一轮是从开机到关机整个流程,在设置好初始随机数种子后,就不要在改变。

	/**************************** 设置随机数种子 ***************************/
	/* 最同一轮显示效果中,随机数种子应该保持一致!!!! */
	srand(time(0));
	r = rand();
	//r = 5.0;//

3.4 显示原理

        产生的随机数是浮点型,然后强制转换为整型,这个整型对应的像素坐标就加1,在一轮显示后,显示所有像素。

        因为浮点型强制转换为整型,简单做了一个四舍五入。在实际项目中可以不用。

i_randn = (int)d_randn;
dec = d_randn-i_randn;
if(dec > 0.5)
{
	i_randn++;
}

if(i_randn >= -OFFSET && i_randn  <= OFFSET)
{
	rand_sum[OFFSET+i_randn] = rand_sum[OFFSET+i_randn]+1;
}

3.5 函数参数定义

        double randn(double u,double g,double *r)

        参数比较简单:

        u是正态分布平均值;

        g是正态分布标准差;

        *r是随机数种子

/**************************** 正态分布参数设置 ***************************/
u = 130.0;//均值
g = 100;   //标准差

/**************************** 设置随机数范围 ***************************/
o = 0.0;  //设置为0,表示为生成的随机数在任意范围,非0,表示产生的随机数在[u-o,u+o]之间

3.6 输出结果打印

        

4.核心算法

       

5.

加微信(微信号:dingzj2000),获取详细算法。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值