正文

香农编码2006-09-20 20:52:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/rickone/18604.html

分享到:

今天的作业,想到可以直接由浮点数格式中取出尾数得到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

参考:单双精度浮点数的IEEE标准格式

阅读(13194) | 评论(5)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册