crc计算 delphi
Delphi与仪表之间的MODBUS通讯
Delphi与仪表之间的MODBUS通讯【摘要】在工控领域,经常会遇到各式各样的现场仪表,这些仪表分散在现场的各个位置,这样的话对管理人员和现场操作人员来说都非常不方便,那如何解决这个问题呢?此时就会用到一种方案,那就是配置上位机,用来集中控制这些仪表,这就是所谓的集散系统。
那么如何通过上位机与现场仪表通讯来获取仪表的数据,同时又能对仪表进行远程操作呢?这也就是今天要论述的课题。
在进行通信程序编写之前,我们首先得对现场仪表有一定的了解,最起码地是应该知道现场仪表支持什么通讯协议,需要设置哪些参数,然后才能展开下一步的工作。
【关键词】Delphi;ModBus;集散系统;多线程一、MODBUS通讯协议MODBUS是由莫迪康(现为施耐德公司的一个品牌)在1979年发明的,是全球第一个真正用于工业现场的总线协议。
MODBUS协议是应用于电子控制器上的一种通用语言,通过它,控制器之间或其他设备之间可以通信,它已经成为一通用工业标准。
有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。
它定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。
它描述了一控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。
它制定了消息域格局和内容的公共格式。
当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。
如果需要回应,控制器将生成反馈信息并用Modbus协议发出。
在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。
这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
二、VSD-6仪表简介VSD-6仪表是某厂家自己制作的一款仪表,它具有一个标准的MODBUS端口(二线制的RS485接囗),在一条RS485总线上可接入接出1至16台VSD-6控制仪表,可方便地同各种组态软件(如:组态王、WINCC、昆仑通态)直接连接通讯,也可以按照标准MODBUS(RTU)通讯协议自编程。
delphi 获取MAC地址
DT := DT-((TZ.Bias+TZ.StandardBias) / (24*60));
Result := DateTimeToStr(DT)+' '+WideCharToString(TZ.StandardName);
mymaclength:=length(mymac);
r:=sendarp(myip,0,@mymac,@mymaclength);
label1.caption:='errorcode:'+inttostr(r);
label2.caption:=format('%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x',[mymac[0],mymac[1],mymac[2],mymac[3],mymac[4],mymac[5]]);
Var
AI,Work : PIPAdapterInfo;
Size : Integer;
Res : Integer;
I : Integer;
Function MACToStr(ByteArr : PByte; Len : Integer) : String;
Begin
Result := '';
End;
Function GetAddrString(Addr : PIPAddrString) : String;
Begin
Result := '';
While (Addr <> nil) do Begin
DELPHI获取硬盘、CPU、网卡序列号
DELPHI获取硬盘、CPU、⽹卡序列号 //引⽤及TYPE变量申明usesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls,nb30; {重要引⽤}typePASTAT = ^TASTAT;TASTAT = recordadapter : TAdapterStatus;name_buf : TNameBuffer;end;TForm1 = class(TForm)Button1: TButton;Edit1: TEdit;Label1: TLabel;Label2: TLabel;Label3: TLabel;Edit2: TEdit;Edit3: TEdit;Button2: TButton;Edit4: TEdit;Label4: TLabel;procedure Button1Click(Sender: TObject);procedure Button2Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementation{$R *.dfm}typeTCPUID = array[1..4] of Longint;//取硬盘系列号:function GetIdeSerialNumber: pchar; //获取硬盘的出⼚系列号;const IDENTIFY_BUFFER_SIZE = 512;typeTIDERegs = packed recordbFeaturesReg: BYTE;bSectorCountReg: BYTE;bSectorNumberReg: BYTE;bCylLowReg: BYTE;bCylHighReg: BYTE;bDriveHeadReg: BYTE;bCommandReg: BYTE;bReserved: BYTE;end;TSendCmdInParams = packed recordcBufferSize: DWORD;irDriveRegs: TIDERegs;bDriveNumber: BYTE;bReserved: array[0..2] of Byte;dwReserved: array[0..3] of DWORD;bBuffer: array[0..0] of Byte;end;TIdSector = packed recordwGenConfig: Word;wNumCyls: Word;wReserved: Word;wNumHeads: Word;wBytesPerTrack: Word;wBytesPerSector: Word;wSectorsPerTrack: Word;wVendorUnique: array[0..2] of Word;sSerialNumber: array[0..19] of CHAR;wBufferType: Word;wBufferSize: Word;wECCSize: Word;sFirmwareRev: array[0..7] of Char;sModelNumber: array[0..39] of Char;wMoreVendorUnique: Word;wDoubleWordIO: Word;wCapabilities: Word;wReserved1: Word;wPIOTiming: Word;wDMATiming: Word;wBS: Word;wNumCurrentCyls: Word;wNumCurrentHeads: Word;wNumCurrentSectorsPerTrack: Word;ulCurrentSectorCapacity: DWORD;wMultSectorStuff: Word;ulTotalAddressableSectors: DWORD;wSingleWordDMA: Word;wMultiWordDMA: Word;bReserved: array[0..127] of BYTE;end;PIdSector = ^TIdSector;TDriverStatus = packed recordbDriverError: Byte;bIDEStatus: Byte;bReserved: array[0..1] of Byte;dwReserved: array[0..1] of DWORD;end;TSendCmdOutParams = packed recordcBufferSize: DWORD;DriverStatus: TDriverStatus;bBuffer: array[0..0] of BYTE;end;varhDevice: Thandle;cbBytesReturned: DWORD;SCIP: TSendCmdInParams;aIdOutCmd: array[0..(SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE-1)-1] of Byte; IdOutCmd: TSendCmdOutParams absolute aIdOutCmd;procedure ChangeByteOrder(var Data; Size: Integer);//函数中的过程varptr: Pchar;i: Integer;c: Char;beginptr := @Data;for I := 0 to (Size shr 1) - 1 do beginc := ptr^;ptr^ := (ptr + 1)^;(ptr + 1)^ := c;Inc(ptr, 2);end;end;begin //函数主体Result := '';if SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT thenbegin // Windows NT, Windows 2000hDevice := CreateFile('\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);endelse // Version Windows 95 OSR2, Windows 98hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);if hDevice = INVALID_HANDLE_VALUE then Exit;tryFillChar(SCIP, SizeOf(TSendCmdInParams) - 1, #0);FillChar(aIdOutCmd, SizeOf(aIdOutCmd), #0);cbBytesReturned := 0;with SCIP dobegincBufferSize := IDENTIFY_BUFFER_SIZE;with irDriveRegs dobeginbSectorCountReg := 1;bSectorNumberReg := 1;bDriveHeadReg := $A0;bCommandReg := $EC;end;end;if not DeviceIoControl(hDevice, $0007C088, @SCIP, SizeOf(TSendCmdInParams) - 1,@aIdOutCmd, SizeOf(aIdOutCmd), cbBytesReturned, nil) then Exit;finallyCloseHandle(hDevice);end;with PIdSector(@IdOutCmd.bBuffer)^ dobeginChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));(Pchar(@sSerialNumber) + SizeOf(sSerialNumber))^:= #0;Result := Pchar(@sSerialNumber);end;end;//=================================================================//CPU系列号:FUNCTION GetCPUID : TCPUID; assembler; register;asmPUSH EBX {Save affected register}PUSH EDIMOV EDI,EAX {@Resukt}MOV EAX,1DW $A20F {CPUID Command}STOSD {CPUID[1]}MOV EAX,EBXSTOSD {CPUID[2]}MOV EAX,ECXSTOSD {CPUID[3]}MOV EAX,EDXSTOSD {CPUID[4]}POP EDI {Restore registers}POP EBXEND;function GetCPUIDStr:String;varCPUID:TCPUID;beginCPUID:=GetCPUID;Result:=IntToHex(CPUID[1],8)+IntToHex(CPUID[2],8)+IntToHex(CPUID[3],8)+IntToHex(CPUID[4],8); end;///================================================================================== ///取MAC(⾮集成⽹卡):function NBGetAdapterAddress(a: Integer): string;varNCB: TNCB; // Netbios control block //NetBios控制块ADAPTER: TADAPTERSTATUS; // Netbios adapter status//取⽹卡状态LANAENUM: TLANAENUM; // Netbios lanaintIdx: Integer; // Temporary work value//临时变量cRC: Char; // Netbios return code//NetBios返回值strTemp: string; // Temporary string//临时变量begin// InitializeResult := '';try// Zero control bloclZeroMemory(@NCB, SizeOf(NCB));// Issue enum commandNCB.ncb_command := Chr(NCBENUM);cRC := NetBios(@NCB);// Reissue enum commandNCB.ncb_buffer := @LANAENUM;NCB.ncb_length := SizeOf(LANAENUM);cRC := NetBios(@NCB);if Ord(cRC) <> 0 thenexit;// Reset adapterZeroMemory(@NCB, SizeOf(NCB));NCB.ncb_command := Chr(NCBRESET);NCB.ncb_lana_num := na[a];cRC := NetBios(@NCB);if Ord(cRC) <> 0 thenexit;// Get adapter addressZeroMemory(@NCB, SizeOf(NCB));NCB.ncb_command := Chr(NCBASTAT);NCB.ncb_lana_num := na[a];StrPCopy(NCB.ncb_callname, '*');NCB.ncb_buffer := @ADAPTER;NCB.ncb_length := SizeOf(ADAPTER);cRC := NetBios(@NCB);// Convert it to stringstrTemp := '';for intIdx := 0 to 5 dostrTemp := strTemp + InttoHex(Integer(ADAPTER.adapter_address[intIdx]), 2);Result := strTemp;finallyend;end;//========================================================================== //取MAC地址(集成⽹卡和⾮集成⽹卡):function Getmac:string;varncb : TNCB;s:string;adapt : TASTAT;lanaEnum : TLanaEnum;i, j, m : integer;strPart, strMac : string;beginFillChar(ncb, SizeOf(TNCB), 0);ncb.ncb_command := Char(NCBEnum);ncb.ncb_buffer := PChar(@lanaEnum);ncb.ncb_length := SizeOf(TLanaEnum);s:=Netbios(@ncb);for i := 0 to integer(lanaEnum.length)-1 dobeginFillChar(ncb, SizeOf(TNCB), 0);ncb.ncb_command := Char(NCBReset);ncb.ncb_lana_num := na[i];Netbios(@ncb);Netbios(@ncb);FillChar(ncb, SizeOf(TNCB), 0);ncb.ncb_command := Chr(NCBAstat);ncb.ncb_lana_num := na[i];ncb.ncb_callname := '* ';ncb.ncb_buffer := PChar(@adapt);ncb.ncb_length := SizeOf(TASTAT);m:=0;if (Win32Platform = VER_PLATFORM_WIN32_NT) thenm:=1;if m=1 thenbeginif Netbios(@ncb) = Chr(0) thenstrMac := '';for j := 0 to 5 dobeginstrPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);strMac := strMac + strPart + '-';end;SetLength(strMac, Length(strMac)-1);end;if m=0 thenif Netbios(@ncb) <> Chr(0) thenbeginstrMac := '';for j := 0 to 5 dobeginstrPart := IntToHex(integer(adapt.adapter.adapter_address[j]), 2);strMac := strMac + strPart + '-';end;SetLength(strMac, Length(strMac)-1);end;end;result:=strmac;end;function PartitionString(StrV,PrtSymbol: string): TStringList;variTemp: integer;beginresult := TStringList.Create;iTemp := pos(PrtSymbol,StrV);while iTemp>0 do beginif iTemp>1 then result.Append(copy(StrV,1,iTemp-1));delete(StrV,1,iTemp+length(PrtSymbol)-1);iTemp := pos(PrtSymbol,StrV);end;if Strv<>'' then result.Append(StrV);end;function MacStr():String;varStr:TStrings;i:Integer;MacStr:String;beginMacStr:='';Str:=TStringList.Create;Str:=PartitionString(Getmac,'-');for i:=0 to Str.Count-1 doMacStr:=MacStr+Str[i];Result:=MacStr;end;//============================================== //调⽤⽰例procedure TForm1.Button1Click(Sender: TObject);beginEdit3.Text:=strpas(GetIdeSerialNumber);//取硬盘号Edit2.text:=GetCPUIDStr;//CPU系列号edit4.Text:=NBGetAdapterAddress(12);//⾮集成⽹卡Edit1.text:=MacStr;//集成和⾮集成⽹卡end;。
Delphi运算符
delphi、c++与vb中的运算符2008-11-21 15:10Delphi_C++_VB 基本运算符号2007-02-25 11:55运算符赋值运算符Pascal :=C/C++ =BASIC =比较运算符运算符等于不等于小于(等于) 大于(等于)Pascal = <> <(=) >(=)C/C++ == != <(=) >(=)BASIC =或者Is <> <(=) >(=)逻辑运算符运算符逻辑与逻辑或逻辑非Pascal and or notC/C++ && || !BASIC And Or Not算术运算符运算符加减乘除(浮点数)除(整数)取模指数Pascal + - * / div mod 无C/C++ + - * / / % 无BASIC + - * / / Mod ^运算符与取反或异或左移右移Pascal and not or xor shl shrC/C++ & ~ | ^ << >>BASIC And Not Or Xor 无无Delphi运算符(2)2007-12-01 12:072.1.4 算术运算符算术运算符是执行算术运算如加、减、乘、除等的符号。
和其他大多数语言不同,在Pascal 中,进行乘、除时,整数和浮点数使用的符号不同。
例如:I := J div C;整数J和C作除法运算,并将结果赋值给I。
几种语言的算术运算符比较见表2-4。
表2-4 算术运算符2.1.5 按位运算符我们知道,变量在内存中是使用一些位(Bit)存储0或者1来保存的。
按位运算符就是对位进行运算的符号。
例如:varI: Byte; {Byte类型的取值范围在0~255,用8比特保存}beginI := 0; {此时I在内存中状态:00000000}I := not I; {对各位取反,因此变为"11111111",即255}end;几种语言的按位运算符比较见表2-5。
各种位运算经验(源码用delphi示例)
二进制中的1有奇数个还是偶数个我们可以用下面的代码来计算一个32位整数的二进制中1的个数的奇偶性,当输入数据的二进制表示里有偶数个数字1时程序输出0,有奇数个则输出1。
例如,1314520的二进制101000000111011011000中有9个1,则x=1314520时程序输出1。
vari,x,c:longint;beginreadln(x);c:=0;for i:=1 to 32 dobeginc:=c + x and 1;x:=x shr 1;end;writeln( c and 1 );end.但这样的效率并不高,位运算的神奇之处还没有体现出来。
同样是判断二进制中1的个数的奇偶性,下面这段代码就强了。
你能看出这个代码的原理吗?varx:longint;beginreadln(x);x:=x xor (x shr 1);x:=x xor (x shr 2);x:=x xor (x shr 4);x:=x xor (x shr 8);x:=x xor (x shr 16);writeln(x and 1);end.为了说明上面这段代码的原理,我们还是拿1314520出来说事。
1314520的二进制为101000000111011011000,第一次异或操作的结果如下:00000000000101000000111011011000XOR 0000000000010100000011101101100---------------------------------------00000000000111100000100110110100得到的结果是一个新的二进制数,其中右起第i位上的数表示原数中第i和i+1位上有奇数个1还是偶数个1。
比如,最右边那个0表示原数末两位有偶数个1,右起第3位上的1就表示原数的这个位置和前一个位置中有奇数个1。
对这个数进行第二次异或的结果如下:00000000000111100000100110110100XOR 000000000001111000001001101101---------------------------------------00000000000110011000101111011001结果里的每个1表示原数的该位置及其前面三个位置中共有奇数个1,每个0就表示原数对应的四个位置上共偶数个1。
Delphi下用SPCOMM对Modbus编程
Delphi下用SPCOMM对Modbus编程一、流程主体流程与普通的串口编程一样。
二、ModbusModbus普通串口不致的地方就是发送与返回的数据除遵循串口本身要求外,还有格式要求。
这里以读多位bit为例,其它的读者可查询Modbu功能码文档。
01功能码,读取多个线圈(位,bit),命令为16进制发送命令:01 01 48 00 00 10 2A 66返回命令: 01 01 02 FF 03 B8 0D三、例程例:串口SPCOMM控件名为:SPCOMM1;发送时钟名为:TimerCom;(1)控件属性设置mName := 'COM1'; //串中号表示 COM1、COM2等串口的名字SPCOMM1.BaudRate := 9600; //波特率根据实际需要设定的波特率,在串口打开后也可更改此值,实际波特率随之更改SPCOMM1.ParityCheck := False;//表示是否需要奇偶校验;SPCOMM1.Parity := None; //没有奇偶校验位; 奇偶校验位;SPCOMM1.ReadIntervalTimeOut:= 40; //信息发送后,40毫秒内返回的数据都算作一次返回。
注意要比发送间隔小。
TimerCom.Interval := 50 //时钟刷新间隔 TimerCom.Interval >SPCOMM1.ReadIntervalTimeOut(2)打开串口SPCOMM1.StopComm; //先关闭串口SPCOMM1.StartComm; //打开串口(3)形成发送命令CRCParityCheck16为对发送命令进行CRC校验,这里就不写了。
varbufByte:array[0..50000] of Byte;bufComReadChar :array[0..50000] of chari,nComReadLength:Integer;nCRC:Word;strSend:string;FnCRCFunt,FnCRCStart:Cardinal;//校验多项式,校验初始值 ]begin//先将数据形成16进制字符组成的字符串,然后再来校验发送strSend := '';strSend := IntToHex(1,2); //第1字节机组号strSend := strSend + '01'; //modbus 功能码01 读多个位操作strSend := strSend + IntToHex(StrToInt('$4800',4); //起始地址3、4字节strSend := strSend + IntToHex(16,4); //位总数, 5、6字节for i := 0 to 5 dobeginbufByte[i] := StrToInt('$' + copy(strSend,i*2+1,2));end;nCRC:=CRCParityCheck16(FnCRCStart ,FnCRCFunt,bufByte,6);strSend := strSend + IntToHex(nCRC,4);for i:=0 to 7 dobufComReadChar:=char(strtoint('$'+copy(strSend,i*2+1,2)));nComReadLength := 8;SPCOMM1.WriteCommData(bufComReadChar,nComReadLe ngth); //发送命令,参数:命令,命令长度end;(4)接受返回命令并解析SPCOMM1ReceiveData(Sender: TObject;Buffer: Pointer; BufferLength: Word);vari:integer;rbuf:array [1..1000] of byte ;begin//接收到数据,进行解析move(Buffer^,(pchar(@rbuf))^,BufferLength);for i := 1 to BufferLength dobeginstrTemp := strTemp + IntToHex(rbuf[i],2) + ' ';end;end;。
delphi 位运算简介及实用技巧
位运算简介及实用技巧去年年底写的关于位运算的日志是这个Blog里少数大受欢迎的文章之一,很多人都希望我能不断完善那篇文章。
后来我看到了不少其它的资料,学习到了更多关于位运算的知识,有了重新整理位运算技巧的想法。
从今天起我就开始写这一系列位运算讲解文章,与其说是原来那篇文章的follow-up,不如说是一个remake。
当然首先我还是从最基础的东西说起。
什么是位运算?程序中的所有数在计算机内存中都是以二进制的形式储存的。
位运算说穿了,就是直接对整数在内存中的二进制位进行操作。
比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。
举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理):110AND 1011----------0010 --> 2由于位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。
当然有人会说,这个快了有什么用,计算6 and 11没有什么实际意义啊。
这一系列的文章就将告诉你,位运算到底可以干什么,有些什么经典应用,以及如何用位运算优化你的程序。
Pascal和C中的位运算符号,下面的a和b都是整数类型,则:C语言 Pascal语言按位与 a & b a and b按位或 a | b a or b异或 a ^ b a xor ba取反 ~a not左移位 a << b a shl b右移位 a >> b a shr b注意C中的逻辑运算和位运算符号是不同的。
520|1314=1834,但520||1314=1,因为逻辑运算时520和1314都相当于True。
同样的,!a和~a也是有区别的。
各种位运算的使用:=== 1. and运算 ===and运算通常用于二进制取位操作,例如一个数 and 1的结果就是取二进制的最末位。
DELPHIXE11.1的几个数学取整
DELPHIXE11.1的几个数学取整Delphi下的四舍五入和取整,除了截取整数Trunc()之外,都是四舍六入五留双,即银行家算法。
但是好像又不全是这么回事儿。
要以实测为准。
例如3.15和3.25,修约时应分别得到3.2和3.2,而不是3.2和3.3。
这个算法在大学物理实验里也是这样。
但是也偶有争议,说是不同的Delphi版本编译器怎样怎样。
我比较了Delphi7和Delphi XE11.1,结果是一样的。
Round()在四舍六入,而SimpleRoundTo()仍然在四舍五入。
unit Unit1;interfaceusesWinapi.Windows, Winapi.Messages, System.SysUtils, System .Variants, System.Classes, Vcl.Graphics,Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;typeTForm1 = class(TForm)Button1: TButton;procedure Button1Click(Sender: TObject);private{ Private declarations }public{ Public declarations }end;varForm1: TForm1;implementationuses math;{$R *.dfm}function RoundClassic(R: Real): Int64;beginResult:= Trunc(R);if Frac(R) >= 0.5 thenResult:= Result + 1;end;function RoundThief(R: Real): Int64;beginR:=R+0.0000000000001;Result:= Trunc(R);if Frac(R) >= 0.5 thenResult:= Result + 1;end;procedure TForm1.Button1Click(Sender: TObject); vara: integer;b: real;begina := Trunc(0.35 * 10);showmessage('3.5取整数部分' + inttostr(a));a := round(2.5);showmessage('Round(2.5)四舍六入五留双,得到2而不是3:' + inttostr(a));b := simpleroundto(2.5, 0);showmessage('2.5取整,SimpleRounTo又开始传统四舍五入3:' + floattostr(b));b := simpleroundto(2.55, -1);showmessage('2.55留1位小数,SimpleRounT o又开始传统四舍五入2.6:' + floattostr(b));b := simpleroundto(2.45, -1);showmessage('2.45留1位小数,SimpleRounT o又开始传统四舍五入2.5:' + floattostr(b));a := ceil(123.4);showmessage('123.4向上取整:' + inttostr(a));a := ceil(-123.4);showmessage('-123.4向上取整:' + inttostr(a));a := floor(123.4);showmessage('123.4向下取整:' + inttostr(a));a := floor(-123.4);showmessage('-123.4向下取整:' + inttostr(a));a := RoundClassic(124.5);showmessage('124.5经典四舍五入:' + inttostr(a));a := RoundThief(124.5);showmessage('124.5取巧四舍五入:' + inttostr(a));//showmessage('33.025四舍五入:' + floattostr(RoundTo(33.025,-2)));end;end.。
Delphi SSE优化算法应用之三(CRC-32C (Castagnoli) 校验算法优化)
Delphi SSE优化算法应用之三(CRC-32C (Castagnoli) 校验算法优化)作者:CodeGame.CRC-32C (Castagnoli) 算法是iSCSI 和SCTP 数据校验的算法,和常用CRC-32-IEEE 802.3算法所不同的是多项式常数CRC32C是0x1EDC6F41 ,CRC32是0x04C11DB7 ,也就是说由此生成的CRC表不同外算法是一模一样.CRC32 常规算法如下:1.function _CRC32CX86(Data: PByte; aLength: Integer): DWORD;2.const3._CRC32CTable: array[0..255] of DWORD = (4.$00000000, $F26B8303, $E13B70F7, $1350F3F4, //CRC32C Table5.$C79A971F, $35F1141C, $26A1E7E8, $D4CA64EB,6.$8AD958CF, $78B2DBCC, $6BE22838, $9989AB3B,7.$4D43CFD0, $BF284CD3, $AC78BF27, $5E133C24,8.$105EC76F, $E235446C, $F165B798, $030E349B,9.$D7C45070, $25AFD373, $36FF2087, $C494A384,10.$9A879FA0, $68EC1CA3, $7BBCEF57, $89D76C54,11.$5D1D08BF, $AF768BBC, $BC267848, $4E4DFB4B,12.$20BD8EDE, $D2D60DDD, $C186FE29, $33ED7D2A,13.$E72719C1, $154C9AC2, $061C6936, $F477EA35,14.$AA64D611, $580F5512, $4B5FA6E6, $B93425E5,15.$6DFE410E, $9F95C20D, $8CC531F9, $7EAEB2FA,16.$30E349B1, $C288CAB2, $D1D83946, $23B3BA45,17.$F779DEAE, $05125DAD, $1642AE59, $E4292D5A,18.$BA3A117E, $4851927D, $5B016189, $A96AE28A,19.$7DA08661, $8FCB0562, $9C9BF696, $6EF07595,20.$417B1DBC, $B3109EBF, $A0406D4B, $522BEE48,21.$86E18AA3, $748A09A0, $67DAFA54, $95B17957,22.$CBA24573, $39C9C670, $2A993584, $D8F2B687,23.$0C38D26C, $FE53516F, $ED03A29B, $1F682198,24.$5125DAD3, $A34E59D0, $B01EAA24, $42752927,25.$96BF4DCC, $64D4CECF, $77843D3B, $85EFBE38,26.$DBFC821C, $2997011F, $3AC7F2EB, $C8AC71E8,27.$1C661503, $EE0D9600, $FD5D65F4, $0F36E6F7,28.$61C69362, $93AD1061, $80FDE395, $72966096,29.$A65C047D, $5437877E, $4767748A, $B50CF789,30.$EB1FCBAD, $197448AE, $0A24BB5A, $F84F3859,31.$2C855CB2, $DEEEDFB1, $CDBE2C45, $3FD5AF46,32.$7198540D, $83F3D70E, $90A324FA, $62C8A7F9,33.$B602C312, $44694011, $5739B3E5, $A55230E6,34.$FB410CC2, $092A8FC1, $1A7A7C35, $E811FF36,35.$3CDB9BDD, $CEB018DE, $DDE0EB2A, $2F8B6829,36.$82F63B78, $709DB87B, $63CD4B8F, $91A6C88C,37.$456CAC67, $B7072F64, $A457DC90, $563C5F93,38.$082F63B7, $FA44E0B4, $E9141340, $1B7F9043,39.$CFB5F4A8, $3DDE77AB, $2E8E845F, $DCE5075C,40.$92A8FC17, $60C37F14, $73938CE0, $81F80FE3,41.$55326B08, $A759E80B, $B4091BFF, $466298FC,42.$1871A4D8, $EA1A27DB, $F94AD42F, $0B21572C,43.$DFEB33C7, $2D80B0C4, $3ED04330, $CCBBC033,44.$A24BB5A6, $502036A5, $4370C551, $B11B4652,45.$65D122B9, $97BAA1BA, $84EA524E, $7681D14D,46.$2892ED69, $DAF96E6A, $C9A99D9E, $3BC21E9D,47.$EF087A76, $1D63F975, $0E330A81, $FC588982,48.$B21572C9, $407EF1CA, $532E023E, $A145813D,49.$758FE5D6, $87E466D5, $94B49521, $66DF1622,50.$38CC2A06, $CAA7A905, $D9F75AF1, $2B9CD9F2,51.$FF56BD19, $0D3D3E1A, $1E6DCDEE, $EC064EED,52.$C38D26C4, $31E6A5C7, $22B65633, $D0DDD530,53.$0417B1DB, $F67C32D8, $E52CC12C, $1747422F,54.$49547E0B, $BB3FFD08, $A86F0EFC, $5A048DFF,55.$8ECEE914, $7CA56A17, $6FF599E3, $9D9E1AE0,56.$D3D3E1AB, $21B862A8, $32E8915C, $C083125F,57.$144976B4, $E622F5B7, $F5720643, $07198540,58.$590AB964, $AB613A67, $B831C993, $4A5A4A90,59.$9E902E7B, $6CFBAD78, $7FAB5E8C, $8DC0DD8F,60.$E330A81A, $115B2B19, $020BD8ED, $F0605BEE,61.$24AA3F05, $D6C1BC06, $C5914FF2, $37FACCF1,62.$69E9F0D5, $9B8273D6, $88D28022, $7AB90321,63.$AE7367CA, $5C18E4C9, $4F48173D, $BD23943E,64.$F36E6F75, $0105EC76, $12551F82, $E03E9C81,65.$34F4F86A, $C69F7B69, $D5CF889D, $27A40B9E,66.$79B737BA, $8BDCB4B9, $988C474D, $6AE7C44E,67.$BE2DA0A5, $4C4623A6, $5F16D052, $AD7D5351);68.var69.i: Integer;71.Result := $FFFFFFFF;72.for I := 0 to aLength - 1 do73.begin74.Result := (Result shr 8) xor _CRC32CTable[(Result and $FF) xor Data^];75.Inc(Data);76.end;77.Result := not Result;78.end;CRC32C使用SSE4.2硬件指令优化算法部分代码如下:1.function _CRC32CSSE(Data: PByte; aLength: Integer): DWORD;2.asm3.push esi4.push edx5.push ecx6.mov esi,eax7.mov eax,$FFFFFFFF8.test edx,edx9.jz @Exit10.test esi,esi11.jz @Exit12.mov ecx,edx13.shr ecx, 214.test ecx,ecx15.jz @Exit16.xor edx,edx17.@Alignment:18.crc32 eax,[edx*4+esi]19.inc edx20.cmp edx,ecx21.jb @Alignment22.@Exit:23.not eax24.pop ecx25.pop edx26.pop esi以上2个不同实现方式在Intel Core i7 720QM 1.60GHz CPU上测试成绩如下:(数据采用随机算法生成,1M*100表示使用1M数据进行100次重复计算,数据量相当于100M)--------------------------------------------------------------------------------------| 数据量| 常规算法时间| 优化算法时间| 快出百分比|--------------------------------------------------------------------------------------| 1M *100 | X86 Time:390ms | SSE Time:32ms | 1218% |--------------------------------------------------------------------------------------| 4M *100 | X86 Time:1575ms | SSE Time:156ms | 1009% |--------------------------------------------------------------------------------------| 8M *100 | X86 Time:3136ms | SSE Time:280ms | 1120% |--------------------------------------------------------------------------------------| 32M *100 | X86 Time:12542ms | SSE Time:1092ms | 1148% |--------------------------------------------------------------------------------------通过对比可以清楚的看到使用SSE4.2中的新指令crc32可以比常规CRC32C算法要快出最少10倍的效率,Intel 新增的指令确实对常规某些算法提供了高效的解决方案,使用好它们将对我们在以后的开发中得到质的提升。
delphi 随机生成四则运算题目
delphi 随机生成四则运算题目在 Delphi 中,你可以使用随机数生成器来生成四则运算题目。
以下是一个简单的示例,演示如何生成两个随机数和一个随机运算符,然后计算结果:```delphiprogram RandomArithmeticQuestion;{$APPTYPE CONSOLE}usesSysUtils, Classes;vara, b, operatorChar, result: Integer;beginWriteLn('随机四则运算题目:');// 生成两个随机数a := RandomRange(1, 100);b := RandomRange(1, 100);// 生成一个随机运算符operatorChar := RandomRange(Ord('+'), Ord('-'));// 根据运算符计算结果case operatorChar ofOrd('+'): result := a + b;Ord('-'): result := a - b;Ord(''): result := a b;Ord('/'): result := a div b; // 注意:这里使用 div,因为 Delphi 没有直接支持整数除法操作符 '/'end;// 输出题目和答案WriteLn(Format('题目: %d %c %d = ?', [a, Chr(operatorChar), b])); WriteLn('答案: ' + IntToStr(result));end.```这个程序首先生成两个介于 1 和 100 之间的随机整数(`a` 和 `b`),然后选择一个随机的运算符(`+`、`-`、`` 或 `/`)。
根据运算符,程序计算结果并将题目和答案输出到控制台。
