我对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位十进制数字,远低于偶数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位系统,那么自20世纪90年代以来gcc如何在16-32位机器上生成随机数?
万分感谢。
答案 0 :(得分:10)
当然k
为unsigned long long
,但x
为unsigned 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);
答案 1 :(得分:4)
x
是unsigned int
- &gt; 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
。
答案 2 :(得分:3)
当您将unsigned int
乘以右侧的unsigned int
时,结果为unsigned int
。因此,它与两个数字相乘的限制相同,无论此值随后被分配给unsigned long long
这一事实。
但是,如果您将unsigned int
变量转换为unsigned long long
,则结果将为unsigned long long
,并且该值不会限制为unsigned int
的大小。
unsigned long long k = (((unsigned long long)x)*((unsigned long long)x));
这应该会给你你想要的结果。