6.1有趣的整数
6.1.1完数
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。如果一个数恰好等于它的因子之和,则称该数为“完全数”。第一个完全数是6,第二个完全数是28,第三个完全数是496,后面的完全数还有8128、33550336等等。
简言之,如果一个数恰好等于其因子之和,这个数就称为完数。
求出10000以内的完数的C语言代码
#include
int main()
{
long p[300]; //保存分解的因子
long i, num, count, s, c = 0;
for (num = 2; num < 10000; num++)
{
count = 0;
s = num;
for (i = 1; i < num / 2 + 1; i++) //循环处理每一个数
{
if (num % i == 0) //能被i整除
{
p[count++] = i; //保存因子,计数器count增加1
s -= i; //减去一个因子
}
}
if (s == 0) //已被分解完成,则输出
{
printf("%4ld是一个完数,因子是",num);
printf("%ld=%ld",num,p[0]); //输出完数
for (i = 1; i < count; i++) //输出因子
printf("+%ld",p[i]);
printf("\n");
c++;
}
}
printf("\n共找到%d个完数.\n",c);
getchar();
return 0;
}
6.1.2亲密数
如果a的所有正因子和等于b,b的所有正因子和等于a,因子包括1但不包括本身,且a不等于b,则称a,b为亲密数对。一般通过叠代编程求出相应的亲密数对。
求出10000以内的亲密数
#include
int main()
{
int i, a, b1, b2, m, g1[100], g2[100], count;
printf("输入最大范围:");
scanf("%d",&m);
for (a = 1; a < m; a++) //循环次数
{
for (i = 0; i < 100; i++) //清空数组
g1[i] = g2[i] = 0;
count = 0; //数组下标
b1 = 0; //累加和
for (i = 1; i < a / 2 + 1; i++) //求数a的因子
{
if (a%i == 0) //a能被i整除
{
g1[count++] = i; //保存因子到数组,方便输出
b1 += i; //累加因子之和
}
}
count = 0;
b2 = 0;
for (i = 1; i < b1 / 2 + 1; i++) //将数a因子之和再进行因子分解
{
if (b1%i == 0) //b1能被i整除
{
g2[count++] = i; //保存因子到数组g2
b2 += i;//累加因子之和
}
}
if (b2 == a&&a < b1) //判断A,B的输出条件,a0) //大于0表示有因子,输出一个数的因子
{
printf("+%d",g1[count]);
count++;
}
printf("\n%d=1",b1);
count = 1;
while (g2[count]>0) //输出另一个数的因子
{
printf("+%d",g2[count]);
count++;
}
}
}
printf("\n");
getchar();
return 0;
}
6.1.3水仙花数
水仙花数(Narcissistic number)也被称为超完全数字不变数(pluperfect digital invariant, PPDI)、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数(Armstrong number),水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身(例如:1^3 + 5^3+ 3^3 = 153)。
求水仙花数
#include
int main()
{
int i, j, k, c;
printf("100-999之间的水仙花数:");
for (c = 100; c < 999; c++)
{
i = c / 100; //分解百位数
j = (c - i * 100) / 10; //分解十位数
k = c % 10;//分解分位数
if (i*i*i + j*j*j + k*k*k == c)
{
printf("%d ",c);
}
}
getchar();
return 0;
}
6.1.4自守数
该博客内容较好理解:https://blog.csdn.net/hanshileiai/article/details/8877890
自守数是指某个数的平方的末尾几位数等于这个数的数。代码如下:
#include
int main()
{
long faciend, num, mod, n_mod, p_mod;//mod被乘数的系数,n_mod乘数的系数,p_mod部分乘积的系数
long i, t, n;//临时变量
scanf("%ld",&num);
printf("1-%ld之间有以下自守数:\n",num);
for (i = 1; i < num; i++)
{
faciend = i;//被乘数
mod = 1;
do {
mod *= 10;//被乘数的系数
faciend /= 10;
} while (faciend>0); //循环求出被乘数的系数
p_mod = mod;//p_mod为截取部分积时的系数
faciend = 0;//积的最后N位
n_mod = 10;//11为截取乘数相应位时的系数
while (mod>0)
{
t = i % (mod * 10);//获取被乘数
n = i%n_mod - i % (n_mod / 10);//分解出每一位乘数作为乘数
t = t*n;//相乘的结果
faciend = (faciend + t) % p_mod;//截取乘积的后面几位
mod /= 10;//调整被乘数的系数
n_mod *= 10; //调整乘数的系数
}
if (i == faciend) //若为自守数,则输出
printf("%ld ",i);
}
getchar();
return 0;
}
6.1.5最大公约数和最小公倍数
详见:https://blog.csdn.net/Holmofy/article/details/76401074(转载)
欧几里得算法(辗转相除法)
缺陷:欧几里德算法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来:一般实际应用中的整数很少会超过64位(当然现在已经允许128位了),对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算128位以上的素数的情况比比皆是,比如说RSA加密算法至少要求500bit密钥长度,设计这样的程序迫切希望能够抛弃除法和取模。
#include
int main()
{
//函数声明
int gcd(int, int);
int lcm(int, int);
int a, b;
printf("输入两个整数(用空格分隔):");
scanf("%d%d",&a,&b);
printf("最大公约数:%d\n",gcd(a,b));
printf("最小公倍数:%d\n",lcm(a,b));
getchar();
return 0;
}
int gcd(int a, int b)
{
int m, n, r;
m = a >= b ? a : b;//m保存较大数
n = a < b ? a : b;//n保存较小数
r = m%n; //求余数
while (r != 0) //辗转相除
{
m = n;
n = r;
r = m%n;
}
return n; //返回最大公约数
}
int lcm(int a, int b) //最小公倍数
{
int t = gcd(a, b); //获取最大公约数
return (a*b) / t;//返回最小公倍数
}
改进:stein算法
#include
int gcd(int a, int b) //最大公约数
{
int m, n, r;
m = a >= b ? a : b; //m保存最大数
n = a < b ? a : b;//n保存较小数
if (n == 0) //弱较小数为0
return m; //返回另一个数为最大公约数
if (m % 2 == 0 && n % 2 == 0) //m,n都是偶数
return 2 * gcd(m / 2, n / 2); //递归调用gcd函数,将m,n都除以2
if (m % 2 == 0)//m为偶数
return gcd(m / 2, n); //递归调用gcd函数,将m除以2
if (n % 2 == 0)//n为偶数
return gcd(m, n / 2);//递归调用gcd函数,将n除以2
return gcd((m+n)/2,(m-n)/2); //m,n都是奇数,递归调用gcd
}
int lcm(int a, int b)//最小公倍数
{
int t = gcd(a, b);//获取最大公约数
return (a*b) / t;
}
int main()
{
int a, b;
printf("输入两个整数(用空格分隔):");
scanf("%d%d", &a, &b);
printf("最大公约数:%d\n", gcd(a, b));
printf("最小公倍数:%d\n", lcm(a, b));
getchar();
return 0;
}
6.3阶乘
6.3.1用递归方法求阶乘
#include
unsigned long factorial(unsigned long n)
{
if (n < 0)
return 1;
if (n == 1)
return 1;
else
return (unsigned long)n*factorial(n - 1);
}
int main()
{
unsigned long n;
printf("输入一个整数n(n>0):");
scanf("%d",&n);
printf("%lu!=%lu\n",n,factorial(n));
getchar();
return 0;
}
6.3.2大数阶乘