所以我被要求对数字的每个数字进行平方并将它们连接起来并使用 C 作为数字返回。但由于某种原因,我在处理 0 作为数字并在我的算法中实现它时遇到问题。例如:当 n = 3210987654 时,预期为 9410816449362516,但得到 941816449362516。
#include<math.h>
unsigned long long square_digits(unsigned n) {
unsigned long long result = 0;
int k = 0;
int digits = (int)log10(n) + 1;
for (int d = 0; d < digits; d++) {
int digit = n % 10;
int squared = digit * digit;
n /= 10;
if (d == 0) {
result += squared * pow(10, k);
}
else {
if (digit == 0) {
k++;
}
else if (digit < 4) {
k++;
result += squared * pow(10, k);
}
else {
k += 2;
result += squared * pow(10, k);
}
}
}
return result;
}
所以我尝试使用变量 k ,它将作为 10 的幂,并根据连接平方数字所需的位数起作用。对于第一个数字,我保持简单,因为我没有更改 k 的值。对于其他人,我首先检查数字平方是否为 2 位数字。如果需要的话,那么每次我都必须增加功率两次,对于个位数平方一次。至于数字 0,我不能相应地相乘或连接,而是通过增加幂向左移动一步。根据我的假设,这应该可以完美地工作,但是这不能正常工作,因为它在处理数字中间的 0 时遇到问题。
例如:对于 n = 3210987654,预期为 9410816449362516,但得到 941816449362516
使用
pow
和log10
使事情变得太复杂(甚至可能由于浮点计算而导致不正确)。进行整数计算时,全部使用整数。
保留一个
factor
变量,以便您知道在添加到结果之前将平方数与什么相乘。从 factor
为 1
开始,然后将每个平方数字乘以 10
或 100
,具体取决于平方数字的值。
类似:
unsigned long long square_digits(unsigned n)
{
unsigned long long result = 0;
unsigned long long factor = 1;
while (n)
{
unsigned digit = n % 10;
unsigned squared = digit * digit;
result += factor * squared;
factor = (squared >= 10) ? factor * 100 : factor * 10;
n /= 10;
}
return result;
}
要解决像这样的大数字的操作,通常最好通过将数字评估为字符串来完成,就像通常对信用卡号等大数字所做的那样。将数字转换为字符串后,可以根据问题场景的需要单独处理每个数字。这样,以下是数字平方函数的重构版本以及“主”函数中的测试工具。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned long long square_digits(long long n)
{
char work[32];
long long x = 1;
long long result = 0;
sprintf(work, "%lld", n); /* Store value in a string */
for (int i = (strlen(work) - 1); i >= 0; i--) /* Evaluate each digit character */
{
result += (work[i] - '0') * (work[i] - '0') * x; /* Square the digit value and multiply by a succesive power of 10 */
x *= 10;
if (work[i] > '3') /* Increase multiplier by 10 again for a two digit square */
x *= 10;
}
return result;
}
int main()
{
long long i;
printf("Enter a value: ");
scanf("%lld", &i);
printf("Result for %lld is %lld\n", i, square_digits(i));
return 0;
}
以下是重点。
使用示例测试此重构代码,创建了以下终端输出。
craig@Vera:~/C_Programs/Console/SquareInt/bin/Release$ ./SquareInt
Enter a value: 3210987654
Result for 3210987654 is 9410816449362516
继续评估这条可能的路线。
你的代码非常复杂且不清楚。通常这样的代码包含错误。
例如,考虑
n
等于 104
。
对于循环的第一次迭代
k
等于 0
:
int k = 0;
所以第一次迭代后
result
将是16
。
下一个数字是
0
。在这种情况下,k
会递增:
if (digit == 0) {
k++;
}
并且变得等于
1
。
那么最后一位数字等于
1
你有
else if (digit < 4) {
k++;
result += squared * pow(10, k);
}
也就是说,
k
等于 2
,因此 result
等于 116
。然而 result
应等于 1016
。
在我看来,我可以建议一个更清晰和简单的解决方案,而不使用处理双值的辅助标准函数
pow
和log10
..
你在这里。
#include <stdio.h>
unsigned int max_divisor( unsigned int n )
{
const unsigned int Base = 10;
unsigned int divisor = 1;
while (!( n / divisor < Base ))
{
divisor *= Base;
}
return divisor;
}
unsigned long long square_digits( unsigned n )
{
const unsigned int Base = 10;
unsigned long long result = 0;
unsigned int divisor = max_divisor( n );
do
{
unsigned long long digit = n / divisor;
digit *= digit;
result = ( digit < 10 ? Base : Base * Base ) * result + digit;
n %= divisor;
} while (divisor /= Base);
return result;
}
int main( void )
{
for (unsigned int n = 0; n <= 10; ++n)
{
printf( "%u -> %llu\n", n, square_digits( n ) );
}
unsigned int n = 3210987654;
printf( "%u -> %llu\n", n, square_digits( n ) );
}
程序输出为
0 -> 0
1 -> 1
2 -> 4
3 -> 9
4 -> 16
5 -> 25
6 -> 36
7 -> 49
8 -> 64
9 -> 81
10 -> 10
3210987654 -> 9410816449362516