今天的作业,想到可以直接由浮点数格式中取出尾数得到ShannanCode,麻烦点的地方是需要重新对阶,因为在尾数规格化省掉了一位,最终效率比较高。
#ifndef SHANNAN_CODE_DEF_200609
#define SHANNAN_CODE_DEF_200609
typedef unsigned long U32;
typedef signed char S8;
class CShannan
{
float *m_p;//消息概率
float *m_sp;//累计概率P
float *m_i;//信息量
int *m_length;//码长
U32 *m_code;
int m_n;
public:
static int cpux86();
public:
CShannan(int n);
~CShannan();
void InputPro();
void OutputCode();
};
#endif
#include "stdio.h"
#include "assert.h"
#include "math.h"
#include "shannan.h"
#ifndef NULL
#define NULL 0
#endif
CShannan::CShannan(int n)
{
assert(n>0);
m_n=n;
m_p=new float[n];
m_sp=new float[n];
m_i=new float[n];
m_length=new int[n];
m_code =new U32[n];
assert(m_p!=NULL);
assert(m_sp!=NULL);
assert(m_i!=NULL);
assert(m_length!=NULL);
assert(m_code!=NULL);
}
CShannan::~CShannan()
{
if(m_p)
delete[]m_p;
if(m_sp)
delete[]m_sp;
if(m_i)
delete[]m_i;
if(m_length)
delete[]m_length;
if(m_code)
delete[]m_code;
}
int CShannan::cpux86()
{
union
{
char a[2];
short int b;
}test;
test.b=1;
if(test.a[0]==1)
return 1;//低位在前
return 0;//高位在前
//test needed
}
void CShannan::InputPro()
{
float last=1.0f;
int i;
for(i=0;i<m_n-1;++i)
{
while(1)
{
printf("输入第%d个消息概率:",i+1);
scanf("%f",m_p+i);
if(m_p[i]<last)
{
last-=m_p[i];
break;
}
else
{
printf("错误,输入概率值必须小于%.4f\n",last);
}
}
}
m_p[m_n-1]=last;
printf("第 %3d 个消息概率值为 %.4f\n开始香农编码...\n",m_n,last);
//Shannan Code
//Sort
for(i=0;i<m_n;++i)
{
for(int j=i+1;j<m_n;++j)
{
if(m_p[j]>m_p[i])
{
float tmp=m_p[i];
m_p[i]=m_p[j];
m_p[j]=tmp;
}
}
}
float a=(float)(-1.0/log(2.0));
for(i=0;i<m_n;++i)
{
m_sp[i]=i>0?m_sp[i-1]+m_p[i-1]:0.0f;
float inf=(float)(a*log(m_p[i]));
m_i[i]=inf;
m_length[i]=(int)inf;
if((float)m_length[i]<inf)
++m_length[i];
}
//由IEEE-754浮点数存储格式标准,直接由累加概率值中取出CODE
for(i=0;i<m_n;++i)
{
U32 *d=(U32*)(m_sp+i);
S8 move=(S8)(((((*d) >> 23) & 0xFF) + 0x1) ^ 0x80);//得到移阶码对应的补码,单精度型的偏移量是0x7F
m_code[i]=(((*d) & 0x7FFFFF) | 0x800000) >> (-move-1);//补上隐含位并对阶后的尾数
}
//End Code
printf("编码完毕!\n");
}
void CShannan::OutputCode()
{
printf("-=-=-=-=-=-=-\n香农编码结果:\n-=-=-=-=-=-=-\n");
printf("消息序号si 消息概率p(si) 累加概率Pi -log p(si) 代码组长度li 二进制代码组\n");
for(int i=0;i<m_n;++i)
{
printf(" s%-5d %-10.4f %-8.4f %-8.4f %-7d ",i+1,m_p[i],m_sp[i],m_i[i],m_length[i]);
for(int j=0;j<m_length[i];++j)
{
if((m_code[i] >> (23-j)) & 0x1)
printf("1");
else
printf("0");
}
printf("\n");
}
}
#include "shannan.h"
#include <stdio.h>
int main()
{
int n;
printf("输入消息符号个数N:");
scanf("%d",&n);
CShannan scode(n);
scode.InputPro();
scode.OutputCode();
return 0;
}
运行结果:
输入消息符号个数N:7
输入第1个消息概率:0.2
输入第2个消息概率:0.1
输入第3个消息概率:0.01
输入第4个消息概率:0.9
错误,输入概率值必须小于0.6900
输入第4个消息概率:0.19
输入第5个消息概率:0.18
输入第6个消息概率:0.15
第 7 个消息概率值为 0.1700
开始香农编码...
编码完毕!
-=-=-=-=-=-=-
香农编码结果:
-=-=-=-=-=-=-
消息序号si 消息概率p(si) 累加概率Pi -log p(si) 代码组长度li 二进制代码组
s1 0.2000 0.0000 2.3219 3 000
s2 0.1900 0.2000 2.3959 3 001
s3 0.1800 0.3900 2.4739 3 011
s4 0.1700 0.5700 2.5564 3 100
s5 0.1500 0.7400 2.7370 3 101
s6 0.1000 0.8900 3.3219 4 1110
s7 0.0100 0.9900 6.6439 7 1111110
评论