今天的作业,想到可以直接由浮点数格式中取出尾数得到ShannanCode,麻烦点的地方是需要重新对阶,因为在尾数规格化省掉了一位,最终效率比较高。 #ifndef SHANNAN_CODE_DEF_200609#define SHANNAN_CODE_DEF_200609typedef 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#endifCShannan::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标准格式

评论