1

この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を使用してunsigned 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();
}

よろしくお願いします!

4

3 に答える 3

1

明らかなエラーは、3つの場所で、入力ワードと最後のチェックサムに0xff、を加えて、上位24ビットを失うことです。longおそらく、値を32ビットに減らそうとしているので、ANDと。が必要0xffffffffLです。また、その前にの戻り値をに変換する必要がありますgetInt()longそうしないと、回避しようとしている符号拡張が引き続き取得されます。

私のJavaは少し錆びていますが、右シフトにint使用する限り(あなたがそうするように)、あなたがに固執することによって正しい結果を得るだろうと私はかなり確信しています。>>>

また、入力が空でないことを確認せずに最初の4バイトを無条件に読み取るというバグもあります。

また、入力が4バイトの倍数であることを確認する必要があります。長さを確認するか、Cバージョンのようint[]に動作するように長さを変更します。byte[]そしてもちろん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;
}
于 2012-12-12T11:58:39.607 に答える
0

Javaでは、>>>符号なしシフトを実行します。つまり、シフトインされた新しいビットにビット値0を挿入し、負の数を正に変換します。符号付きシフト>>は符号ビットを拡張します。これは負の値の場合は1であるため、負の数は負のままです。

コードを修正するには、少なくとも&操作でを置き換えます0xFF。また、ループの後で1回だけでなく、0xFFFFFFFFに割り当てるたびにそれを行う必要があると思います(100%確実ではありませんが、正しいビットが保持され、余分なビットが侵入しないかどうかを確認するためにコードを調べる必要があります) ANDを付けないので、後悔するより安全です)。tmpsum

また、メソッドの最初のものとして追加します。

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

また、データのバイト数が処理したいよりも多い場合に備えて、引数を削除するか、size代わりに(有効であることを確認した後)実際に使用します。data.length

于 2012-12-12T12:00:53.617 に答える
0

C ++バージョンは32ビットを返しますsumが、Javaバージョンはを返します& 0xFF。これは8ビットしか残しません。

  1. で符号なしシフトを実行し>>>、他のすべての演算は、符号付きJava型での結果が、符号付きビットの解釈を除いて、C++符号なし型での同じ演算と等しくなるように定義されます。したがって、実際にintここで使用できます。
  2. を使い続ける場合は、 32ビットを取得longするためにを使用する必要があります。& 0xFFFFFFFF
于 2012-12-12T12:02:56.023 に答える