1. 问题描述
什么是自守数
如果一个数字的平方的尾数刚好等于该数本身,那么这个数就是自守数。
例如:
5 * 5 = 25, 25 * 25 = 625, 76 * 76 = 5776
本文要求出0~1000以内的自守数。
2. 问题分析
首先分析平方后结果的构成,以376为例:
376 * 376 = 141376
① 376 * 6 = 2256
② 376 * 70 = 26320
③ 376 * 300 = 112800
141376 = ① + ② + ③
虽然数字很大,但是对自守数的判读有用的其实只有①②③中数字的最后三位之和的最后三位:256 + 320 + 800 = 1376。
因此判定一个数num是否为自守数的步骤如下:
1)计算数字num是几位数字,把位数存储在n里;
2)被乘数num依次乘上num的各个位上的数字,求出前文中的①②③。
3)提取①②③的最后n位数值,并依次相加,得到res;
4)提取res的最后n位数值,与num相比,如果二者相等,那么num就是自守数。
3. 代码
#include <stdio.h>
int zishou(int num); //判断自守数的子程序,返回长度为n的数的平方值的最后n位
int len(int num); //计算任意一个int类型数的长度
void main()
{
int i, count=0; //count表示这是0-1000的第几个自守数
for(i=0;i<=1000;i++)
{
if(zishou(i)==i) //是自守数
{
printf("第%d个自守数: i=%d i*i=%d\n", ++count, i, i*i);
}
}
}
//计算任意一个int类型数的长度
int len(int num)
{
int len;
for(len=0;num!=0;len++)
{
num/=10;
}
return len;
}
//判断自守数的子程序,返回长度为n的数的平方值的最后n位
int zishou(int num)
{
int res=0;
int cpy;
int i, exp=1;
int k=1;
cpy = num; //cpy是被乘数,num原始值之后会因为位数提取而被改变,所以要备份
for(i=0;i<len(cpy);i++)
{
exp *= 10;
}
//依次提取① ② ③(详见问题分析部分)中的最后n位的数值(判断对象有n位,例如对于判断对象376, n=3),求出他们的值,存储在res里
while(num!=0)
{
res += (cpy*(num%10)*k)%exp;
num /= 10;
k *= 10;
}
//提取res的最后n位
return res%exp;
}
结果展示: