C++ 中的平方数,Kaprekar 数
Squaring number in c++, Kaprekar numbers
在 C++ 中检测范围内的 Kaprekar 数字时发现此问题。对于号码 77778 -
unsigned long long sq = pow(n, 2);
returns 6,049,417,284 而
unsigned long long sq = n * n;
returns 1,754,449,988
知道为什么吗?这是 pow 避免但正常 n*n 没有的某种溢出吗?
我怀疑 n
被声明为 unsigned int
,并且您的编译器使用的数据模型假定 int
为 32 位宽。可以用此类型表示的最大值为 232 - 1 = 4294967295。超出此值的任何值都会环绕。所以分配4294967296会变成0,4294967297会变成1,依此类推
你溢出了;由于两个操作数都是 unsigned int
,因此结果类型也将相同。该操作的真实结果将是 6049417284。将其分配给 unsigned int
将(换行)并变为 1754449988 = 6049417284 - 4294967296。此 unsigned int
结果分配给更宽的类型 unsigned long long
,这不会改变价值。有必要了解结果类型(表达式的类型)和目标类型(将保存结果的变量的类型)之间的区别。
无符号类型中的环绕行为(更正式地模 n)在 C++ 中定义明确,因此编译器可能不会警告您。
If an unsigned integer overflows, the result is defined modulo 2w, where w is the number of bits in that particular unsigned integer. By implication, an unsigned integer is never negative.
假设您的 n
是典型的 int
或 unsigned int
,这是因为
这一行
unsigned long long sq = n * n;
等同于
unsigned long long sq = (int)(n * n);
因为 n * n 将在将结果分配给 sq 之前首先处理(均为整数)。因此,这是一个 溢出 问题(欢迎来到 堆栈溢出也是!)。
您可能还想通过搜索更多地了解这些术语 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;
那么结果将是相同的,因为不会有 溢出。
您的 n
被声明为 32 位整数。您需要将其更改为 long long 或将操作强制转换为 long long。
unsigned long long sq=(unsigned long long)n*n;
这将给出正确答案
在 C++ 中检测范围内的 Kaprekar 数字时发现此问题。对于号码 77778 -
unsigned long long sq = pow(n, 2);
returns 6,049,417,284 而
unsigned long long sq = n * n;
returns 1,754,449,988
知道为什么吗?这是 pow 避免但正常 n*n 没有的某种溢出吗?
我怀疑 n
被声明为 unsigned int
,并且您的编译器使用的数据模型假定 int
为 32 位宽。可以用此类型表示的最大值为 232 - 1 = 4294967295。超出此值的任何值都会环绕。所以分配4294967296会变成0,4294967297会变成1,依此类推
你溢出了;由于两个操作数都是 unsigned int
,因此结果类型也将相同。该操作的真实结果将是 6049417284。将其分配给 unsigned int
将(换行)并变为 1754449988 = 6049417284 - 4294967296。此 unsigned int
结果分配给更宽的类型 unsigned long long
,这不会改变价值。有必要了解结果类型(表达式的类型)和目标类型(将保存结果的变量的类型)之间的区别。
无符号类型中的环绕行为(更正式地模 n)在 C++ 中定义明确,因此编译器可能不会警告您。
If an unsigned integer overflows, the result is defined modulo 2w, where w is the number of bits in that particular unsigned integer. By implication, an unsigned integer is never negative.
假设您的 n
是典型的 int
或 unsigned int
,这是因为
这一行
unsigned long long sq = n * n;
等同于
unsigned long long sq = (int)(n * n);
因为 n * n 将在将结果分配给 sq 之前首先处理(均为整数)。因此,这是一个 溢出 问题(欢迎来到 堆栈溢出也是!)。
您可能还想通过搜索更多地了解这些术语 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;
那么结果将是相同的,因为不会有 溢出。
您的 n
被声明为 32 位整数。您需要将其更改为 long long 或将操作强制转换为 long long。
unsigned long long sq=(unsigned long long)n*n;
这将给出正确答案