精华内容
下载资源
问答
  • 信息论实验-信源编码2(Lz编码和算数编码的C++实现)

    万次阅读 多人点赞 2017-08-13 17:21:36
    上一篇文章给出了Huffman编码和Shannon Fano编码编码原理以及C++的程序,程序可以用来实现给任意类型的文件进行无损压缩,缺点是比较耗时,不能作为正常的通用压缩软件来使用,但是作为算法理解,算法思路是没有...

    上一篇文章给出了Huffman编码和Shannon Fano编码的编码原理以及C++的程序,程序可以用来实现给任意类型的文件进行无损压缩,缺点是比较耗时,不能作为正常的通用压缩软件来使用,但是作为算法理解,算法思路是没有问题的,后续可能需要进行优化,下面的LZ编码和算数编码和Huffman、Fano编码是走的截然不同的道路,他们的思想差别很大,但却殊途同归,在算法理解上我借助了一些网友前辈的博客中的例子,文章最后我也会指出引用了那些文章,谢谢前辈们给出的经典的例子能让晚辈站在巨人的肩膀上,所以在此声明,希望我的引用不会侵犯到前辈们的权益
    * 先上源代码*
    信源编码源代码

    第三章:算数编码的实现

    一. 算数编码的原理

    算数编码不同于Huffman编码,它是非分组(非块)码。它从全序列出发,考虑符号之间的依赖关系来进行编码的。
    算数编码主要的编码方法正是计算输入信源符号序列所对应的区间。术编码的基本原理是将编码的消息表示成实数0和1之间的一个间隔(Interval),消息越长,编码表示它的间隔就越小,表示这一间隔所需的二进制位就越多。
    算术编码用到两个基本的参数:符号的概率和它的编码间隔。信源符号的概率决定压缩编码的效率,也决定编码过程中信源符号的间隔,而这些间隔包含在0到1之间。编码过程中的间隔决定了符号压缩后的输出。
    给定事件序列的算术编码步骤如下:
    (1)编码器在开始时将“当前间隔” [ L, H) 设置为[0,1)。
    (2)对每一事件,编码器按步骤(a)和(b)进行处理
    (a)编码器将“当前间隔”分为子间隔,每一个事件一个。
    (b)一个子间隔的大小与下一个将出现的事件的概率成比例,编码器选择子间隔对应于下一个确切发生的事件相对应,并使它成为新的“当前间隔”。
    (3)最后输出的“当前间隔”的下边界就是该给定事件序列的算术编码。
    设Low和High分别表示“当前间隔”的下边界和上边界,CodeRange为编码间隔的长度,LowRange(symbol)和HighRange(symbol)分别代表为了事件symbol分配的初始间隔下边界和上边界。算术编码也是一种对错误很敏感的编码方法,如果有一位发生错误就会导致整个消息译错。
    算术编码可以是静态的或者自适应的。在静态算术编码中,信源符号的概率是固定的。在自适应算术编码中,信源符号的概率根据编码时符号出现的频繁程度动态地 进行修改,在编码期间估算信源符号概率的过程叫做建模。需要开发动态算术编码的原因是因为事先知道精确的信源概率是很难的,而且是不切实际的。当压缩消息 时,我们不能期待一个算术编码器获得最大的效率,所能做的最有效的方法是在编码过程中估算概率。因此动态建模就成为确定编码器压缩效率的关键。

    二. 算数编码过程

    假设有信源符号{A, B. C, D}, 对应的概率和初始编码间隔如下表所示

    符号ABCD
    概率01.0.40.20.3
    初始编码间隔[0, 0.1)[0.1, 0.5)[0.5, 0.7)[0.7, 1)

    如果二进制消息序列的输入为:CADACDB。编码时首先输入的符号是C, 找到他的编码范围是[0.5, 0.7)。由于消息由于消息中第二个符号A的编码范围是[0, 0.1),因此它的间隔就取[0.5, 0.7)的第一个十分之一作为新间隔[0.5, 0.52)。依此类推,编码第3个符号D时取新间隔为[0.514, 0.52),编码第4个符号A时,取新间隔为[0.514, 0.5146),…。消息的编码输出可以是最后一个间隔中的任意数
    编码过程如下表所示
    表3.2 算数编码的编码过程

    步骤输入符号编码间隔编码判决
    1C[0.5, 0.7]符号的间隔范围[0.5, 0.7]
    2A[0.5, 0.52][0.5, 0.7]间隔的第一个1/10
    3D[0.514, 0.52][0.5, 0.52]间隔的最后一个1/10
    4A[0.514, 0.5146][0.514, 0.52]间隔的第一个1/10
    5C[0.5143, 0.51442][0.514, 0.5146]间隔的第五个1/10开始,二个1/10
    6D[0.514384, 0.51442][0.5143, 0.51442]间隔的最后3个1/10
    7B[0.5143836,0.514402][0.514384,0.51442]间隔的4个1/10,从第1个1/10开始
    8从[0.5143876, 0.514402]中选择一个数作为输出:0.5143876

    译码过程如下表
    表3.3 算数编码的译码过程

    步骤间隔译码符号译码判决
    1[0.5, 0.7]C0.51439在间隔 [0.5, 0.7)
    2[0.5, 0.52]A0.51439在间隔 [0.5, 0.7)的第1个1/10
    3[0.514, 0.52]D0.51439在间隔[0.5, 0.52)的第7个1/10
    4[0.514, 0.5146]A0.51439在间隔[0.514, 0.52]的第1个1/10
    5[0.5143, 0.51442]C0.51439在间隔[0.514, 0.5146]的第5个1/10
    6[0.514384, 0.51442]D0.51439在间隔[0.5143, 0.51442]的第7个1/10
    7[0.51439,0.5143948]B0.51439在间隔[0.51439, 0.5143948]的第1个1/10
    8译码的消息:C A D A C D B

    三. 算数编码的实现

    这几种算法唯独算数编码我没有用C++实现,当时记得为了应付课堂作业,借用了网上一位博友的代码,大家如果想借鉴这个算法实现的代码,我这里可以给出我更改后的版本,但并不是我原创的,但是很抱歉具体是在哪里借鉴的我忘记了,当时比较草率,没有想太多,这里我还是把过程及测试结果给大家介绍清楚,代码的话如果能找到原主人最好不过了,这里我给出我改过的版本。
    算数编码我只是使用字符串进行了测试,不能做到像Huffman编码一样对任何类型的文件都进行编码和译码。
    主函数

    int main()
    {
        string str; //输入要编码的String类型字符串
        int number = 0, size = 0; //number--字符串中不重复的字符个数;size--字符串长度 
        char c[N]; //用于存储不重复的字符
        long double p[N], output; //p[N]--不重复字符的概率,output--编码结果 
        disp();
        cout << "输入要编码的字符串:";
        getline(cin, str); //输入要编码的字符串
        size = str.length(); //字符串长度
        number = proba(str, c, p, size);//调用求概率函数,返回不重复字符的个数
        cout.setf(ios::fixed); //“魔法配方”规定了小数部分的个数
        cout.setf(ios::showpoint); //在此规定编码结果的小数部分有十个
        cout.precision(10);//调用编码函数,返回编码结果
        output = bma(c, p, str, number, size);//调用译码函数,输出要编码的字符串,
        yma(str, c, p, number, size, output); //以验证编码是否正确   
        getchar();
        return 0;
    }

    特殊结构和功能函数的定义

    #define N 100 //输入的字符应该不超过50个
    struct L //结构用于求各字符及其概率
    {
        char ch; //存储出现的字符(不重复)
        int num; //存储字符出现的次数
        double f;//存储字符的概率
    };
    //显示信息
    void disp();
    //求概率函数,输入:字符串;输出:字符数组、字符的概率数组;返回:数组长度; int proba(string str,char c[],long double p[],int count);
    //求概率的辅助函数
    int search(vector<L> arch, char, int n);
    long double bma(char c[], long double p[], string str, int number, int size);
    int proba(string str, char c[], long double p[], int count);
    //编码函数,输入:字符串,字符数组,概率数组,以及数组长度;输出:编码结果 long double bma(char c[],long double p[],string str,int number,int size);
    //译码函数,输入:编码结果,字符串,字符数组,概率数组,以及它们的长度;输出:字符串
    //该函数可以用于检测编码是否正确
    void yma(string str, char c[], long double p[], int number, int size, long double input);
    
    void disp()
    
    {
    
        cout << endl;
        cout << "此程序只需要输入要编码的字符串,不需要输入字符概率\n";
        cout << endl;
    
    }
    
    //求概率函数
    
    int proba(string str, char c[], long double p[], int count)
    
    {
    
        cout.setf(ios::fixed); //“魔法配方”规定了小数部分位数为三位
        cout.setf(ios::showpoint);
        cout.precision(3);
        vector<L>pt; //定义了结构类型的向量,用于同时存储不重复的字符和其概率
        L temp; //结构类型的变量
        temp.ch = str[0]; //暂存字符串的第一个字符,它的个数暂设为1
        temp.num = 1;
        temp.f = 0.0;
        pt.push_back(temp); //将该字符及其个数压入向量
        for (int i = 1; i<count; i++)//对整个字符串进行扫描
    
        {
            temp.ch = str[i]; //暂存第二个字符
            temp.num = 1;
            temp.f = 0.0;
            for (int j = 0; j<pt.size(); j++) //在结构向量中寻找是否有重复字符出现
            { //若重复,该字符个数加1,并跳出循环 
                int k; //若不重复,则压入该字符,并跳出循环 
                k = search(pt, str[i], pt.size());
                if (k >= 0)
    
                {
                    pt[k].num++;
                    break;
                }
                else
                {
                    pt.push_back(temp);
                    break;
                }
    
            }
    
        }
        for (int i = 0; i<pt.size(); i++) //计算不重复字符出现的概率
        {
            pt[i].f = double(pt[i].num) / count;
        }
        int number = pt.size(); //计算不重复字符出现的次数
        cout << "各字符概率如下:\n";
        for (int i = 0; i<number; i++) //显示所得的概率,验证是否正确
        {
            if (count == 0)
            {
                cout << "NO sample!\n";
            }
            else
            {
                c[i] = pt[i].ch;
                p[i] = pt[i].f;
                cout << c[i] << "的概率为:" << p[i] << endl;
            }
        }
        return number; //返回不重复字符的个数
    }
    //求概率的辅助函数
    //若搜索发现有重复字符返回正数
    //否则,返回-1
    int search(vector<L> arch, char ch1, int n)
    {
        for (int i = 0; i<n; i++)
        {
            if (ch1 == arch[i].ch) return i;
        }
    return -1;
    }
    //编码函数
    long double bma(char c[], long double p[], string str, int number, int size)
    {
        long double High = 0.0, Low = 0.0, high, low, range;
        //High--下一个编码区间的上限,Low--下一个编码区间的下限;
        //high--中间变量,用来计算下一个编码区间的上限;
        //low--中间变量,用来计算下一个编码区间的下限;
        //range--上一个被编码区间长度
        int i, j = 0;
        for (i = 0; i<number; i++)
        {
            if (str[0] == c[i]) break; //编码第一个字符
        }
        while (j<i)
        {
            Low += p[j++]; //寻找该字符的概率区间下限
        }
        range = p[j]; //得到该字符的概率长度
        High = Low + range; //得到该字符概率区间上限
        for (i = 1; i<size; i++) //开始编码第二个字符
        {
            for (j = 0; j<number; j++) //寻找该字符在c数组中的位置
            {
                if (str[i] == c[j])
                {
                    if (j == 0) //若该字符在c数组中的第一个字符
                    {
                        low = Low; //此时该字符的概率区间下限刚好为零 
                        high = Low + p[j] * range;
                        High = high;
                        range *= p[j]; //求出该字符的编码区间长度
                    }
                    else //若该编码字符不是c数组中的第一个 
                    {
                        float proba_next = 0.0;
                        for (int k = 0; k <= j - 1; k++)
                            proba_next += p[k]; //再次寻找字符的概率区间下限
                        low = Low + range*proba_next; //编码区间下限 
                        high = Low + range*(proba_next + p[j]);//编码区间上限
                        Low = low; //编码区间下限 
                        High = high; //编码区间上限 
                        range *= p[j]; //编码区间长度
                    }
                }
                else continue; //i++,编码下一个字符 
            }
        }
        cout << endl;
        cout << "输入字符串的编码为:" << Low << endl;
        return Low;
    }
    //译码函数
    void yma(string str, char c[], long double p[], int number, int size, long double input)
    {
        vector<char> v; //定义char类型向量v
        long double temp; //中间变量
        long double sum[N]; //存储不重复字符概率区间的下限
        sum[0] = 0.0; //数组第一个元素为0
        for (int i = 1; i<number + 1; i++) //计算数组各元素的值
        {
            sum[i] = sum[i - 1] + p[i - 1];
        }
        for (int j = 0; j<size; j++)
        {
            for (int k = 0; k<number; k++)
            {
                //确定被编码字符的下限属于【0,1】之间的哪一段 
                if ((input>sum[k]) && (input<sum[k + 1])) //发现在哪就将属于该段的字符压入向量v
                {
                    v.push_back(str[j]);
                    temp = (input - sum[k]) / (sum[k + 1] - sum[k]);//计算下一个被编码字符的下限 
                    input = temp;
                    break;
                }
                else
                    continue;
            }
        }
        cout << endl;
        cout << "译码输出为:"; //将译码结果输出
        for (int m = 0; m<v.size(); m++)
        {
            cout << v[m];
        }
        cout << endl;
    }

    第四章:LZ编码的实现之LZ-78编码

    一. LZ-78编码原理

    经过查找资料,LZ编码并不是一种编码,而是一组编码,由LZ-77和LZ-78演变而来有很多种变形。所以这里我只选取了一种比较简单的算法LZ-78算法。
    LZ-78编码算法是一种分段编码算法。算法的压缩过程非常简单。在压缩时维护一个动态词典Dictionary,其包括了历史字符串的index与内容。设信源符号集 A=a0,a1,a2...aq1 共q个字符,设输入信源序列为

    S1S2...Sn

    编码就是将此序列分成不同的X段。分段的原则是:
    1. 先取第一个符号作为第一段,然后再继续分段
    2. 若出现有与前面相同符号时,就在添加进跟随后面的一个符号一起组成一个段,以使与前面的段不同。
    3. 尽可能取最少个连通着的信源符号,并保证隔断都不相同。直至信源符号徐立结束。
    这样,不同的段内的信源符号可看成一短语,可得不同段所对应的短语字典表。若编成二元码,段号用二进制表示,段号所需码长为 l=logX(n) ,X(n)是段号数。

    二. LZ-78编码过程

    LZ-78编码在压缩时维护一个动态词典Dictionary,其包括了历史字符串的index与内容;压缩情况分为三种:
    1. 若当前字符c未出现在词典中,则编码为(0, c);
    2. 若当前字符c出现在词典中,则与词典做最长匹配,然后编码为(prefixIndex,lastChar),其中,prefixIndex为最长匹配的前缀字符串,lastChar为最长匹配后的第一个字符;
    3. 为对最后一个字符的特殊处理,编码为(prefixIndex,)
    举例
    以字符串“ABBCBCABABCAABCAAB”压缩编码构造字典的过程如下
    LZ-78编码
    1. A 不在字典中; 插入A
    2. B不在字典中; 插入B
    3. B 在字典中.
    BC 不在字典中; 插入BC
    4. B在字典中.
    BC在字典中.
    BCA不在字典中.;插入BCA
    5. B在字典中.
    BA不在字典中; 插入BA.
    6. B在字典中.
    BC在字典中.
    BCA在字典中.
    BCAA不在字典中;插入BCAA
    7. B在字典中.
    BC在字典中.
    BCA在字典中.
    BCAA在字典中.
    BCAAB 不在字典中; 插入BCAAB.

    三. LZ-78编码编程实现和性能分析

    LZ-78算法我构建了一个LZ78类。类的定义如下

    class LZ78
    {
    public:
        struct Dictionary
        {
            unsigned int Index;
            int preIndex;
            unsigned char lastChar;
            vector<unsigned char> stringInDic;
        };
    public:
        struct OutData
        {
            unsigned int preIndex;
            unsigned char lastChar;
        };
    public:
        string fileAddress;
        LZ78();   //构造函数
        void open(string);
        void Press();
        void Decode(string sourcefile, string dstfile);
    private:
        bool IfStringInDic(vector<Dictionary> CurrentString, vector<unsigned char> DataDic, unsigned int &Index);
    private:
        vector<unsigned char> FindPreString(vector<Dictionary> DataDic, unsigned int);
    };

    核心属性
    1. struct Dictionary: 存储字典信息
    2. struct OutData: 存储输出信息即上面所提到的二元组(preIndex, lastChar);
    3. string fileAddress: 需要压缩的文件的路径名称
    核心函数:
    1. void open(string address) : 打开待压缩文件
    2. void Press(): 压缩文件操作
    3. void Decode(string sourcefile, string dstfile): 解码操作
    正式操作见下面主函数:
    主函数:

    int main()
    {
        LZ78 haha;
        clock_t start, end;
        start = clock();
        haha.open("./KongFu.jpg");  //打开文件
        haha.Press();   //压缩文件
        end = clock();
        cout << "压缩文件用时:" << endl << endl;
        cout << double((end - start) / CLOCKS_PER_SEC) << "/s" << endl << endl;
        start = clock();
        LZ78 nothaha;
        nothaha.Decode("./KongFu.jpg.lz", "KongFuout.jpg");
        cout << "解压用时:" << endl << endl;
        cout << double((start - end) / CLOCKS_PER_SEC) << "/s" << endl << endl;
        getchar();
    }

    文件压缩步骤
    第一步:建立haha对象为LZ78类型
    第二步:打开待压缩的文件
    第三步:压缩文件
    第四部:压缩结束
    文件解压步骤
    第一步:建立nothaha对象为LZ78类型
    第二步:解压文件
    第三步:解压结束
    LZ-78编码的性能测试见下表
    表4.1 LZ-78编码性能测试

    原始文件890Bytes(文本)46.7kb(图像)7.82M(视频)
    压缩文件3133Bytes47.9kb7.81M
    压缩率1.291.02599.8%
    压缩用时6/s20/s/
    解码用时0/s0/s/

    看到自己程序跑的结果自己都想笑,这也太慢了点了,有时候想安慰一下自己,可能是C++读取文件的API很耗时,要想速度快,有朝一日自己写读取文件的API,励志。
    最后附上LZ-78程序的C++源代码

    LZ78.h

    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;
    class LZ78
    {
    public:
        struct Dictionary
        {
            unsigned int Index;
            int preIndex;
            unsigned char lastChar;
            vector<unsigned char> stringInDic;
        };
    public:
        struct OutData
        {
            unsigned int preIndex;
            unsigned char lastChar;
        };
    public:
        string fileAddress;
        LZ78();   //构造函数
        void open(string);
        void Press();
        void Decode(string sourcefile, string dstfile);
    private:
        bool IfStringInDic(vector<Dictionary> CurrentString, vector<unsigned char> DataDic, unsigned int &Index);
    private:
        vector<unsigned char> FindPreString(vector<Dictionary> DataDic, unsigned int);
    };
    
    LZ78::LZ78()
    {
    
    }
    void LZ78::open(string input)
    {
        fileAddress = input;
    }
    
    void LZ78::Press()
    {
        ifstream read;
        read.open(fileAddress, ios::in|ios::binary);
        if (!read )
        {
            cout << "文件读取错误" << endl << endl;
            return;
        }
        ofstream write;
        write.open(fileAddress + ".lz", ios::out|ios::binary);
        if (!write)
        {
            cout << "输出文件不能建立(*.lz)" << endl << endl;
        }
    
        unsigned char *firstchar = new unsigned char;
        read.read((char*)firstchar, sizeof(unsigned char));
        vector<Dictionary> DataDic;    //建立字典
        while (!read.eof())
        {
    
            if (DataDic.size() == 0)
            {
                Dictionary firstDic;
                OutData *firstout = new OutData;
                firstDic.Index = 1;
                firstDic.preIndex = 0;
                firstDic.lastChar = *firstchar;
                firstDic.stringInDic.push_back(*firstchar);
                DataDic.push_back(firstDic);
                firstout->lastChar = *firstchar;
                firstout->preIndex = 0;
                write.write((char*)firstout, sizeof(OutData));
            }
            else
            {
                unsigned char *now = new unsigned char; //用于读取的字符
                unsigned char *reallast = new unsigned char;
                vector<unsigned char> CurrentString;
                unsigned int index = 0;  //字符串存在在字典中的位置, 初始设为0
                Dictionary currentInfo;   //存储当前的单词到字典中
                OutData *currentOutdata = new OutData;  //存储当前编码信息,一会压缩进如压缩文件。
    
                int EOFflag = 0;
                do
                {
                    read.read((char*)now, sizeof(unsigned char));
                    if (read.eof())
                    {
                        EOFflag = 1;  //标记是否到文件的结尾
                        break;
                    }
                    else
                    {
                        CurrentString.push_back(*now);
                    }
                } 
                while (IfStringInDic(DataDic, CurrentString, index));
    
    
                if (EOFflag == 1)
                {
                    if (CurrentString.size() == 0)
                    {
                        break;  //如果当前字符串中没有字符,直接跳出循环
                    }
                    else
                    {     //如果当前字符串中有字符,对这段字符进行压缩。
                        *reallast = CurrentString[CurrentString.size() - 1];
                        CurrentString.erase(CurrentString.end() - 1);
                        IfStringInDic(DataDic, CurrentString, index);
    
                    }
    
                }
                else
                {
                    *reallast = *now;
                }
                currentInfo.Index = DataDic.size() + 1;
                currentInfo.lastChar = *reallast;
                currentInfo.preIndex = index;
                currentInfo.stringInDic = CurrentString;
                DataDic.push_back(currentInfo);
    
                currentOutdata->lastChar = *reallast;
                currentOutdata->preIndex = index;
                write.write((char*)currentOutdata, sizeof(OutData));
    
            }
    
        }
    
        read.close();
        write.close();
    }
    
    bool LZ78::IfStringInDic(vector<Dictionary> DataDic, vector<unsigned char> CurrentString, unsigned int &Index)
    {
        int flag = 0;
        for (int i = 0; i < DataDic.size(); i++)
        {
            if (CurrentString == DataDic[i].stringInDic)
            {
                Index = DataDic[i].Index;
                flag = 1;
                return true;
            }
    
        }
        if (flag == 0)
        {
            return false;
        }
    }
    
    
    void LZ78::Decode(string sourcefile, string dstfile)
    {
        ifstream readfile;
        ofstream putfile;
        readfile.open(sourcefile, ios::in | ios::binary);
        putfile.open(dstfile, ios::out | ios::binary);
        OutData *getdata = new OutData;
        readfile.read((char*)getdata, sizeof(OutData));
        vector<Dictionary> DataDic;    //建立字典
        Dictionary *spacefirst = new Dictionary;
        spacefirst->Index = 0;
        spacefirst->lastChar = '0';
        spacefirst->preIndex = 0;
        //spacefirst->stringInDic
        DataDic.push_back(*spacefirst);
        while (!readfile.eof())
        {
            Dictionary *now = new Dictionary;
            now->lastChar = getdata->lastChar;
            now->Index = DataDic.size();
            now->preIndex = getdata->preIndex;
            vector<unsigned char> preString;  //存储前一个的字符串
            if (now->preIndex != 0)
            { //如果preIndex等于0那么此字符是新出现的字符,否则在前面字典中找
                preString = FindPreString(DataDic, now->preIndex);
            }
            preString.push_back(now->lastChar);  
            now->stringInDic = preString;  //获取此单词的字符串。
            DataDic.push_back(*now);
            for (int i = 0; i < preString.size(); i++)
            {
                putfile.write((char*)&preString[i], sizeof(unsigned char));
            }
            readfile.read((char*)getdata, sizeof(OutData));
    
        }
        readfile.close();
        putfile.close();
    }
    
    vector<unsigned char>  LZ78::FindPreString(vector<Dictionary> DataDic, unsigned int preindex)
    {
        if (DataDic.size() < 1)
        {
            cout << "不能找到前一个字符串" << endl;
        }
        else
        {
            for (int i = 0; i < DataDic.size(); i++)
            {
                if (preindex == DataDic[i].Index)
                {
                    return DataDic[i].stringInDic;
                }
            }
        }
    }

    LZ-78Main.cpp

    #include "LZ78.h"
    #include <string>
    #include <time.h>
    int main()
    {
        LZ78 haha;
        clock_t start, end;
        start = clock();
        haha.open("./KongFu.jpg");  //打开文件
        haha.Press();   //压缩文件
        end = clock();
        cout << "压缩文件用时:" << endl << endl;
        cout << double((end - start) / CLOCKS_PER_SEC) << "/s" << endl << endl;
        start = clock();
        LZ78 nothaha;
        nothaha.Decode("./KongFu.jpg.lz", "KongFuout.jpg");
        cout << "解压用时:" << endl << endl;
        cout << double((start - end) / CLOCKS_PER_SEC) << "/s" << endl << endl;
        getchar();
    }

    总结

    经过此次试验真的是收获了很多,首先是对各种编码的熟悉,从Huffman编码、Shannon Fano码、算数编码到LZ编码家族,了解了Zip,winrar等压缩软件的压缩原理,以及压缩算法从兴起到应用,里面还有一些版权纠纷的故事(LZW版权问题)。到现在的操作系统使用的压缩软件的情况,Windows主要的软件是winrar和zip, linux系统下主要是.gz和gzip软件。其原理都是基于DELLATE算法的。DELLATE算法是以Huffman编码和LZW编码为核心的。另一方面,从信息论角度细致的学习了各种编码的编码原理和译码方式,这些收获相信在今后的学习中都会有用的。这次实验不仅锻炼了编程能力,而且学习到很多编码领域的新知识。

    参考文献
    《信息论与编码》傅祖芸、赵建中 电子工业出版社
    C++实现Huffman文件编码和解码:http://www.cnblogs.com/matrix-r/p/3354887.html
    zip压缩原理 http://blog.jobbole.com/76676/
    Huffman对文件编码和解码http://blog.csdn.net/computer_liuyun/article/details/41446773
    huffman编码原理与实现:http://blog.csdn.net/abcjennifer/article/details/8020695
    二进制和ASCII编码: http://blog.csdn.net/sxhelijian/article/details/29594687
    压缩编码的历史:http://blog.csdn.net/kimylrong/article/details/39405981
    Lz78算法:http://www.cnblogs.com/aeexiaoqiang/p/6529375.html
    算数编码: http://blog.csdn.net/adam_tu/article/details/7696455

    展开全文
  • 霍尔编码器原理及测速--PID—arduino

    万次阅读 多人点赞 2020-03-04 17:13:28
    本人目前是一个大一菜鸟,零基础学的编码器方面,希望我的经验对你有些帮助。 分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机带霍尔传感器。先来看一下最基本的 接线方法------- ------S1与S2...

    标题

    本人目前是一个大一菜鸟,最近在学编码器方面的知识,希望我的经验对你有些帮助。
    分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机。先来看一下最基本的
    接线方法-------
    在这里插入图片描述

    测速原理

    ##测速原理
    这里需要用到一些基本函数,大家可以去相关网站去找一下,重要的是定时器函数和中断函数
    我用的这个电机脉冲数双相300个,单相150个。(电机的型号不同可能会不一样,如果店家那没有的话可以抠出来下面一部分程序测)
    具体思路:首先使用定时器定时一个时间,我这里用的是50ms。编码器转一圈会发送脉冲,一个脉冲可以产生一个中断,在中断函数里令一个变量自加,每产生一个脉冲该变量就加1。所以该变量就是脉冲数。
    通过50ms内产生得脉冲数就可以算出速度了(这里是角速度,如果要具体算速度的话乘以轮子半径即可)。用脉冲数/150( 这里用单相或者双相都一样,我用的单相得)即可得到在这50ms内电机转动得圈数。再乘以20就是一秒内转的圈数,再乘以60就是一分钟转的圈数 。 下面是代码
    打开串口绘图器即可观察数据(打印函数一定要用 Serial.println()才可以显示哦)

    #include <TimerOne.h>
    float v;
    volatile long counter_val0=0;
    volatile long counter_val1=0;      //该变量用于存储编码器的值,所以用类型修饰符volatile;
    int j=0;                           //定时器标志;
    
    void setup()
    {
      delay(2000);
      pinMode(2, INPUT);
      pinMode(3, INPUT);                    //设置为输入模式,并且2,3号引脚是中断口0,1;
    
      Serial.begin(115200);                //初始化波特率为115200
      attachInterrupt(0, counter0, RISING);//设置编码器A相位上升沿中断
      attachInterrupt(1, counter1, RISING);//设置编码器B相位上升沿中断
      Timer1.initialize(50000);            // 设置定时器中断时间,单位微秒 ,这里是50毫秒
      Timer1.attachInterrupt( timerIsr ); // 打开定时器中断
      interrupts();                      //打开外部中断
    }
    void loop()
    {
      long lTemp = 0; //定义临时存储数据变量
      if(j==1)        //判断是否发生定时器中断,这里是50ms发生一次
       {
           j=0;       //清除标记
       }     
    }
    //外部中断处理函数
    void counter0()
    {
         counter_val0++;    //每一个中断加一
    }
    void counter1()
    {
         counter_val1++;    //每一个中断加一
    }
    //定时器中断处理函数
    void timerIsr()
    {
       j=1;                           //定时时间达到标志     
       v=60*20*counter_val0/150.0;    //这里的单位是转每分钟:r/min
       Serial.println(v);    
       counter_val0=0;
       counter_val1=0;               //清空该时间段内的脉冲数
       return v;                
    }
    

    PID

    如果有对PID算法感兴趣的我们可以讨论下,根据编码器测速写了一个控制电机速度的算法,但是参数我还没调出来。下面是源代码。如果有错误希望大佬们给我提醒一下

    #include <TimerOne.h>
    #define set_point 100
     float v;
    long counter_val0=0;
    long counter_val1=0;
    int j=0;
    
    void setup()
    {
      delay(2000);
      pinMode(2, INPUT);
      pinMode(3, INPUT);
      pinMode(8,OUTPUT);
      pinMode(9,OUTPUT);       //启用电机A的三个管脚,全部设置为输出状态
      digitalWrite(9, LOW);       //松开电机A的制动
      digitalWrite(8, HIGH);      //设置方向为正向旋转
      Serial.begin(115200);//初始化波特率为115200
      attachInterrupt(0, counter0, RISING);//设置编码器A相位上升沿中断
      attachInterrupt(1, counter1, RISING);//设置编码器B相位上升沿中断
      Timer1.initialize(50000); // 设置定时器中断时间,单位微秒
      Timer1.attachInterrupt( timerIsr ); // 打开定时器中断
      interrupts();  //打开外部中断
    }
    void loop()
    {
      long lTemp = 0; //定义临时存储数据变量
      if(j==1)   //判断是否发生定时器中断,即定时时间是否到达
       {
           j=0; }
          int v1=(int)v;
           analogWrite(9,PIDControl_L(50,v1));
           analogWrite(8,0);
           
         
    }
    //外部中断处理函数
    void counter0()
    {
         counter_val0++;    //每一个中断加一
    }
    void counter1()
    {
         counter_val1++;    //每一个中断加一
    }
    //定时器中断处理函数
    void timerIsr()
    {
       j=1;     //定时时间达到标志     
       v=1200*counter_val0/150.0;
    
             Serial.println(v);  
       
       counter_val0=0;
       counter_val1=0;
       return v;
    }
    
    
    float PIDControl_L(int SpeedSet,int speed)        //pid
    {
        float Kp=50,Ki=9,kd=0.1;
        float cap;  
       int e=0,e1=0,e2=0;       
       static float PwmControl;
        static  float  pwm;
        e2=e1; 
        e1 = e; 
        e=SpeedSet-speed;
        PwmControl+=Kp *(e-e1)+ Ki*e+kd*(e-2e1+e2); 
        pwm=map(PwmControl,0, 60, 0, 255);
             
      
        cap = pwm;             
     
        return pwm;
    }
    

    `

    展开全文
  • 主数据及编码

    千次阅读 2020-01-26 12:03:40
    早期以 ERP 为代表的制造业集成应用系统的发展过程中,产生了信息孤岛和数据处理危机问题。为了解决这些问题,主数据这个概念随之诞生。 目前,对主数据的定义没有统一,一些 MDM 产品提供商和学者提出了各自对主...

    之前做数据梳理的时候对主数据进行了一个总结,虽然项目没有很好的开展,不过对我来说也是有很多收获的,这里把之前用到的一些文档总结如下。


    术语和定义

    主数据

    早期以 ERP 为代表的制造业集成应用系统的发展过程中,产生了信息孤岛和数据处理危机问题。为了解决这些问题,主数据这个概念随之诞生。

    目前,对主数据的定义没有统一,一些 MDM 产品提供商和学者提出了各自对主数据的定义,如下:

    David Loshin 在其主数据管理的著作中对主数据的定义是:主数据是企业中跨应用的核心业务实体,包括元数据、定义、属性、关系、角色和类别等。

    维基百科对主数据的定义是:主数据是在企业中可以共享的、一致的业务实体,是跨系统、跨应用和跨流程的基础数据的唯一来源,包括业务数据、非结构数据、分析型数据、组织架构数据及元数据。

    Gartner 公司的定义是:主数据是描述企业核心实体的、跨业务流程的、统一的数据标识和属性。

    ISO 标准中的定义:主数据是指事务处理需参考的独立的基础数据实体。

    著名的软件供应商 oracle 的定义:多个业务系统中最核心的、需要共享的数据,它是支持企业业务和分析的关键基础数据;IBM 对主数据的定义是:存在于多个异构系统中的跨核心业务实体的、具有高价值的数据。尽管不同角色对主数据定义的表达形式有所差异,但都反映了主数据的基本特征。总的来说,主数据的定义是:

    主数据(Master Data)是指具有高业务价值的、可以在企业内跨越各个业务部门被重复使用的数据,具有相对静态的特点,是单一的、准确的、权威的数据来源。

    基础主数据

    基础主数据就是在品名规范、收集模板、扩充视图填写过程中需要提前维护的字段,类似于元数据,是其他主数据的基础数据。

    基础主数据分为两大类:一类是自定义的基础数据,这部分数据在新建 主数据时可以新增,数据申请人员有权限进行申请,如用户创建的属性时, 发现系统中没有该类属性,则该用户可以申请新增此属性。另一类是很少新增或 者修改的基础数据,这些数据一般是货币、国家、行业、标准等,在系统初始化。

    主数据编码标准

    主数据编码标准定义了数据的分类和编码规则,是主数据标准化建设的核 心内容。 通过对主数据分类编码的标准化,杜绝自然语言描述下的不规则和理解 的二义性,便于实现计算机信息处理,以提高信息管理的效率

    主数据属性标准

    主数据标准,是各类主数据的数据模型标准,定义了属性构成、元数据、数据关系和参考数据等内容,是主数据标准化的关键。主数据包括物料、供应商、 客户、财务、组织架构数据。每类主数据应该由哪些属性(或字段)去约束,都 需要提前规范化、标准化。

    主数据管理

    主数据管理(Master Data Managent, MDM)描述了一组规程、技术和解决方案,用于为所有利益相关方(如用户、应用程序、数据仓库、流程以及贸易伙伴)创建并维护业务数据的一致性、完整性、相关性和精确性。

    主数据编码标准

    编码原则

    编码过程中遵循以下总体原则:

    • 唯一性

    确保主数据对象的数据条目都有一个唯一的代码,不重复;

    • 科学性

    根据业务需求,选择主数据最稳定的本质属性或特征作为分类的基础和依据;

    • 兼容性

    应与相关标准协调一致,确保与集团、相关伙伴在有关主数据编码上尽量遵循公共的标准;

    • 可扩充性

    编码应留有适当的后备容量,以便适应不断扩充的需要;

    • 简明性

    编码结构应尽量简单,长度尽量短,以便节省存储空间和减少代码的差错率;

    • 实用性

    编码应尽可能反映编码对象的现实特点,避免过于理想,而造成对业务效率的降低;

    编码规则

    企业信息编码方法

    信息化的过程中,为了便于计算机处理信息,需要给企业的各类信息(人员、物资、机构等)进行编码。信息编码一般由数字和字母组成,编码位数由编码对象的多少决定,同时还要遵循一定的信息分类和编码原则。根据代码的含义性将代码分为图示的几大类型。按照代码所代表的编码对象或编码对象的特征,又可以将代码分为标识码和特征码,特征码又包括分类码、结构码、状态码、一般取值码等。这些编码之间的分类也不是绝对的,在实际应用过程中可以按照具体的编码对象选择最佳的编码或多类编码的组合。

    3-1编码规则示意图

    顺序码

    在一个有序的字母、数字或者字母加数字的集合中,顺序地为编码对象分配编码。顺序码包括三种类型:递增顺序码、系列顺序码和约定顺序码。

    递增顺序码:按照预先定义的字母或者数字递增步长顺序增加。

    系列顺序码:首先划分编码对象类别,然后确定各个类别的代码范围,最后,顺序地赋予编码对象在各自类别编码范围内的代码值。

    约定顺序码:首先将编码对象本身按照某种顺序(缩写字母顺序或事件、活动的年代顺序等)进行排列,然后再将有序的代码值(字母或数字顺序)与其排列顺序进行一一对应,从而得到编码对象的代码值。这种编码的前提是所有的编码对象都预先已知并且编码对象集合不会扩展。该编码不是完整意义上的顺序码。

    无序码

    无序码是对编码对象用无序的字母或自然数进行编码,该编码无规律可循,通常由计算机随机给出。通常作为复合码的一部分而使用。

    缩写码

    缩写码,将编码对象的名称(英文或者中文拼音)进行缩写,编码的形成是取名称中的一个或多个字符(如首字母)。缩写码适用于编码对象是相对稳定的且被人们所熟知的有限标识代码集。

    层次码

    该编码方式以线分类为基础,下位类包含在上位类中,层次码的编码基础是编码对象各层级间特性的差异,将编码对象编成连续递增的复合代码。

    层次码适用于统计目的、基于学科的出版分类等情况

    3-2层次码示例

    矩阵码

    这种编码方式以矩阵表(复式记录表)为基础,编码对象的代码是矩阵表中行值和列值的组合,这样不同的编码对象对应一样的行(或列)会有若干相同的特性。矩阵码对编码对象的要求是具有良好的结构和稳定性,如汉字编码字符集[31] 。

    并置码

    这种编码实质上是将编码对象的特性代码段组合而成的复合代码(如图 2-7所示)。这些特性代码描述编码对象相互独立的特性,可以是无序码、缩写码、顺序码等任意编码类型。面分类法常使用此编码结构。

    主数据

    主数据分类方法

    信息分类的基本方法有三种:线分类法、面分类法和混合分类法。

    线分类法

    线分类法也称层级分类法。它将分类对象按照若干属性依次分为若干逐级展开的层级类目,形成一个有层次的分类体系。在该体系中,同层级类目之间互不重复交叉、形成并列关系,不同层级类目之间是从属关系。采用线分类法进行编码时一般采用的编码结构是层次码,为每个层级编码,最低的层级可以使用流水码,最终编码是各层级编码的组合。该分类体系可以用分类树进行表示(如图所示)。

    4-1线分类图示

    线分类法具有清晰的层次结构,能较好地反映类目之间的隶属关系,是人们习惯使用的分类方式,既符合手工操作的习惯,也易于被计算机处理。但是该分类体系结构弹性较差,当改动或者删除分类层级中的一个中间类目时,会引起该类目的下层级结构发生变化;另外,当分类层级较深时,代码位会变长,影响使用效率。

    面分类法

    面分类法是依据分类对象本身固有的各种属性(或特性),划分成互相之间没有隶属关系独立的“面”,每个“面”由一组类目组成。将某个“面”下的一种类目和其他某个或多个“面”的一种类目组合在一起,可以组成一个复合类目。采用面分类法进行编码时,对每个面进行编码,然后将“面”编码进行组合即为最终编码。面分类法示意图如所示。

    4-2面分类图示

    面分类法描述的分类结构具有较大的柔性,单个“面”内类目的改变不会引起其他“面”的变化;面分类法使用性更强,在分类属性(或特性)不改变的情况下,可以通过类目组合规则的变化对分类结果进行调整。当然,该方法也有不足:采用该分类进行编码,使得编码容量利用不充分;当分类属性(或特性)较多时,组合数量会急剧增加;另外,根据对象特性划分的面有时类目很多,但实际组合应用的不多,即存在大量无应用意义的组合,导致结构上的冗余;同时难于手工信息处理。

    混合分类法

    混合分类法将线分类法和面分类法综合起来运用,吸收两种方法优点,避免各自的缺点,从而得出更为合理的分类结构。在实际应用过程中,通常将线分类法作为主体,在划分的某一个层次中将面分类法作为辅助分类方法进行分类。如由德国提出的著名的 OPITZ分类码,该编码方案在对零件进行编码时取得了良好的效果。


    定义因研究不同各有差别,但实施是非常重要的,毕竟主数据分类好,产品开发加班少,希望以后有机会实施整个数据治理。

    展开全文
  • 定义会计凭证编码范围 SNRO

    千次阅读 2018-06-21 11:23:08
    定义会计凭证编码范围事务代码:SNRO SNUM对象:RF_BELEG1:短文本和长文本用来说明这个编号范围对象,输入任意描述即可。2:所谓子对象,多数指一个组织结构,比如公司代码、销售组织、工厂等,这样编号就在对应的每...

    定义会计凭证编码范围
    事务代码:SNRO SNUM
    对象:RF_BELEG


    1:短文本和长文本用来说明这个编号范围对象,输入任意描述即可。

    2:所谓子对象,多数指一个组织结构,比如公司代码、销售组织、工厂等,这样编号就在对应的每个组织下面独立编号,最典型的例子是财务凭证,每个公司代码下的财务凭证都是独立编号的(其对应的数据表BKPF,也必定把公司代码做为一个键字段)。

    3:到期年标记是指编号按年度归零,每当开始一个新年度时,相应的编号也需要从头开始,比如财务凭证和物料凭证都是这样(比如表BKPF MKPF,都把年度做为一个键字段)

    4:编号长度域就填创建的域,但是一定要先激活。指定这个编号范围对象ZDIAODUDAN 的长度,会计凭证编号长度为 10

    5:无翻滚间隔是指如果编号达到最大,是否自动从头开始,勾上就不从头开始,而在获取编号的时候提示出错。我们这里应该打勾。

    6:编号范围处理,属于翻译问题,实际就是编号范围的事务码,如果指定这个事务码,就可以不需要通过 SNUM 或者 SNRO 的主屏幕然后输入编号范围对象的名字来维护这个编号范围,而可以输入事务码直接进入它的号码范围维护屏幕。

    7:警告百分比是指如果编号使用到一定比例,就发出系统警告,提示管理人员增大范围或者进行历史数据归档,避免编号全部用完后影响正常业务,会计凭证编号填写95,就是10%的时候提示。

    8:主内存缓冲是 指系统为了提高性能而预先取出一些编号放在应用服务器上,当程序取用编号时直接从应用服务器获取,而无需再读取数据库了。通常,如果对号码的连续性要求不高的情况下可以使用这种方式,而如果是财务凭证等要求连续的编号,则应该把主内存缓冲关闭,方法是通过菜单编辑-设置缓存-无缓存

    注意点:如果号码段出问题 可以吧 这个mainmemory buffering 去掉

    保存后点击下面的 number ranges

    参考:http://blog.sina.com.cn/s/blog_4298a2c80102wmvn.html

    展开全文
  • HTML meta charset 定义网页编码信息

    千次阅读 2012-08-01 10:00:11
    使用http-equiv的content-type可以提供网页的编码信息 charset示例 使用UTF8编码(国际化编码)metahttp-equiv="content-type"content="text/html; charset=UTF-8"/> 使用中文gb2312编码meta ...
  • 直流电机、减速器、编码器与TB6612FNG知识整理

    千次阅读 多人点赞 2020-02-16 13:21:30
    之前把MPU6050的相关知识了解了一下,可以做到测量欧拉角,在平衡小车的开发中需要测量小车的倾角来...定义2.原理二.TB6612FNG1.简介2.优点3.使用方法三.减速器1.作用2.分类四.编码器1.概述2.原理3.四倍频技术 一...
  • 详解遗传算法(含MATLAB代码)

    万次阅读 多人点赞 2019-05-29 11:30:47
    1.编码 2.适应度函数 3.选择算子 4.交叉算子 5.变异算子 6.运行参数 四、遗传算法的基本原理 4.1 模式定理 4.2 积木块假设 五、遗传算法编程实例(MATLAB) 一、遗传算法概述 遗传算法(...
  • 信息论基础(学习笔记整理)

    万次阅读 多人点赞 2019-06-08 13:24:12
    整理信息论基础的知识点。
  • 信源编码与信道编码

    万次阅读 多人点赞 2017-03-26 17:02:44
    但现代通信应用中常见的信源编码方式有:Huffman编码、算术编码、L-Z编码,这三种都是无损编码,另外还有一些有损的编码方式。信源编码的目标就是使信源减少冗余,更加有效、经济地传输,最常见的应用形式就是压缩。...
  • h264编码概述五(slice定义

    千次阅读 2018-11-16 17:55:41
    一、slice定义 h264编码可以将一幅图片分割...在H264编码协议中定义,当前帧的当前Slice片内宏块不允许参考其他Slice的宏块。 二、在序列中的位置 三、elecard示例Slice信息 四、H264协议Slice格式定义 ...
  • 编码和可靠性编码

    千次阅读 2019-03-31 20:24:36
    编码和可靠性编码
  • h264编码概述三(帧定义

    千次阅读 2018-07-17 16:36:04
    一、视频编码基本概念 序列、帧、Slice、宏块概念如下图所示。 二、视频压缩编码的基本步骤 其中对视频质量有影响的模块有:量化和滤波。 量化模块的QP值,直接影响视频质量。由于量化后,视频质量有...
  • 定义 哈夫曼编码,又称为霍夫曼编码,是一种字符编码。 在计算机数据压缩处理中,霍夫曼编码使用变长编码表()对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现几率的方法得到的,...
  • 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。 当然对于 ANSI编码 而言, 0x00~0x7F 之间的字符,依旧是1个字节代表1个字符。这一点是ANSI编码与...
  • 正例中的数字就是延伸信息,表示星期几。 正例: public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6),SUNDAY(7);} ( 三 ) 代码格式 【强制】大括号的使用...
  • 遗传算法的编码模式

    万次阅读 2017-12-29 14:17:13
    转载请标明出处 遗传算法的实现有6个主要因素:参数的编码、初始种群的设定、适应度函数的设计、遗传操作、算法控制参数的设定、约束条件的处理。参数的编码即把一个问题的可行解从其解空间转换到遗传算法所能处理...
  • 什么是信道编码?信道编码比较

    万次阅读 多人点赞 2018-11-23 14:24:20
    消除干扰,让无线信号更干净,这本是信道编码技术的初衷。然而,最近网络上这场“Polar码投票”闹剧,无中生有地添加杂质,与所议论的技术之本质背道而驰,若Polar码也有血肉之躯,此君情何以堪?香农前辈若在世,也...
  • bat脚本编码问题

    千次阅读 2019-10-30 11:18:39
    问题根源:cmd窗口的“当前代码页”编码与bat脚本的编码不一致。 解决方案: 在cmd窗口中右键标题栏,选择属性->选项,可以看到默认的当前代码页为936 (ANSI/OEM)。 所以我们可以通过以下两种方式解决问题。...
  • 地理编码

    千次阅读 2019-01-23 22:43:47
    2.地理编码与逆地理编码的比较。 3.地理编码的过程 ① 构建或获取参考数据 ② 确定地址定位器样式 ③ 构建地址定位器 ④ 定位地址 ⑤ 发布或维护地址定位器 二.使用arcgis实现地理编码 准备: 软件...
  • 图像编码(一)

    千次阅读 2016-11-23 16:25:24
    图像编码的一些基本知识。
  • 编码

    千次阅读 多人点赞 2019-07-04 16:49:57
    大多数编码器都使用光学传感器来提供脉冲序列形式的电信号, 这些信号可以依次转换成运动、方向或位置信息编码器依运动方式可分为旋转编码器或是线性编码器;按照读出方式编码器可以分为接触式和非接触式两种;...
  •   在非监督学习中,最典型的一类神经网络莫过于autoencoder(自编码器),它的目的是基于输入的unlabeled数据X={x(1),x(2),x(3),...}X={x(1),x(2),x(3),...}X=\{x^{(1)}, x^{(2)}, x^{(3)}, ...\},通过训练得到数据...
  • CSDN GitHub Ubuntu下apache的安装与配置 AderXCoding/system/tools ...1. 问题描述–(linux下经常遇到的编码问题)师兄在 windows 下写的一段程序(C/C++ 编写), 传给我在 Linux 下面运行, 编译和运行的时候输出
  • C++ 计算三角形面积

    万次阅读 多人点赞 2018-03-28 10:46:23
    C++编码实现计算三角形面积1- 计算公式方法一: S=√[p(p-a)...使用结构体定义定义计算两点间距离函数,定义计算面积函数3- 编码#include &lt;iostream&gt; #include&lt;math.h&gt; using names...
  • 字符编码那些事--彻底理解掌握编码知识

    万次阅读 多人点赞 2020-05-04 16:42:33
    每一个程序员都不可避免的遇到字符编码的问题,很多人在字符编码方面同样遇到不少问题,而且一直对各种编码懵懵懂懂、不清不楚。这篇文章就是针对字符编码中的一些问题进行了详细的阐述,能从根本上理解字符编码
  • 简析多种编码方式(Hex, Base64, UTF-8) 首先计算机只认得二进制,0和1,所以我们现在看到的字都是经过二进制数据编码后的;计算机能针对0和1的组合做很多事情,这些规则都是人定义的;然后有了字节的概念,8比特...
  • 编码器及其变形很多,本篇博客目前主要基于普通自编码器、欠完备自编码器、稀疏自编码器和去噪自编码器,会提供理论+实践(有的理论本人没有完全理解,就先没有写上,后更)。另外,关于收缩自编码器、变分自编码...
  • Java编码规范

    热门讨论 2014-02-20 17:27:40
    在软件的生命周期中,维护的花费通常占很大的比例,且几乎所有的软件,在其整个生命...本文档定义了我公司软件开发过程中使用的开发语言的编码规范,指导软件开发人员在进行项目开发过程中提高代码质量、统一编码要求。
  • php页面为utf-8编码  header("Content-type: text/html; charset=utf-8");  php页面为gbk编码  header("Content-type: text/html; charset=gb2312");  php页面为big5编码  header("Content-type: ...
  • NC65 通过编码规则生成物料编码

    千次阅读 2018-10-23 09:39:25
    思路分析:通过编码规则定义-全局 了解到物料编码的生成规则基于流水号的形式  比如规则定义:物料分类编码+流水号 (5+7) ( 物料分类为5位 已后补位0的形式在展现 那样编码就会做到唯一性)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 985,286
精华内容 394,114
关键字:

信息编码的定义