UVa OJ 128 - Software CRC (软件CRC)

Time limit: 3.000 seconds
限时:3.000秒

 

Problem
问题

You work for a company which uses lots of personal computers. Your boss, Dr Penny Pincher, has wanted to link the computers together for some time but has been unwilling to spend any money on the Ethernet boards you have recommended. You, unwittingly, have pointed out that each of the PCs has come from the vendor with an asynchronous serial port at no extra cost. Dr Pincher, of course, recognizes her opportunity and assigns you the task of writing the software necessary to allow communication between PCs.
你在一家有很多PC机的公司工作。你的老板是Penny Pincher博士,想把所有电脑都连接起来。你提出的建议是购买网卡,但她觉得太贵了。此时,你无意间想到这些计算机都来自同一个供货商,并且都有一个异步通信的串口可以直接使用而无需花钱。Pincher博士采纳了这个主意,并让你编写用于连通计算机(通过串口的异步通信方式)的软件。

You've read a bit about communications and know that every transmission is subject to error and that the typical solution to this problem is to append some error checking information to the end of each message. This information allows the receiving program to detect when a transmission error has occurred (in most cases). So, off you go to the library, borrow the biggest book on communications you can find and spend your weekend (unpaid overtime) reading about error checking.
后来,你在某次通信过程中读取了一些数据位,结果发现传输中出现了错误。解决这个问题的传统办法就是在每条报文的后面都附加一段错误校验信息。这样软件就可以利用这些校验信息来检测传输过程中是否出现了错误(在绝大多数情况下都有效)。在此后的一周里你天天去泡图书馆(在没有加班费的空闲时间),借了最厚的通信书籍查阅有关错误校验的知识。

Finally you decide that CRC (cyclic redundancy check) is the best error checking for your situation and write a note to Dr Pincher detailing the proposed error checking mechanism noted below.
最后你确定使用CRC(循环冗余校验)是解决当前问题的最佳方案,并给Pincher博士递交了一分关于错误校验机制的说明,如下:

CRC Generation
CRC的生成

The message to be transmitted is viewed as a long positive binary number. The first byte of the message is treated as the most significant byte of the binary number. The second byte is the next most significant, etc. This binary number will be called "m" (for message). Instead of transmitting "m" you will transmit a message, "m2", consisting of "m" followed by a two-byte CRC value.
传输的报文可以视为一个很长的二进制数。报文的1个字节是整个二进制数的最高位,第2个字节其次,等等。将此二进制数称为“m”(message, 报文),在传输m时要附加两个字节的CRC编码,称为“m2”。

The CRC value is chosen so that "m2" when divided by a certain 16-bit value "g" leaves a remainder of 0. This makes it easy for the receiving program to determine whether the message has been corrupted by transmission errors. It simply divides any message received by "g". If the remainder of the division is zero, it is assumed that no error has occurred.
选择的CRC码应该能使m2能被一个16位的数“g”整除,这样的话接收方软件就可以非常容易的确定消息在传输过程中是否出错。只需要将收到的每一条消息除以“g”,如果余数为0就表示没有错误发生。

You notice that most of the suggested values of "g" in the book are odd, but don't see any other similarities, so you select the value 34943 for "g" (the generator value).
你除了注意到书中建议的大多数“g”值都是奇数外没发现其它的规律,因此你选择“34943”作为“g”的值。

 

Input and Output
输入与输出

You are to devise an algorithm for calculating the CRC value corresponding to any message that might be sent. To test this algorithm you will write a program which reads lines (each line being all characters up to, but not including the end of line character) as input, and for each line calculates the CRC value for the message contained in the line, and writes the numeric value of the CRC bytes (in hexadecimal notation) on an output line. Each input line will contain no more than 1024 ASCII characters. The input is terminated by a line that contains a # in column 1. Note that each CRC printed should be in the range 0 to 34942 (decimal).
你要设计一种算法,为要发送的所有 报文计算出CRC码。为了测试你的算法,你还要写一个程序来读取每行输入的字串(每行都从开始一直到(但不包括)换行符结束),并为每一行字串表示的消息计算出CRC值,然后对应的输出一行,打印出CRC字节的数值。每行输入都不会超过1024个ASCII字符。首字符为#号的一行表示输入结束。注意每个CRC都应该在0到34942(十进制)的范围内。

 

Sample Input
输入示例

this is a test

A
#

 

Sample Output
输出示例

77 FD
00 00
0C 86

 

Analysis
分析

实际在通迅中使用的CRC校验码要比题目中描述的复杂得多,涉及的知识点也很广,这里仅介绍与题目相关的算法,了解其它内容请参见“循环冗余校验”(维基百科)。

本题最主要的算法就是将字符串看作一个很长的整数,然后执行除法取余。简单来讲,就是要实现大数的除法。我们先来看10进制的例子,请用笔计算:2357 ÷ 6。我们只关心余数,第一次在3上面试商3,下面得余数5;用5 × 10 + 5 = 55作为第二次被除数,商9得余数1;用1 × 10 + 7 = 17作第三次被除数,商2余5。注意到每次被除数的每一位去除以除数6得到的余数都要累计到下一位(乘以10再加下一位)。只要能保证被除数中每一位都大于除数,就可以避免出现借位的情况。将笔算除法推广到n进制,即得到大数除法。设p为一个n进制整数作为被除数,q为小于n的除数(即选择的校验码生成数):

p = a0n0 + a1n1 + ... + aknk

现在要求的是p ÷ q的余数rk,即r0 = p mod q,先从rk开始向前计算:

rk = aknk mod q
rk-1 = (rkn + ak-1nk-1) mod q
...
r0 = (r1n + a0n0) mod q

根据此递推公式就很容易处理大数的除法了。为了方便实现,在程序中可以使用216=65535进制或232=4294967295进制。这样在计算余数时,无需将上一个r乘以进制,只要左移16位或32位即可,最大限度的利用了寄存器和CPU的特性。

求得余数后,下一步就是要将余数转为校验码。设校验码为c,那么应满足:

(a0n0 + a1n1 + ... + aknk + c) mod q = 0

前面已求得:

(a0n0 + a1n1 + ... + aknk) mod q = r

显然,c的值不止一个,但最小的正值c可用如下公式来计算:

c = q - (nr mod q)

上式很容易理解,就不赘述了。至此,CRC码计算完成。这里还有一个要注意的地方,我们一般写程序和编译的机器环境(包括OJ系统运行的环境)都是x86架构的,也就意味着字节序是little-endian, 即在存储器中的所有整型数值都是高位在前低位在后。比如32位16进制数:AF045Bh,在内存中的顺序应该是:

5B 04 AF 00

如果我们直接将字符串的指针转为int型指针进行计算就会算错。必须先对每一组字节(整型变量大小的一组)先进行反转再作运算。

 

Solution
解答

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
int main(void) {typedef unsigned short word;char Bits[1032]; //存储输入的字符串cin.sync_with_stdio(false); //输入的数据量很大,关闭同步以加速cout << setbase(16) << setiosflags(ios::uppercase) << setfill('0');//循环处理输入的每一行字符串for (string Line; getline(cin, Line) && Line[0] != '#'; cout << endl) {word nGen = 34943, nLen = Line.length(), *pBit = (word*)Bits;//将字符串转存到静态数组中。x86的CPU字节序为little-endian,reverse_copy(Line.begin(), Line.end(), Bits); //反转为正字节序*(word*)(&Bits[nLen]) = 0; //将结尾后面的一些位都清零nLen = nLen / 2 + (nLen % 2 != 0); //计算作为int数组的长度long nRem = 0;//nRem表示余数//循环除所有的位,累加进位的余数,生成CRC码for (int i = nLen - 1; i >= 0; --i) {nRem = ((nRem << 16) + pBit[i]) % nGen;}if (nRem != 0) { //如果余数不为0,则需构造CRC码,算法见文档nRem = nGen - (nRem << 16) % nGen;} //下面按要求的格式输出CRC码unsigned char* pByte = (unsigned char*)&nRem;cout << setw(2) << (int)pByte[1] << ' ' << setw(2) << (int)pByte[0];}return 0;
}

转载于:https://www.cnblogs.com/devymex/archive/2010/08/28/1810480.html

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

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

相关文章

ipv4编址

IPv4的编址&#xff1a; IPv4的地址有32位&#xff0c;通过使用点分十进制法&#xff0c;将其划分成4个由“.”隔断的部分&#xff0c;每一个部分的取值是0~255 {2^0~(2^8)-1} IP地址是32位类似这样的二进制串&#xff1a;1100 0000 1111 1111 1111 1111 1111 1110&#xff08;…

基于 vue 的验证码组件

登录页面有个验证码&#xff0c;暂时没用到后台&#xff0c;在网上找了两个博客&#xff0c;记录一下。 一、直接写&#xff08;参考-UIEngineer&#xff09; 这个样式比较简单&#xff0c;直接在需要验证码的地方添加就行了。如果这个页面比较复杂&#xff0c;用组件会比较好…

Java 8 Friday:更多功能关系转换

过去&#xff0c;我们一直在每个星期五为您提供有关Java 8的新内容的新文章。这是一个非常令人兴奋的博客系列 &#xff0c;但我们想再次将重点放在Java和SQL的核心内容上。 我们仍然偶尔会写关于Java 8的博客&#xff0c;但不再是每个星期五&#xff08;有些人已经注意到&…

【WXS全局对象】Date

属性&#xff1a; 名称说明Date.parse( [dateString] )解析一个日期时间字符串&#xff0c;并返回 1970/1/1 午夜距离该日期时间的毫秒数。Date.UTC(year,month,day,hours,minutes,seconds,ms) 根据世界时返回 1970 年 1 月 1 日 到指定日期的毫秒数。 参数&#xff1a;year/m…

13个不可不知的ASP.NET MVC扩展点

ASP.NET MVC设计的主要原则之一是可扩展性。处理管线&#xff08;processing pipeline&#xff09;上的所有&#xff08;或大多数&#xff09;东西都是可替换的。因此&#xff0c;如果您不喜欢ASP.NET MVC所使用的约定&#xff08;或缺乏某些约定&#xff09;&#xff0c;您可以…

程序员常用的3大Web安全漏洞防御解决方案:XSS、CSRF及SQL注入(图文详解)

https://blog.csdn.net/ChenRui_yz/article/details/86489067 随着互联网的普及&#xff0c;网络安全变得越来越重要&#xff0c;程序员需要掌握最基本的web安全防范&#xff0c;下面列举一些常见的安全漏洞和对应的防御措施。01 常见的Web安全问题1.前端安全XSS 漏洞CSRF 漏洞…

在 HTML 中引入 vue.js 写页面

突然说要写两个页面&#xff08;只有两个页面&#xff0c;不是一个完整的项目。。&#xff09;&#xff0c;有点懵&#xff0c;不知道从哪下手&#xff0c;而且只对 vue 熟悉那么一丢丢&#xff0c;其他框架不是很熟悉。但是没办法鸭&#xff0c;只能硬着头皮去做了&#xff01…

JavaFX技巧14:StackPane子项-隐藏但不消失

另一个简短提示&#xff1a;Swing提供了一个名为CardLayout的布局管理器&#xff0c;该管理器管理容器内的一组组件&#xff08;卡&#xff09;&#xff0c;但始终仅显示其中一个。 方法CardLayout.show&#xff08;Container &#xff0c;String&#xff09;允许在组件/卡之间…

【WXS数据类型】Array

属性&#xff1a; 名称值类型说明[Array].constructor[String]返回值为“Array”,表示类型的结构字符串[Array].length[Number]返回数组长度 方法&#xff1a; 原型&#xff1a;[Array].toString() 说明&#xff1a;将数组转换成字符串&#xff0c;用逗号分隔每个元素 原型&am…

Mschart图表制作

首先一次安装这三个 &#xff08;1&#xff09;.Microsoft .NET Framework 3.5 的 Microsoft 图表控件 &#xff08;2&#xff09;.Microsoft .NET Framework 3.5 语言包的 Microsoft 图表控件 &#xff08;3&#xff09;.Microsoft Chart Controls Add-on for Microsoft Visua…

vue打包后,font格式错误

本地测试没有问题&#xff0c;项目打包以后&#xff0c;浏览器打开控制台&#xff0c;提示font格式错误&#xff1a; 把我的双引号给去掉了。。。-^- 不开心。 解决办法&#xff1a; 1. 把 font: 字体粗细 字体大小/行高 "字体样式"; 分开来写。 改成&#xff1a;…

获取可用密码算法的列表

您如何学习可用的密码算法&#xff1f; Java规范列出了几种必需的密码&#xff0c;摘要等&#xff0c;但是提供程序通常提供的不止这些。 幸运的是&#xff0c;这很容易了解我们系统上的可用内容。 public class ListAlgorithms {public static void main(String[] args) {//…

【...】小程序扩展运算符 ... 说明

小程序扩展运算符 ... &#xff0c;用来将一个对象展开。 以下示例&#xff1a; 1 <template is"objectCombine" data"{{...obj1, ...obj2, e: 5}}"></template> 1 Page({2 data: {3 obj1: {4 a: 1,5 b: 26 },7 o…

fhq_treap || BZOJ 3224: Tyvj 1728 普通平衡树 || Luogu P3369 【模板】普通平衡树

题面&#xff1a;【模板】普通平衡树 代码&#xff1a; 1 #include<cstdio>2 #include<cstring>3 #include<iostream>4 #include<cstdlib>5 using namespace std;6 inline int rd(){7 int x0,f1;char cgetchar();8 while(c<0||c>9){if(c…

关于Zend framework 里一段代码的疑问

初学框架 看了一些代码 有一些疑问 在此记录 1 publicfunction__isset($key)2 {3 returnthis->_engine->get_temlate_vars($key)!null;4 }我想这个函数返回的一定是一个bool值 但不知道get_temlate_vars($key)!null 这里面的!是怎么个用法 希望有知道的能告诉我一声 谢谢…

html笔记(四)弹性盒+响应式

大标题小节一、弹性盒1. 标准盒模型和怪异盒模型2. 弹性盒dipalay3. 与display配合使用的其他属性4. 弹性盒的对齐方式5. 弹性盒的默认特性二、响应式布局1. 媒体查询2. 怎样使用媒体查询3. 优缺点以及使用场景4. Meta 标签的定义5. 常见的属性操作三、多列布局四、移动端布局1…

【app.json】配置说明,不断更新中

app.json文件用来对微信小程序进行全局配置&#xff0c;决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。 注意&#xff1a; 1) json配置中键名、键值必须使用双引号&#xff0c;不能使用单引号。 2) 以下配置中除了page字段是必需设置&#xff0c;其它项目…

使用Java泛型的模板方法模式示例

如果发现除了某些部分外&#xff0c;您的许多例程完全相同&#xff0c;那么您可能需要考虑使用Template Method来消除容易出错的代码重复 。 这是一个示例&#xff1a;下面是两个做类似事情的类&#xff1a; 实例化并初始化Reader以从CSV文件读取。 阅读每一行并将其分解为令…

golang 使用错误总结

以下是平时一些总结&#xff0c;伙伴们如发现有误或者更好解决方案/其他一些问题一起分享出来&#xff0c;互相学习&#xff0c;共同进步 1 win下编译linux golang 可执行文件 &#xff0c;服务器上无法运行 几种问题定位&#xff1a; 1 查看服务器报错日志定位 2 查看web服务器…

享受Android应用程序的Java技术盛宴

Java™ 语言是 Android 开发人员所选的工具。Android 运行时使用自己的虚拟机Dalvik&#xff0c;这并不是多数程序开发人员使用的普通Java 虚拟机。Dalvik支持Java 编程语言的大部分功能——但并不是全部。在本文中&#xff0c;您将学习高级Java功能及其如何在Android中实现。这…