8

I wrote a checksum calculation function in android/java. the function as follows

void CalculateCheckSum( byte[] bytes ){
     short CheckSum = 0, i = 0;
     for( i = 0; i < bytes.length; i++ ){
        CheckSum = (short) ((short)CheckSum + (short)bytes[i]);
     }

     Log.i("Checksum", Integer.toHexString(CheckSum));
}

input values for calculation of checksum are 0xEF, 0x01, 0xEF, 0x01, 0x33, 0x0C, 0xB8, 0xE5, 0xFC, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF. I manually calculated the checksum value and result is 0xCE4. When using the above function i get answer as 0xFFFFFFE4. Is any error in my calculation, if yes then please correct me.

thanks

Riskhan
  • 4,434
  • 12
  • 50
  • 76

6 Answers6

2

Use a debugger and debug your code. Generally though, if you keep adding stuff up, even if you use an int or a long, it is bound to overflow at some point, so you will get unexpected results. Best to use a standard checksum algorithm or one of the already available classes such as CRC32 or Adler31. As for your code, you seem to be treating the result as an integer, so why cast to short in the first place?

Java does all arithmetic calculations using int's, so your bytes get converted to int and the ones that don't fit into a byte will look like this as int's: ffffffef (-17). Naturally you only need the actual byte value, so you need to zero out everything else using (0xff & b). So your loop than becomes something like this:

  int checkSum = 0;

  for(byte b : bytes){
    checkSum += (0xff & b);
  }
Nikolay Elenkov
  • 52,576
  • 10
  • 84
  • 84
  • I want to send some packet to an embedded equipment that uses above checksum method to calculate. so i can't change CRC32 or other – Riskhan Sep 11 '12 at 07:37
2

The problem here is the (short) cast of bytes[i]. It extends the sign. You should change (short)bytes[i] to (bytes[i] & 0xff). This will give you the correct answer.

It has nothing to do with byte overflow, contrary to most of the other answers. You don't have to change the array type either.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

byte according to Java Docs :

The value of a byte is ranged between 2^(-7) and (2^7)-1 (-128 to 127).

But your value 0xEF (in decimal 239) has already reached the limit of a byte. That's what cause the sum give the wrong numbers.

Aprian
  • 1,718
  • 1
  • 14
  • 24
  • Is any data type that supports 8 bit value ( ie 0-255) in java – Riskhan Sep 11 '12 at 07:38
  • There is no `unsigned` primitive type in java afaik. But you can find other dependencies which provides `unsigned` type. – Aprian Sep 11 '12 at 07:45
  • 1
    try this [link](http://stackoverflow.com/questions/4266756/can-we-make-unsigned-byte-in-java) – Aprian Sep 11 '12 at 07:49
  • 1
    0xEF fits into a byte. It just takes the value -17 when you use it in an expression. That by itself won't disturb the calculation. – user207421 Sep 11 '12 at 08:00
1

As mentioned above by aprian, while byte has the necessary 8 bits for your hex values, it can only store values between -128 and 127. So a quick and easy solution would be to use the next bigger primitive, in this case short.

short shorts[] = {0xEF, 0x01, 0xEF, 0x01, 0x33, 0x0C, 0xB8, 0xE5, 0xFC, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

int checkSum = 0;

for( short s : shorts){
    checkSum = checkSum + s;
}

System.out.println("Checksum: " + Integer.toHexString(checkSum));

That gives me the output:

Checksum: ce4

Of course this means you might have to convert your byte array beforehand.

Sebastian_H
  • 349
  • 3
  • 13
0

finally i got...

corrected code

void CalculateCheckSum( byte[] bytes ){
         short CheckSum = 0, i = 0;
         for( i = 0; i < bytes.length; i++){
              CheckSum += (short)(bytes[i] & 0xFF);
         }
         Log.i("Checksum", Integer.toHexString(CheckSum));
    }

thanks to aprian and others

Riskhan
  • 4,434
  • 12
  • 50
  • 76
  • Thanks to Aprian? He was completely wrong, and he didn't give you this code. Only two answers gave you this code, and you should accept one of those, not your own. Posting your own when those others exist is a waste of time and space. – user207421 Jan 29 '18 at 06:19
-1

You should use integers as input if you convert them with:

    String CalculateCheckSum( Integer[] bytes ){
        Integer CheckSum = 0, i = 0;
        for( i = 0; i < bytes.length; i++ ){
            CheckSum += bytes[i];
        }
        return Integer.toHexString(CheckSum);
    }

this will return the expected 0xCE4 hope this fixed your problem

Casabian
  • 308
  • 2
  • 8