在检测某个范围内的Kaprekar数时,在C ++中发现了这个问题。编号为77778 -
unsigned long long sq = pow(n, 2);
在
时返回6,049,417,284unsigned long long sq = n * n;
返回1,754,449,988
任何想法为什么?这是什么样的溢出,功率可以避免,但正常的n * n不会。
答案 0 :(得分:2)
假设您的n
是典型的int
或unsigned int
,原因是
这一行
unsigned long long sq = n * n;
相当于
unsigned long long sq = (int)(n * n);
因为在将结果赋给sq之前,首先会处理n * n(两者都是整数)。所以,这是一个溢出问题(欢迎使用 Stack Overflow 也是!)。
您可能还想通过搜索来了解这些术语overflow
和casting
(因为它们是计算中非常常见的问题,早期了解它们会有很大的帮助!)。
这与Kaprekar数字无关。在大多数情况下,机器int
是32位。因此,它只能处理值-2,147,483,648到2,147,483,647(或无符号整数计数器部分的0到4,294,967,295)。
因此处理n * n会给你:
n * n = 6,049,417,284 - 4,294,967,296 = 1,754,449,988 //overflow at (4,294,967,295 + 1)!
如果您事先进行施法:
unsigned int n = 77778;
unsigned long long sq = pow(n, 2);
unsigned long long sq2 = (unsigned long long)n * n; //note the casting here.
std::cout << sq << std::endl;
std::cout << sq2 << std::endl;
然后结果将是相同的,因为不会有溢出。
答案 1 :(得分:2)
您的n
被声明为32位int。您需要将其更改为long long或将操作强制转换为long long。
unsigned long long sq=(unsigned long long)n*n;
这将给出正确答案
答案 2 :(得分:1)
我怀疑n
被声明为unsigned int
,并且您的编译器使用的数据模型假定int
为32位宽。可以使用此类型表示的最大值为2 32 - 1 = 4294967295。超出此值的任何值都将会回滚。因此,分配4294967296将变为0,4294967297将变为1,依此类推。
你有溢出;由于两个操作数均为unsigned int
,因此结果类型也是相同的。该操作的真实结果是6049417284.将其分配给unsigned int
将(换行)并变为1754449988 = 6049417284 - 4294967296.此unsigned int
结果被分配给更宽的类型unsigned long long
,它没有改变价值。理解结果的类型(表达式的类型)和目标类型(将保存结果的变量的类型)之间的区别是必要的。
无符号类型中的环绕行为(更正式地模n)在C ++中是明确定义的,因此编译器可能不会警告您。
如果无符号整数溢出,则结果以模2 w 定义,其中w是该特定无符号整数中的位数。通过暗示,无符号整数永远不会为负。