2

unsigned long long を使用する単純な C コードがあります。

#include<stdlib.h>
unsigned long long get_random_id(const char *imeiId)
{
    const unsigned long long MULT = 2862933555777941757LL;
    const unsigned long long ADDEND = 3037000493LL;
    unsigned long long newId, oldId;
    oldId = atoll(imeiId);
    newId = MULT * oldId + ADDEND;
    return newId;
}
void main()
{
  printf("%llu",get_random_id("351746051295833"));
}

これを Java コードに変換することになっているので、次のように BigInteger を使用しています。

public static void main(String args[]) {
        System.out.println(get_random_id("351746051295833"));
    }
    static BigInteger get_random_id(String imeiId) {
        final String MULT_STRING = "2862933555777941757";
        final String ADDEND_STRING = "3037000493";

        BigInteger MULT =  new BigInteger(MULT_STRING);
        BigInteger ADDEND = new BigInteger(ADDEND_STRING);
        BigInteger oldId = new BigInteger(imeiId);
        BigInteger temp = MULT.multiply(oldId);
        BigInteger newId = temp.add(ADDEND);
        return newId;
    }

ここでの問題は、Java と C コードで同じ出力が得られないことです。C コードの場合、10076018645131828514 を取得しています。Java コードの場合、1007025573367229468539210487799074 を取得しています。

同じ入力に対するこれらの異なる出力を理解できません。

PS: Ubuntu 32 ビット マシンでコードを実行し、gcc コンパイラを使用しています。

4

5 に答える 5

3

unsigned long long長さが制限された整数形式です (おそらく64 ビット以上)。つまり、2 64 -1 より大きい値は保持できません。

ABigIntegerは、任意の長さの整数形式です。つまり、a に格納される数値のサイズはBigInteger、使用可能なメモリによってのみ効果的に制限されます (また、配列のサイズなどの JVM の制限もありますが、かなり大きいです)。

C プログラムの計算のどこかでunsigned long longオーバーフローが発生し、カットオフ結果が得られます。

それは起こりませんBigInteger(静かにオーバーフローすることはありません)。正確な結果が得られるだけです。

オーバーフローをエミュレートするBigIntegerには、目的のビット マスク (64 セット ビット) を保持する を作成し、 を使用myValue.and(MASK)して「オーバーフロー」結果を取得します。

ただし、オーバーフローが発生する可能性のあるすべてのステップでそれを行う必要があります。そして、それは確かに C コードよりも遅くなります。

于 2013-11-13T09:19:51.147 に答える
1

答えを正しく計算するには、少なくとも 110 ビットを処理できる型が必要です。あなたのプラットフォームでは、Cunsigned long longはおそらく 64 ビットしかないので、十分ではないと思います。あふれています。

Java プログラムからの答えは正しいです。

于 2013-11-13T09:22:56.140 に答える
1

実際の乗算を行う場合、Java の出力は正しいです。

Pythonを使用して以下を見つけました:

>>> 2862933555777941757 * 351746051295833 + 3037000493
1007025573367229468539210487799074L

次に、C コードで得ているものを取得します。

>>> 2862933555777941757 * 351746051295833 + 3037000493
1007025573367229468539210487799074L
>>> _ % (2**64)   # Previous result mod 2 ^ 64 (**Assumming ULL is 64 bits on your system**)
10076018645131828514L  # This is what you have as the output of your C code.

署名されていない長い長いラップアラウンドがあります。:)

于 2013-11-13T09:22:00.687 に答える
0

long longs はプラットフォームに依存します。それらが移植可能である、または他のマシンで同じサイズであるとは期待できません。

を実行してsizeof(unsigned long long)、マシン上で実際にどれくらい大きいかを確認してください。私の推測では、あなたはオーバーフローしていると思います。

于 2013-11-13T09:20:44.777 に答える