Java中多项式x^16 + x^12 + x^5 + 1计算CCITT标准CRC
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24694713/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calculation of CCITT standard CRC with polynomial x^16 + x^12 + x^5 + 1 in Java
提问by AdrianES
I need help with calculating of CCITT standard CRC with polynomial x^16 + x^12 + x^5 + 1 (0x1081) in Java. I have tried many examples on the internet but every one of them returns other values than the ones in the example.
我需要在 Java 中使用多项式 x^16 + x^12 + x^5 + 1 (0x1081) 计算 CCITT 标准 CRC 的帮助。我在互联网上尝试了很多示例,但每个示例都返回示例中的值以外的其他值。
For example for this array [0xFC] [05] [11] the result needs to be [27] [56].
例如,对于这个数组 [0xFC] [05] [11],结果需要是 [27] [56]。
Using this code:
使用此代码:
public static void main(String[] args) {
byte[] array = new byte[3];
array[0] = (byte) 0xFC;
array[1] = (byte) 0x05;
array[2] = (byte) 0x11;
// array[3] = (byte) 0x00;
// array[4] = (byte) 0x00;
System.out.println(Integer.toHexString(crc16(array)));
}
private static final int POLYNOMIAL = 0x1081;
private static final int PRESET_VALUE = 0xFFFF;
public static int crc16(byte[] data) {
int current_crc_value = PRESET_VALUE;
for (int i = 0; i < data.length; i++) {
current_crc_value ^= data[i] & 0xFF;
for (int j = 0; j < 8; j++) {
if ((current_crc_value & 1) != 0) {
current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
} else {
current_crc_value = current_crc_value >>> 1;
}
}
}
current_crc_value = ~current_crc_value;
return current_crc_value & 0xFFFF;
}
I get result FA DE
not [27] [56]
我得到的结果FA DE
不是 [27] [56]
Using this code:
使用此代码:
public static void main(String[] args) {
int crc = 0x0000;
int polynomial = 0x1081;
// byte[] testBytes = "123456789".getBytes("ASCII");
// byte[] array = args[0].getBytes();
byte[] array = new byte[3];
array[0] = (byte) 0xFC;
array[1] = (byte) 0x05;
array[2] = (byte) 0x11;
for (byte b : array) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7-i) & 1) == 1);
boolean c15 = ((crc >> 15 & 1) == 1);
crc <<= 1;
if (c15 ^ bit) crc ^= polynomial;
}
}
crc &= 0xffff;
System.out.println("CRC16-CCITT = " + Integer.toHexString(crc));
}
I get this CRC16-CCITT = 8dca
我明白了 CRC16-CCITT = 8dca
Using this code:
使用此代码:
private final int polynomial = 0x1081;
private int[] table = new int[256];
public int ComputeChecksum(int[] bytes) {
int crc = 0xffff;
for (int i = 0; i < bytes.length; ++i) {
int index = (crc ^ bytes[i]) % 256;
crc = (crc >> 8) ^ table[index];
}
return crc;
}
public CRC162() {
int value;
int temp;
for (int i = 0; i < table.length; ++i) {
value = 0;
temp = i;
for (byte j = 0; j < 8; ++j) {
if (((value ^ temp) & 0x0001) != 0) {
value = (value >> 1) ^ polynomial;
} else {
value >>= 1;
}
temp >>= 1;
}
table[i] = value;
}
}
public static void main(String[] args) {
CRC162 c = new CRC162();
int[] arr = new int[]{0xFC, 0x05, 0x11};
System.out.println(Integer.toHexString(c.ComputeChecksum(arr)));
}
I get this 521
我明白了 521
Hope someone can help me. I need this for communication with device using ID003 protocol.
希望可以有人帮帮我。我需要它来与使用 ID003 协议的设备进行通信。
EDIT: Using this online calculator at http://www.lammertbies.nl/comm/info/crc-calculation.htmlfor input FC0511 i get 0x2756 right from CRC-CCITT (Kermit).
编辑:使用http://www.lammertbies.nl/comm/info/crc-calculation.html 上的这个在线计算器输入 FC0511 我从 CRC-CCITT (Kermit) 得到 0x2756。
采纳答案by Serge Ballesta
Here is another version of the Kermit CRC. This one is a direct translation from the C codes in http://www.lammertbies.nl/comm/info/crc-calculation.html. The optimisation is that a table of CRC value for any byte is pre-computed at class loading time, and so the remaining of CRC computations is much simpler.
这是 Kermit CRC 的另一个版本。这是从http://www.lammertbies.nl/comm/info/crc-calculation.html 中的 C 代码的直接翻译。优化是在类加载时预先计算任何字节的CRC值表,因此剩余的CRC计算要简单得多。
public class Crc {
private static final int POLYNOMIAL = 0x8408;
private static final int PRESET = 0;
static private int[] tab;
static {
tab = new int[256];
for (int i = 0; i < 256; i++) {
tab[i] = initial((byte) i);
}
}
private static int initial(byte c) {
int crc = 0;
for (int j = 0; j < 8; j++) {
if (((crc ^ c) & 1) == 1) {
crc = ((crc >> 1) ^ POLYNOMIAL);
} else {
crc = (crc >> 1);
}
c = (byte) (c >> 1);
}
return crc;
}
private static int update_crc(int crc, byte c) {
int cc = (0xff & c);
int tmp = (crc ^ cc);
crc = (crc >> 8) ^ tab[tmp & 0xff];
return crc;
}
private static int swab(int n) {
return (((n & 0xFF00) >> 8) + ((n & 0xFF) << 8));
}
public static int crc(String str) {
return crcb(str.getBytes());
}
public static int crcb(byte... i) {
int crc = PRESET;
for (byte c : i) {
crc = update_crc(crc, c);
}
return swab(crc);
}
public static void main(String[] args) {
int crc = Crc.crcb((byte) 0xFC, (byte) 5, (byte) 0x11);
System.out.println(Integer.toHexString(crc));
crc = Crc.crc("123456789");
System.out.println(Integer.toHexString(crc));
}
}
The output is as expected :
输出符合预期:
2756
8921
回答by Mark Adler
x^16 + x^12 + x^5 + 1 is not 0x1081. It is 0x1021. x^5 is 20, not 80. (Note that the x^16 is dropped.)
x^16 + x^12 + x^5 + 1 不是 0x1081。它是 0x1021。x^5 是 20,而不是 80。(注意 x^16 被删除了。)
Furthermore, the Kermit CRC that you need is reflected, so the polynomial is reversed giving 0x8408.
此外,您需要的 Kermit CRC 被反映,因此多项式被反转给出 0x8408。
For this CRC, you initialize with zero and do not complement the result.
对于此 CRC,您用零初始化并且不对结果进行补码。
So modifying your first example accordingly, this computes what you want:
因此,相应地修改您的第一个示例,这将计算您想要的内容:
public static void main(String[] args) {
byte[] array = new byte[3];
array[0] = (byte) 0xFC;
array[1] = (byte) 0x05;
array[2] = (byte) 0x11;
// array[3] = (byte) 0x00;
// array[4] = (byte) 0x00;
System.out.println(Integer.toHexString(crc16(array)));
}
private static final int POLYNOMIAL = 0x8408;
private static final int PRESET_VALUE = 0;
public static int crc16(byte[] data) {
int current_crc_value = PRESET_VALUE;
for (int i = 0; i < data.length; i++) {
current_crc_value ^= data[i] & 0xFF;
for (int j = 0; j < 8; j++) {
if ((current_crc_value & 1) != 0) {
current_crc_value = (current_crc_value >>> 1) ^ POLYNOMIAL;
} else {
current_crc_value = current_crc_value >>> 1;
}
}
}
return current_crc_value & 0xFFFF;
}
回答by Jan Bobis
/**
* converts the given String to CRC16
*
* @param inputStr
* - the input string to get the CRC
* @param polynomial
* - the polynomial (divisor)
* @param crc
* - the CRC mask
* @param isHex
* - if true, treat input string as hex, otherwise, treat as
* ASCII
* @return
*/
public static String getCRC16CCITT(String inputStr, int polynomial,
int crc, boolean isHex) {
int strLen = inputStr.length();
int[] intArray;
if (isHex) {
if (strLen % 2 != 0) {
inputStr = inputStr.substring(0, strLen - 1) + "0"
+ inputStr.substring(strLen - 1, strLen);
strLen++;
}
intArray = new int[strLen / 2];
int ctr = 0;
for (int n = 0; n < strLen; n += 2) {
intArray[ctr] = Integer.valueOf(inputStr.substring(n, n + 2), 16);
ctr++;
}
} else {
intArray = new int[inputStr.getBytes().length];
int ctr=0;
for(byte b : inputStr.getBytes()){
intArray[ctr] = b;
ctr++;
}
}
// main code for computing the 16-bit CRC-CCITT
for (int b : intArray) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((crc >> 15 & 1) == 1);
crc <<= 1;
if (c15 ^ bit)
crc ^= polynomial;
}
}
crc &= 0xFFFF;
return Integer.toHexString(crc).toUpperCase();
}
Works for both ASCII and HEX computation.
适用于 ASCII 和 HEX 计算。
public static void main(String args[]) {
String testStr = "9142656";
// XModem ASCII
System.out.println("CRC-CCITT (XModem) Ascii: "
+ getCRC16CCITT(testStr, 0x1021, 0x0000, false));
// 0xFFFF ASCII
System.out.println("CRC-CCITT (0xFFFF) Ascii: "
+ getCRC16CCITT(testStr, 0x1021, 0xFFFF, false));
// 0x1D0F ASCII
System.out.println("CRC-CCITT (0x1D0F) Ascii: "
+ getCRC16CCITT(testStr, 0x1021, 0x1D0F, false));
// XModem Hex
System.out.println("CRC-CCITT (XModem) Hex: "
+ getCRC16CCITT(testStr, 0x1021, 0x0000, true));
// 0xFFFF Hex
System.out.println("CRC-CCITT (0xFFFF) Hex: "
+ getCRC16CCITT(testStr, 0x1021, 0xFFFF, true));
// 0x1D0F Hex
System.out.println("CRC-CCITT (0x1D0F) Hex: "
+ getCRC16CCITT(testStr, 0x1021, 0x1D0F, true));
}
Output:
输出:
CRC-CCITT (XModem) Ascii: 87F4
CRC-CCITT (0xFFFF) Ascii: 763A
CRC-CCITT (0x1D0F) Ascii: 9F86
CRC-CCITT (XModem) Hex: 57FF
CRC-CCITT (0xFFFF) Hex: D33F
CRC-CCITT (0x1D0F) Hex: 59EF
CRC-CCITT (XModem) Ascii: 87F4
CRC-CCITT (0xFFFF) Ascii: 763A
CRC-CCITT (0x1D0F) Ascii: 9F86
CRC-CCITT (XModem) Hex: 57FF
CRC-CCITT (0xFFCCITT) Hex: 763A
CRC-CCITT (0x1D0F) ) 十六进制:59EF
Solution is based from the sample found in princeton university http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java
解决方案基于普林斯顿大学http://introcs.cs.princeton.edu/java/61data/CRC16CCITT.java 中的示例
回答by Leandro S
This is not mine but worked perfect for me, "DatatypeConverter" is something i already have in my proyect. This is a real world example for me and works.
这不是我的,但对我来说很完美,“DatatypeConverter”是我在我的项目中已经拥有的东西。这对我来说是一个真实的例子并且有效。
* Reads in a sequence of bytes and prints out its 16 bit
* Cylcic Redundancy Check (CRC-CCIIT 0xFFFF).
*
* 1 + x + x^5 + x^12 + x^16 is irreducible polynomial.
import javax.xml.bind.DatatypeConverter;
public class CRC16CCITT {
public static void main(String[] args) {
int crc = 0xFFFF; // initial value
int polynomial = 0x1021; // 0001 0000 0010 0001 (0, 5, 12), in your case: 0x1081
// CRC of this should be 28570
byte[] testBytes = DatatypeConverter.parseHexBinary("00000000000000000000FA00000002009F1D19B87475445E1122330000000000");
for (byte b : testBytes) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((crc >> 15 & 1) == 1);
crc <<= 1;
if (c15 ^ bit)
crc ^= polynomial;
}
}
crc &= 0xffff;
System.out.println("CRC16-CCITT = " + Integer.toHexString(crc));
// 6F9A = 28570
}
}