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

如果您进行实际的乘法运算,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 回答
1

您需要一种可以处理至少 110 位的类型,才能正确计算答案。我怀疑在您的平台上,Cunsigned long long可能只有 64 位,这还不够。溢出来了

您的 Java 程序的答案是正确的。

于 2013-11-13T09:22:56.140 回答
1

这是一个广泛使用的线性同余生成器:

(2862933555777941757 * N + 3037000493) % 2^64

模数部分由字长以零成本提供,在本例中为 64 位,因此未包含在 C 代码中。使用多精度算术的任何版本的代码都是错误的,它必须是 64 位的。一个好的状态数据类型是 uint64_t。

于 2015-12-29T23:29:14.560 回答
0

long longs 取决于平台。你不能指望它们是便携的,或者在其他机器上尺寸相同。

尝试做一个sizeof(unsigned long long)看看它在你的机器上实际有多大。虽然我的猜测是你正在溢出。

于 2013-11-13T09:20:44.777 回答