Java 8位二进制加法

Java 8位二进制加法,java,algorithm,delphi,binary,checksum,Java,Algorithm,Delphi,Binary,Checksum,有人能解释一下如何用8位二进制加法计算校验和吗?这是文档的摘录: 这是消息的一般形式: STX | TYPE | FS | DATA | FS | CHK | ETX STX是十六进制02 ETX是十六进制03 FS是十六进制15 “类型”是唯一的1字节消息标识符(例如,“p”表示轮询消息)。 “数据”包含可打印的ASCII字符 校验和 校验和是对和之间的所有字符(包括所有字符)计算的校验和是通过将所有包含的字符进行8位二进制相加,并假定第8位或奇偶校验位为零来计算的。超出第8位的进位丢失。8

有人能解释一下如何用8位二进制加法计算校验和吗?这是文档的摘录:

这是消息的一般形式:

STX | TYPE | FS | DATA | FS | CHK | ETX
STX是十六进制02

ETX是十六进制03

FS是十六进制15

“类型”是唯一的1字节消息标识符(例如,“p”表示轮询消息)。 “数据”包含可打印的ASCII字符

校验和


校验和是对
之间的所有字符(包括所有
字符)计算的校验和是通过将所有包含的字符进行8位二进制相加,并假定第8位或奇偶校验位为零来计算的。超出第8位的进位丢失。8位结果转换为两个可打印的ASCII十六进制字符,范围从00到FF,然后作为
插入数据流。十六进制字符A-F为大写。接收设备重新计算缓冲消息的校验和,并将其与接收到的校验和进行比较。比较是传输的后续确认(
)或否定确认(
)的基础。

将每个字符视为一个整数值。由于每个字符的高位都假定为零(因为在规范中没有说明需要检查它),因此使用类似以下内容(pseudo-C/C++/Java/which)屏蔽其值:

现在您只需添加(pseudo-C/C++/Java/where):

这将连续添加每个ASCII字符,并从结果和中删除超过第8位的所有内容。当您全部完成(C或编写糟糕的C++)时:

作为一种优化(如果您真的需要它——在这种情况下不太可能!),您可以推迟
s&=0xff
位,而是在校验和的使用点使用截断。不过,这不会为您节省太多性能,因为I/O的成本会高得多,并且可能会导致您在以后重构代码时忘记执行此操作。

这类(未经测试的)JavaScript函数解决了您的问题吗?
函数计算校验和(数据){
function calc_checksum( DATA ) {
  var i;
  var checksum = 0;
  for ( i = 0; i < DATA.length; ++i ) { 
    checksum += DATA[i];      // any carry just falls off the high-order end
  }
  return 0x7F & checksum;
}
var i;
var校验和=0;
对于(i=0;i

在Java中,您可以执行以下操作

byte[] bytes =
byte total = 0;
for(byte b: bytes) total += b;

OutputStream os = 
os.write(total);

此外,请使用以下功能

function Summatory(const Data: AnsiString): Byte;
var
    C: AnsiChar;
begin
    Result := 0;

    for C in Data do
    begin
        Result := Result + Ord(C);
    end;
end;
对于Delphi的旧版本,没有“For in”:

函数summary被声明为Byte,因此它将“忽略”超过第8位的进位。您可以传递所有要添加的字节

使用
SysUtils
中的函数
IntToHex
将8位结果转换为两个可打印的ASCII十六进制字符


例如:
ChkSum:=IntToHex(总和(数据),2)

当字节之和超过256时,上述答案均无效

OP可能试图将西门子Dimension EXL200化学分析仪与他的实验室信息系统连接起来

他发布的段落(关于校验和的规范)是从他们的手册中复制/粘贴的。 在过去的12个小时里,我一直在为这个特殊的问题绞尽脑汁,却找不到任何解决办法。 我包括西门子手册中提到的一些字符串,因为它们提供了校验和

您会注意到上面的所有答案都有效,但仅适用于部分字符串。 在其他情况下,手册中的校验和与我们使用上述方法得到的完全不同

我发布了两个例子,一个失败,一个成功=>相同的算法

为方便起见(由于协议使用十六进制字符,我将包含实际的字节数组,因此任何阅读此协议的人都可以使用自己选择的语言进行尝试)。 我希望有人能在这里找到解决方案:

  • 示例一:@Just My Correct Opinion的解决方案失败:
  • /***
    原始字符串:
    P9300110
    字节数组:
    {80, 28, 57, 51, 48, 48, 28, 49, 28, 49, 28, 48, 28}
    预期校验和:
    6C
    实际校验和:
    3A
    代码如下:
    ***/
    字节[]byteArry={80,28,57,51,48,48,28,49,28,48,28};
    字符串ss=新字符串(byteArry);
    int s=0;
    对于(int i=0;i
  • 例二:@Just My Correct Opinion的解决方案成功:
  • /***
    原始字符串:
    文科硕士
    字节数组:
    {77, 28, 65, 28, 28}
    预期校验和:
    E2
    实际校验和:
    E2
    代码如下:
    ***/
    字节[]byteArry={77,28,65,28,28};
    字符串ss=新字符串(byteArry);
    int s=0;
    对于(int i=0;i
    在上面的例子中,我注意到只要字节的总和超过某个值(我不能确定),它就会失败,但我认为大约是256。任何高于256的结果都不同于西门子员工想要的结果。 第一个例子以很大的差距超过了256,但第二个例子是226。手册中还有一个更小字节和的例子,上面的代码似乎可以工作,生成预期的校验和。 我不是一个很好的程序员,但我确信这与溢出有关


    巴尔加夫R.

    对我来说似乎很清楚。你不明白什么?你能给我举个例子(示例代码)吗?从来没有做过这样的事情…你需要在Delphi或Java中使用它吗?没关系,虽然这是在Delphi中,但我知道这两种语言。我认为OP是在寻找8位校验和,而不是7位校验和。Delphi示例代码+1-你应该使用(const Data:AnsiString)作为参数,但其余的都可以。对于旧版本的Delphi,没有“in”,您应该添加一个i局部变量,然后为i添加一个i局部变量 function calc_checksum( DATA ) { var i; var checksum = 0; for ( i = 0; i < DATA.length; ++i ) { checksum += DATA[i]; // any carry just falls off the high-order end } return 0x7F & checksum; }
    byte[] bytes =
    byte total = 0;
    for(byte b: bytes) total += b;
    
    OutputStream os = 
    os.write(total);
    
    function Summatory(const Data: AnsiString): Byte;
    var
        C: AnsiChar;
    begin
        Result := 0;
    
        for C in Data do
        begin
            Result := Result + Ord(C);
        end;
    end;
    
    function Summatory(const Data: AnsiString): Byte;
    var
        I: Integer;        
    begin
        Result := 0;
    
        for I := 1 to Length(Data) do
        begin
            Result := Result + Ord(Data[I]);
        end;
    end;
    
    /***
    
    RAW STRING:
    P<FS>9300<FS>1<FS>1<FS>0<FS>
    
    BYTE ARRAY:
    {80, 28, 57, 51, 48, 48, 28, 49, 28, 49, 28, 48, 28}
    
    EXPECTED CHECKSUM : 
    6C
    
    ACTUAL CHECKSUM : 
    3A
    
    CODE TO REPRODUCE BELOW:
    ***/
    
    byte[] byteArry = {80, 28, 57, 51, 48, 48, 28, 49, 28, 49, 28, 48, 28};
    String ss = new String(byteArry);
    int s = 0;
    
    for(int i = 0; i < ss.length(); i++)
        {
            s += ss.charAt(i) & 0x7f;
            s &= 0xff;
        }
        System.out.println(s);
        System.out.format("Checksum: %02X\n", s);
    }
    
    
    /***
    
    
    RAW STRING:
    M<FS>A<FS><FS>
    
    BYTE ARRAY:
    {77, 28, 65, 28, 28}
    
    EXPECTED CHECKSUM : 
    E2
    
    ACTUAL CHECKSUM : 
    E2
    
    CODE TO REPRODUCE BELOW:
    ***/
    
    byte[] byteArry = {77, 28, 65, 28, 28};
    String ss = new String(byteArry);
    int s = 0;
    
    for(int i = 0; i < ss.length(); i++)
        {
            s += ss.charAt(i) & 0x7f;
            s &= 0xff;
        }
        System.out.println(s);
        System.out.format("Checksum: %02X\n", s);
    }