C#,数值计算——算术编码压缩技术与方法(Compression by Arithmetic Coding)源代码

news2024/11/16 8:25:18

算术编码的数据压缩

算术编码是无损和有损数据压缩算法中常用的一种算法。

这是一种熵编码技术,其中常见符号比罕见符号用更少的比特进行编码。与诸如霍夫曼编码之类的众所周知的技术相比,它具有一些优势。本文将详细描述CACM87算术编码的实现,让您很好地了解实现它所需的所有细节。

从历史的角度来看,这篇文章是我20多年前写的一篇关于算术编码的数据压缩文章的更新。这篇文章发表在多布博士期刊的印刷版上,这意味着为了避免过多的页数,我们进行了大量的编辑。特别是,多布博士的文章结合了两个主题:算术编码的描述,以及使用PPM(部分匹配预测)进行压缩的讨论。

因为这篇新文章将在网上发布,空间考虑不再是一个重要因素,我希望这能让我公正地对待算术编码的细节。PPM本身就是一个有价值的话题,将在后面的文章中讨论。我希望这项新的努力,虽然冗长得令人恼火,但将是对我在1991年想做的主题的彻底解释。

我认为理解算术编码的最好方法是将其分为两部分,我将在本文中使用这个想法。首先,我将描述算术编码是如何工作的,使用标准C++数据类型实现的常规浮点算术。这允许实现一个完全可以理解但有点不切实际的实现。换句话说,它是有效的,但它只能用于编码非常短的消息。

文章的第二部分将描述一种实现,在该实现中,我们切换到对无界二进制数进行特殊类型的数学运算。这本身就是一个有点令人难以置信的话题,所以如果你已经理解了算术编码,它会有所帮助——你不必为同时学习两件事而烦恼。

最后,我将介绍用现代C++编写的工作示例代码。它不一定是世界上优化程度最高的代码,但它是可移植的,很容易添加到现有项目中。它应该非常适合学习和试验这种编码技术。

基本原理

关于算术编码,首先要了解的是它产生了什么。算术编码采用由符号(几乎总是八位字符)组成的消息(通常是一个文件),并将其转换为大于或等于零且小于1的浮点数。这个浮点数字可能很长——实际上,整个输出文件都是一个长数字——这意味着它不是传统编程语言中习惯使用的普通数据类型。我的算法实现必须从头开始,一点一点地创建这个浮点数,同样地,一点地读入并解码它。

这个编码过程是逐步完成的。当文件中的每个字符都被编码时,一些比特将被添加到编码的消息中,因此随着算法的进行,它会随着时间的推移而建立起来。

关于算术编码,需要理解的第二件事是,它依赖于一个模型来表征它正在处理的符号。该模型的工作是告诉编码器给定消息中字符的概率是多少。如果模型给出了消息中字符的准确概率,那么它们将被编码为非常接近最优。如果模型歪曲了符号的概率,那么编码器实际上可能会扩展消息,而不是压缩它!

using System;

namespace Legalsoft.Truffer
{
    /// <summary>
    /// compression by arithmetic coding
    /// </summary>
    public class Arithcode
    {
        private int NWK { get; } = 20;
        private int nch { get; set; }
        private int nrad { get; set; }
        private int ncum { get; set; }
        private int jdif { get; set; }
        private int nc { get; set; }
        private int minint { get; set; }
        private int[] ilob { get; set; }
        private int[] iupb { get; set; }
        private int[] ncumfq { get; set; }

        public Arithcode(int[] nfreq, int nnch, int nnrad)
        {
            this.nch = nnch;
            this.nrad = nnrad;
            this.ilob = new int[NWK];
            this.iupb = new int[NWK];
            this.ncumfq = new int[nch + 2];

            if (nrad > 256)
            {
                throw new Exception("output radix must be <= 256 in Arithcode");
            }

            minint = (int)(int.MaxValue / nrad);
            ncumfq[0] = 0;
            for (int j = 1; j <= nch; j++)
            {
                ncumfq[j] = ncumfq[j - 1] + Math.Max(nfreq[j - 1], 1);
            }
            ncum = ncumfq[nch + 1] = ncumfq[nch] + 1;
        }

        public void messageinit()
        {
            jdif = (int)(nrad - 1);
            for (int j = NWK - 1; j >= 0; j--)
            {
                iupb[j] = nrad - 1;
                ilob[j] = 0;
                nc = (int)j;
                if (jdif > minint)
                {
                    return;
                }
                jdif = (int)((jdif + 1) * nrad - 1);
            }
            throw new Exception("NWK too small in arcode.");
        }

        public void codeone(int ich, byte[] code, ref int lcd)
        {
            if (ich > nch)
            {
                throw new Exception("bad ich in Arithcode");
            }
            advance(ich, code, ref lcd, 1);
        }

        public int decodeone(byte[] code, ref int lcd)
        {
            int ja = (byte)code[lcd] - ilob[nc];
            for (int j = nc + 1; j < NWK; j++)
            {
                ja *= (int)nrad;
                ja += (byte)code[lcd + j - nc] - ilob[j];
            }
            int ihi = (int)(nch + 1);
            int ich = 0;
            while (ihi - ich > 1)
            {
                int m = (int)((ich + ihi) >> 1);
                if (ja >= multdiv(jdif, ncumfq[m], (int)ncum))
                {
                    ich = (int)m;
                }
                else
                {
                    ihi = m;
                }
            }
            if (ich != nch)
            {
                advance(ich, code, ref lcd, -1);
            }
            return ich;
        }

        public void advance(int ich, byte[] code, ref int lcd, int isign)
        {
            int jh = multdiv(jdif, ncumfq[ich + 1], (int)ncum);
            int jl = multdiv(jdif, ncumfq[ich], (int)ncum);
            jdif = jh - jl;
            arrsum(ilob, iupb, jh, NWK, (int)nrad, nc);
            arrsum(ilob, ilob, jl, NWK, (int)nrad, nc);
            int j = nc;
            for (; j < NWK; j++)
            {
                if (ich != nch && iupb[j] != ilob[j])
                {
                    break;
                }
                if (isign > 0)
                {
                    code[lcd] = (byte)ilob[j];
                }
                lcd++;
            }
            if (j + 1 > NWK)
            {
                return;
            }
            nc = j;
            for (j = 0; jdif < minint; j++)
            {
                jdif *= (int)nrad;
            }
            if (j > nc)
            {
                throw new Exception("NWK too small in arcode.");
            }
            if (j != 0)
            {
                for (int k = nc; k < NWK; k++)
                {
                    iupb[k - j] = iupb[k];
                    ilob[k - j] = ilob[k];
                }
            }
            nc -= j;
            for (int k = (int)(NWK - j); k < NWK; k++)
            {
                iupb[k] = ilob[k] = 0;
            }
            return;
        }

        public int multdiv(int j, int k, int m)
        {
            return (int)((ulong)j * (ulong)k / (ulong)m);
        }

        public void arrsum(int[] iin, int[] iout, int ja, int nwk, int nrad, int nc)
        {
            int karry = 0;
            for (int j = (int)(nwk - 1); j > nc; j--)
            {
                int jtmp = ja;
                ja /= nrad;
                iout[j] = iin[j] + (jtmp - ja * nrad) + karry;
                if (iout[j] >= nrad)
                {
                    iout[j] -= nrad;
                    karry = 1;
                }
                else
                {
                    karry = 0;
                }
            }
            iout[nc] = iin[nc] + ja + karry;
        }
    }
}
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/697423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Uniapp_分包

前言&#xff1a;由于微信小程序的包只限制压缩不能超过2M&#xff0c;当开发的页面过多就要进行分包操作,tabbar页面不能进行分包其他页面可以 最多5个分包 不超过20M 第一步、找到这个位置 然后把这个代码复制进去 开启分包 "optimization" : {"subPackages&…

Linux系统【VS】Windows系统

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

FPS(CF、CS GO、PUBG、APEX、瓦罗兰) AI YOLOV5 自瞄 模型 权重

YOLOV5的各种AI自瞄权重&#xff0c;有需要的联系 联系方式 如果对上面的资源有需要&#xff0c;私聊或者留言或者进入下面项目了解详细内容 联系方式 加我时&#xff0c;请备注所需要的权重 https://gitee.com/wcx895278175/cf-ai-yolov5-self-aiming

【Oracle】springboot连接Oracle 集成mybatis、druid

目录 项目结构与库表数据pom.xmlapplication.yml实体类Mappercontroller接口测试 基于spring-boot 2.7.11&#xff0c;连接Oracle 11g 仅做一个简单的示例 特别说明&#xff08;不一定正确&#xff0c;还请指正&#xff09;&#xff1a;我Oracle也不熟&#xff0c;但据我观察发…

【Java高级语法】(二十三)系统辅助工具类:解析System类,一个系统操作与资源管理工具类~

Java高级语法详解之系统辅助工具类 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 System类常用方法3.2 使用技巧 4️⃣ 应用场景&#x1f33e; 总结 1️⃣ 概念 Java的System类是Java标准库中一个重要且常用的类。它被设计用于提供与系统相关的操作和信息访问功能。System类的设计…

【算法系列之贪心算法III】leetcode135. 分发糖果

134. 加油站 力扣题目链接 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。 给定…

创建临时文件mkstemp()和tmpfile()

有些程序需要创建一些临时文件&#xff0c;仅供其在运行期间使用&#xff0c;程序终止后即行删除。例如&#xff0c;很多编译器程序会在编译过程中创建临时文件。GNU C语言函数库为此而提供了一系列库函数。&#xff08;之所以有“一系列”的库函数&#xff0c;部分原因是由于这…

ASD光谱仪.asd格式光谱曲线文件转换为.txt格式的方法

本文介绍基于ViewSpec Pro软件&#xff0c;将ASD地物光谱仪获取到的.asd格式文件&#xff0c;批量转换为通用的.txt文本格式文件的方法。 ASD光谱仪是英国Malvern Panalytical公司研发的系列野外便携式全范围光谱辐射仪和光谱仪&#xff0c;可以获取地物的实时光谱信息。我们用…

Arch Linux 中的 AUR 是什么?您应该使用它吗?

Arch Linux AUR 存储库包含社区驱动的软件,如果您采取一些简单的预防措施,就可以安全使用。即使您不懂 shell 脚本,也可以使用一些指标来判断包是否安全。 AUR 是 Arch Linux 皇冠上的宝石之一,提供了数千个附加软件包。但是这个用户驱动的存储库使用起来安全吗,还是应该避…

你给企业创建百科了吗?5分钟带你看懂创建企业百度百科的实用技巧和注意事项

企业百度百科是一种企业在互联网上展示自身形象和产品的重要途径。通过在百度百科上创建企业页面&#xff0c;可以让更多的人了解企业的历史、文化、产品和服务等信息&#xff0c;提高企业知名度和品牌形象。分媒互动将介绍企业百度百科的创建方法和需要注意的事项。 一、企业百…

搭建IP代理池 - ProxyPool

前言 在爬虫开发中&#xff0c;我们经常会碰到ip封禁&#xff0c;访问限制的问题&#xff0c;今天主要分享个我在开发中用到过比较好用的ip代理池&#xff0c;希望有需要的小伙伴提供到帮助~ 简介 ProxyPool是一个简易高效的代理池&#xff0c;他可以在windows上搭配redis使…

【强化学习】常用算法之一 “SARSA”

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

飞控的安全性设计

针对安全性设计&#xff0c;就必须先考虑故障情况。一般来讲&#xff0c;飞控故障有以下几个方面&#xff1a; 1、通讯故障 飞行器与地面端&#xff08;遥控器或地面站等设备&#xff09;需要进行实时通信&#xff0c;如果通信发生故障&#xff0c;后果很严重&#xff0c;因此…

赛效:WPS文字(Word)中的页面背景如何删除

1&#xff1a;打开一个有背景颜色的文档。 2&#xff1a;在“页面布局”选项卡里点击“背景”&#xff0c;在下拉菜单里点击“删除页面背景”。 3&#xff1a;接下来我们看到&#xff0c;文档背景已经恢复了默认的颜色。 如果你想了解更多办公软件以及办公技巧&#xff0c;可以…

青大数据结构【2019】【五算法设计】

关键字: 简单选择排序、二叉树后序遍历 1) void Countsort(int A[],int B[],int n) {int i,j,count;for(i=0;i<n;i++){count=0;for(j=0;j<n;j++)if(A[j]<A[i])count++;B[count]=A[i];}} 2) 每个元素都要与n个元素(含自身)进行比较,故比较次数为n方 3) …

Redis之数据类型String、List、Hash、Set、Sorted Set(详细)

一、String数据类型 1、SET/GET/APPEND/STRLEN &#xff08;1&#xff09; APPEND &#xff08;2&#xff09; SET/STRLEN 2、 INCR/ DECR/INCRBY/DECRBY &#xff08;1&#xff09;INCR/ DECR &#xff08;2&#xff09; INCRBY/DECRBY INCRBY key increment&#xff1…

JavaWed第二章:HTML和CSS的知识制作静态网页

目录 前言 一.HTML和CSS的介绍 &#x1f496;HTML的基本框架 二.HTML常用标签大全 三.资源路径讲解 &#x1f496;路径 &#x1f496;图片 img标签讲解 &#x1f496;超链接标签讲解 四.CSS &#x1f496;CSS的引入方式 五.HTML页面布局 &#x1f496;盒子模型介绍 …

小米手机文件误删还有救,这10个工具请收好!

说到智能手机&#xff0c;小米以其令人印象深刻的功能和实惠的价格成为一个受欢迎的品牌。然而&#xff0c;与任何其他智能手机一样&#xff0c;小米设备上可能会由于各种原因而发生数据丢失。幸运的是&#xff0c;有多种恢复软件可以帮助您从小米设备中检索丢失或删除的数据。…

vue2 配置less

在vue2中配置less&#xff0c;需要安装less和less-loader npm install less less-loader5 --save-dev 直接安装less-loader会报错&#xff0c;提示如下&#xff1a; 安装less 3.0.0版本 npm install less3.3.0 然后在安装less-loader就ok啦。 在vue中使用&#xff0c;设置…

三维空间离散点如何拟合平面?

文章目录 0.引言1.算法原理2.算法实现 0.引言 在点云建模过程中&#xff0c;有时需要对扫描建模的点云进行标定&#xff0c;在实际使用中往往以地面做为参照平面&#xff0c;需要将扫描的三维空间点云进行拟合平面&#xff0c;以便纠正扫描结果。本文对三维空间离散点拟合平面算…