首页 > 范文大全 > 正文

嵌入式Linux平台下随机序列算法的设计

开篇:润墨网以专业的文秘视角,为您筛选了一篇嵌入式Linux平台下随机序列算法的设计范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

【摘 要】本文以多媒体播放器的随机不重复播放机能为切入点,针对嵌入式平台实时性要求高,处理速度不够快,但系统存储歌曲量大的特点,进行随机序列产生算法的设计和实现,并在ARM linux平台下进行算法的设计检证。

【关键词】嵌入式;Linux;随机序列;播放

0 背景

随着近几年嵌入式系统总体能力的提升,嵌入式多媒体应用越来越丰富。从低端的MP3播放器,中端的workman,到高端的智能手机,音乐播放功能已经成为系统默认具备的功能。

嵌入式系统的存储能力已经跨入G时代。随身可携带的歌曲数量从几十首,已经上升至几百首,甚至上万首。

随机播放机能存在一种需求,要将播放列表中的歌曲随机播放一遍,在所有歌曲都播放一遍之前,不能出现有重复播放的情况。

1 嵌入式系统的特点

嵌入式系统的能力现在虽然已经提升不少,但和个人计算机相比较,运算能力仍然无法匹敌个人计算机。并且还存在以下几种嵌入式系统特有的特点:

*运算数据通常不能被交换到外部存储设备上,程序可以使用的内存无法超过物理内存容量。

*人机交互需要快速的实时响应,耗时过长的程序给用户较差的性能体验。

*外部存储器多为FLASH设备,写入寿命有限制,程序设计需要尽可能减少FLASH的写操作。

因此,在嵌入式系统中,随机播放的算法需要在时间以及空间的设计中,获得一个平衡,这样才能让用户有最好的体验。

2 算法的目标

*需要随机播放的总数是可变化。

*在总数给定的情况下,随机产生的序列不能出现重复。

*时间和空间使用是平衡的,满足嵌入式系统的特点。

3 解决方案

为了能够达成上述目标,主要采用下面几种技术方案:

*将随机序列的产生,分配到每一次歌曲切换的时候,而不是在初始化的过程中全部生成。

*将随机序列中某一个随机数的产生,分解为按照16进制数位分别产生,避免因为歌曲总量的提高导致时间出现指数级别的增长,尽可能控制为线性增长。

*采用bitmap标示已经产生的随机数。

*采用用时申请的方式动态申请内存。

*记录随机序列产生的结果,并提供回溯查询功能。

基于上面的技术方案,在本设计中将整体算法划分为两个部分:

*随机数列产生器,用于产生不重复的随机数列。

*随机数列记录器,用于记录已经随机数列,并向外部提供访问接口。

4 数据结构设计

4.1 顶层数据结构

顶层数据结构(shuffle_t)包含随机数列产生器和随机数列记录器。

下面是数据结构定义:

typedef struct _shuffle_t {

/* 随机数列的最大值 */

int max;

/* 随机数列产生器 */

random_t *random;

/* 随机数列记录器 */

sequence_t *sequence;

}shuffle_t;

在内存中的数据关系如图1所示。

图1 顶级数据结构示意图

4.2 随机数列产生器数据结构

随机数列产生器的数据结构(random_t)包含三个部分:

*动态增长的bitmap池。

*优化的16以内的随机数产生器。

*按数位顺序产生,代有检测功能的随机数列控制器。

下面是数据结构定义:

/*双向循环链表 */

typedef struct _chain_t {

/* 前一个链表 */

struct _chain_t *prev;

/* 后一个链表 */

struct _chain_t *next;

}chain_t;

/* digit池的描述头 */

typedef struct _pool_head_t {

/* 双向循环链表 */

chain_t chain;

/* 当前digit池的总数 */

int total;

/* 当前digit池已使用个数 */

int used;

/* digit池首地址 */

char *data;

}pool_head_t;

/* digit池总入口 */

typedef struct _pool_t {

/* bitmap池中,一个bitmap单位的大小 */

int block_size;

/* bitmap池双向链表的表头 */

chain_t chain;

}pool_t;

/* 16以内随机数产生器 */

typedef struct _hex_random_t {

/* /dev/urandom 文件描述符 */

int fd;

/* 16以内随机数缓存: 128个 */

int seed[16];

/* 16以内随机数缓存使用位置 */

int position;

}hex_random_t;

/* 16进制数位点阵图 */

typedef struct _digit_t {

/* 当前数位在16进制数位的位置 */

int offset;

/* 点阵图 */

int bitmap;

/* 低阶数位的digit首地址 */

struct _digit_t *lower_digit[ 16 ];

}digit_t;

/* 随机数列产生器 */

typedef struct _random_t {

/* 随机数最大值 */

int max;

/* digit池总入口 */

pool_t pool;

/* 16以内随机数产生器 */

hex_random_t hex_random;

/* 随机数最大值的16进制位数 */

int digit_total;

/* 最高阶digit首地址 */

digit_t *digit_root;

}random_t;

在内存中的数据关系如图2所示。

图2 随机数列产生器数据结构示意图

当随机数列最大值为255,并且32至255已经都产生时,随机数列产生器数据结构信息如图3所示。

图3 随机数列产生器数据结构示意图(特例)

4.3 随机数列记录器数据结构

随机数列记录器的数据结构(sequence_t)包含两个部分:

* 动态增长的记录数组

* 游标

下面是数据结构定义:

/* 随机数列记录器 */

typedef struct _sequence_t {

/* 记录器的最大值 */

int index_max;

/* 记录器的当前值 */

int index_current;

/* 记录块中的条目数 */

int index_per_block;

/* 记录块的总数 */

int block_total;

/* 记录块首地址的数组 */

int **block_vector;

}sequence_t;

在内存中的数据关系如图4所示。

图4 随机数列记录器数据结构示意图

5 关键算法流程图

某一个随机数的产生,是按照数位从高到低产生的,只有在最大数值范围内的随机数,并且是新的随机数才是合法的随机数。

因此,即使是32位范围的随机数,也只有8个数位,采取递归调用的方式并不会因为函数层次太深而占用太多的堆栈,并且代码实现比较方便。

图5至图7,采用软件设计中通用的PAD图,直观的展示了随机数列中某一个随机数的产生流程。

图5 某一个随机数产生函数PAD图

6 测试结果

在 S5PV210 开发板上进行测试,(CPU为cortex-A8 1G ARM单核处理器, 内存为200Mhz 512M的DDR2),重复产生最大值分别为15,255,4095和65535的随机数列1000次,并记录下随机数列的总体消耗时间、平均消耗时间以及某一个随机数产生的最大消耗时间。

表1和表2是测试结果。单位是微秒。

表1 测试结果1

表2 测试结果2

7 结束语

从测试结果可以看到,总体耗时和随机数列的最大值成正比;而平均耗时和数位的个数成正比;最大耗时不固定,基本上也体现出和随着数位个数增加。

平均产生一个随机数为几个纳秒,最大可能为几个毫秒。在嵌入式Linux平台下,已经基本达成算法的目标。

【参考文献】

[1]严蔚敏,吴伟民.数据结构:C语言版[M].北京:清华大学出版社,1996.

[2]韦东山.嵌入式Linux应用开发完全手册[M].北京:人民邮电出版社,2008.

[3]谭浩强.C程序设计[M].2版.北京:清华大学出版社,1999.