无符号长长不会存储大数字

unsigned long long won't store big numbers

本文关键字:数字 存储 无符号      更新时间:2023-10-16

我对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.

ac通常为32位大数,m为2^32-1因此,在进行模运算之前,a*x(t-1)很有可能得到一个64位的数字。

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

万分感谢

当然kunsigned long long,但xunsigned int,因此x*x也是。表达式被计算为unsigned int,当超出unsigned类型的限制时,会导致通常的绕行。伤害完成后,将转换为unsigned long long

可能的修复:

  • make x and unsigned long long
  • unsigned long long k = ((unsigned long long)x*(unsigned long long)x);
  • unsigned long long k = (1ULL*x*x);

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 .

当您将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));