Преобразование функции контрольной суммы C ++ в Java

Я пытаюсь преобразовать эту контрольную сумму C ++ в Java, но пока мне не удалось. Что я делаю неправильно?

Что он должен делать?
Предполагается вернуть положительную контрольную сумму для буфера в OpenGL

Вот часть C

DWORD QuickChecksum(DWORD *data, int size){

if(!data) {
return 0x0;
}

DWORD sum;
DWORD tmp;
sum = *data;

for(int i = 1; i < (size/4); i++)
{
tmp = data[i];
tmp = (DWORD)(sum >> 29) + tmp;
tmp = (DWORD)(sum >> 17) + tmp;
sum = (DWORD)(sum << 3)  ^ tmp;
}

return sum;
}

И вот что я пробовал в Java. Насколько я знаю, DWORD является 32-битным, поэтому я использую int в long, чтобы получить неподписанное int, которое должно быть сделано в java с >>>?

Я так много смотрю на эту проблему, что ослепла.

public static long getChecksum(byte[] data, int size) {
long sum, tmp;
sum = getInt(new byte[]{data[0], data[1], data[2], data[3]},true) & 0xFF;
for(int I = 4; I < data.length; I += 4)
{
tmp = getInt(new byte[]{data[I],data[I+1],data[I+2],data[I+3]},true) & 0xFF;
tmp = (sum >>> 29) + tmp;
tmp = (sum >>> 17) + tmp;
sum = (sum << 3) ^ tmp;
}
return sum & 0xFF;
}

private static int getInt(byte[] bytes, boolean big) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
return bb.getInt();
}

Спасибо за вашу помощь!

1

Решение

Очевидная ошибка заключается в том, что в трех местах вы И входное слово и окончательная контрольная сумма с 0xffтеряя старшие 24 бита. Предположительно, вы пытаетесь уменьшить long значение до 32 бит, что требует AND с 0xffffffffL, Вам также необходимо преобразовать возвращаемое значение getInt() в long прежде чем сделать это, в противном случае вы все равно получите расширение знака, которое вы пытаетесь избежать.

Мой Java немного ржавый, но я уверен, что вы получите правильные результаты, если будете придерживаться int, пока вы используете >>> для сдвига вправо (как вы делаете).

У вас также есть ошибка, когда вы безоговорочно читаете первые четыре байта, не проверяя, что ввод не пустой.

Вам также нужно убедиться, что входные данные кратны 4 байтам; либо путем проверки длины, либо путем изменения его для работы с int[] скорее, чем byte[] как версия C делает. И, конечно, нет необходимости size параметр, так как массивы Java имеют свой размер.

Следующее должно дать те же результаты, что и версия C:

public static int checksum(int[] data)
{
if (data.length == 0) {
return 0;
}

int sum = data[0];
for (int i = 1; i < data.length; ++i) {
int tmp = data[i];
tmp = (sum >>> 29) + tmp;
tmp = (sum >>> 17) + tmp;
sum = (sum << 3)   ^ tmp;
}

return sum;
}
1

Другие решения

Версия C ++ возвращает 32 бита sum, но ваша версия Java делает & 0xFF, который только оставляет 8.

  1. Вы делаете беззнаковый сдвиг с >>> и все другие операции определены так, чтобы их результат в знаковом типе Java был равен той же операции над типом без знака C ++, за исключением интерпретации подписанного бита. Таким образом, вы можете использовать int Вот.
  2. Если вы продолжаете использовать longнужно использовать & 0xFFFFFFFF получить 32 бита.
0

В Java >>> выполняет сдвиг без знака, то есть он вставит значение бита 0 в новые сдвинутые биты, превратив отрицательное число в положительное. Смена подписи >> расширяет знаковый бит, который равен 1 для отрицательных значений, поэтому отрицательные числа остаются отрицательными.

Чтобы исправить свой код, хотя бы заменить 0xFF с 0xFFFFFFFF в вашем & операции. Кроме того, я думаю, что вам, возможно, придется делать это каждый раз, когда вы назначаете tmp а также sumне один раз после цикла (не уверен на 100%, придется пройти через код, чтобы увидеть, сохранятся ли правильные биты и не появятся ли дополнительные биты даже без ANDing, так что это лучше, чем потом сожалеть).

Я также добавил бы в качестве первого шага в методе:

if (data.length & 3 != 0)
throw new IllegalArgumentException("byte buffer size not multiple of 4");

Кроме того, я бы либо удалить size аргумент, или на самом деле использовать его вместо data.length (после проверки он действителен), если данные могут иметь больше байтов, чем вы хотите обработать.

0
По вопросам рекламы [email protected]