3

我对 C/C++unsigned long long类型感到困惑,因为理论上它应该存储多达 2^64-1,这是一个 19 位十进制数字,但以下代码:

unsigned int x = 1000000u; //(One million)
unsigned long long k = (x*x);
cout << k << endl;

打印出 3567587328,这是不正确的。现在 1,000,000^2 结果为 1,000,000,000,000 - 12 位十进制数字,远低于 even 的限制signed long long。这怎么可能发生?它与我正在运行的系统有什么关系吗?(32 位 Ubuntu)

如果我需要 64 位系统来实现 64 位操作,那么就会出现另一个问题:大多数编译器使用线性同余生成器来生成随机数,如下所示:

x(t) = (a*x(t-1) + c) mod m.

a并且c通常是一个32位的大数,m是2^32-1 所以a*x(t-1)在进行模运算之前很有可能导致一个64位的数。

如果需要 64 位系统,那么自 1990 年代以来 gcc 如何在 16-32 位机器上生成随机数?

太感谢了。

4

3 回答 3

10

当然kunsigned long long,但是xunsigned int,因此也是x*x。您的表达式被计算为unsigned int,当超过无符号类型的限制时,这会导致通常的环绕。损坏完成后,将其转换为unsigned long long.

可能的修复:

  • x一个unsigned long long
  • unsigned long long k = ((unsigned long long)x*(unsigned long long)x);
  • unsigned long long k = (1ULL*x*x);
于 2013-03-10T21:25:47.623 回答
5

xunsigned int-->x*x也是unsigned int。如果乘法的结果超过 的最大值unsigned int,则会发生回绕。只有在这些操作之后,才会将结果分配给接收变量 ( k)。如果您希望结果是unsigned long long您需要将至少一个操作数提升为这种类型,例如:unsigned long long k = (unsigned long long)x * x;.

关于您的第二个问题:编译器通常不会生成数字,这是在运行时完成的。我不知道你从哪里得到的公式x(t) = (a*x(t-1) + c) mod m。假设这确实是公式,则有一些方法可以使中间结果有界:模运算可以应用于任何操作数或中间结果而不改变结果。因此x(t) = (a*x(t-1) + c) mod m = (a mod m) * (x(t-1) mod m) + c mod m

于 2013-03-10T21:39:13.913 回答
3

当您将右侧unsigned int的 an 与 an相乘时,结果为. 因此,它与被相乘的两个数字具有相同的限制,无论该值随后分配给.unsigned intunsigned intunsigned long long

但是,如果将unsigned int变量转换为unsigned long long,则结果将是 anunsigned long long并且值将不限于 an 的大小unsigned int

unsigned long long k = (((unsigned long long)x)*((unsigned long long)x));

那应该会给您想要的结果。

于 2013-03-10T21:28:52.080 回答