无符号长整型无法存储大数值

4

我对 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的平方结果为1,000,000,000,000,是一个12位小数的数字,远远低于甚至signed long long的限制。这是怎么发生的呢?是否与我运行的系统有关?(32位Ubuntu)

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

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

ac通常是32位大数,m是2^32-1。因此,在模运算执行之前,a*x(t-1)很可能会产生一个64位数字。

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

非常感谢。


1
将 x 改为 long long 类型,它就可以工作了。 - brian beuning
3个回答

11

虽然kunsigned long long,但xunsigned int,因此x*x也是unsigned int。你的表达式计算结果为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);

非常感谢,我从未被教过 int*int 的结果在分配给其他变量之前会被包装成一个 int - Max

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


你的答案太棒了。顺便说一下,这个公式在许多编译器中使用不同的参数,如此处所述:http://en.wikipedia.org/wiki/Linear_congruential_generator。非常感谢。 - Max

3
当你把一个无符号整数与另一个无符号整数相乘时,右侧的结果也是一个无符号整数。因此,它的限制与被乘数有关,而不管将此值随后分配给一个无符号长整型(unsigned long long)的事实如何。
然而,如果你将无符号整数变量强制转换为无符号长整型,结果将是一个无符号长整型,其值不会被限制为无符号整型的大小。
unsigned long long k = (((unsigned long long)x)*((unsigned long long)x));

那样就可以得到你想要的结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接