我正在尝试编写一个函数,该函数查找从2到给定上限范围内的所有友好数字。
我编写了一个函数,该函数查找给定数字的除数之和。
我还编写了一个函数,该函数使用以下事实:如果 num1 的除数之和为 S(num1),而 num2 = s(num1)- num1 具有相同的除数,那么num1和num2是友好数字。
这是我的代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
void amicableNumbers(int n);
int findSumOfDevisors(int num);
void main() {
int upperRange;
printf("enter the value for upper range: ");
scanf("%d", &upperRange);
printf("the amicable numbers between 2 and %d:\n", upperRange);
amicableNumbers(upperRange);
}
void amicableNumbers(int n) {
int sum, sum2, i;
for (i = 2; i <= n; i++) {
sum = findSumOfDevisors(i);
if (sum > i && sum <= n) {
sum2 = findSumOfDevisors(sum);
if (sum2 == i)
printf("%d and %d \n", i, sum);
}
}
}
int findSumOfDevisors(int num) {
int sum = 1, i, n;
n = (int)sqrt((double)num);
for (i = 2; i <= n; i++) {
if ((n % i) == 0) {
sum += i;
sum += n / i;
}
}
return sum;
}
但是,当我运行它时,我得到了错误的输出。例如,对于upperRange 301
,我发现2-301
范围内没有任何友好数字。
可和数字是两个不同的数字,因此彼此相关,以使每个数字的适当除数之和等于另一个数字。例如,对220和284是友好的数字。 220的适当除数之和为1 + 2 + 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110 = 284,而284的适当除数之和为1 + 2 + 4 + 71 + 142 = 220。
除数本身以外,数字的适当除数是该数字的正因数。
答案 0 :(得分:3)
OP的findSumOfDevisors()
有麻烦。也许其他代码也可以。
sqrt()
不一定要给出准确的平方根-一些较弱的实现可能会导致值刚好在预期答案之上或之下。加上(int)
会截断分数,答案如123.999999999 ...变成123而不是124。在任何情况下,此处都不需要精度问题的浮点数学。
仅建议使用整数数学:
// n =(int) sqrt((double)num);
// for (i = 2; i <= n; i++)
for (i = 2; i <= num/i; i++)
避免溢出。
// for (i = 2; i*i <= num; i++) `i*i` may overflow.
for (i = 2; i <= num/i; i++)
将相同的值累加两次?当除数和商相同时,代码会将它们都计算在内。我只希望一个。
sum += i;
// sum += n / i;
if (i != n/i) sum += n/i;
出于完整性考虑,我希望findSumOfDevisors(0)
,findSumOfDevisors(1)
返回0,而不是像OP的代码一样返回1。负数是另一个未解决的问题。
// int sum = 1;
int sum = num > 1;
使用昂贵的/, %
还是2换1?考虑以下代码。 %
和/
可能会调用一些昂贵的余数和除法计算。然而,对于许多优秀的编译器而言,num/i
和num % i
会导致发出的代码在一次操作中同时计算两个代码。最好为清晰起见编写代码,但是如果您需要考虑持久性,请研究一个好的优化编译器的结果。
for (i = 2; i < num/i; i++) {
if (num%i == 0) {
答案 1 :(得分:2)
不建议在findSumOfDivisors
中使用浮点运算,请尝试以下方法:
int findSumOfDivisors(int num) {
int sum = 1, div, i;
for (i = 2; i <= (div = num / i); i++) {
if (num % i == 0) {
sum += i;
if (i == div)
break;
sum += div;
}
}
return sum;
}
此外,您的amicableNumbers
函数太复杂了,您应该简单地测试一下该和的除数之和是否为原始数:
void amicableNumbers(int n) {
int sum, i;
for (i = 2; i <= n; i++) {
sum = findSumOfDivisors(i);
if (sum > i && sum <= n && findSumOfDivisors(sum) == i)
printf("%d and %d\n", i, sum);
}
}
}
最后,没有参数的main
的原型是int main(void)
,您应该测试scanf()
的返回值并从0
返回main
。
这是改进版:
#include <stdio.h>
int findSumOfDivisors(int num) {
int sum = 1, div, i;
for (i = 2; i <= (div = num / i); i++) {
if (num % i == 0) {
sum += i;
if (i == div)
break;
sum += div;
}
}
return sum;
}
void amicableNumbers(int n) {
int sum, i;
for (i = 2; i <= n; i++) {
sum = findSumOfDivisors(i);
if (sum > i && sum <= n && findSumOfDivisors(sum) == i)
printf("%d and %d\n", i, sum);
}
}
}
int main(void) {
int upperRange;
printf("enter the value for upper range: ");
if (scanf("%d", &upperRange) == 1) {
printf("the amicable numbers between 2 and %d:\n", upperRange);
amicableNumbers(upperRange);
}
return 0;
}
答案 2 :(得分:1)
您的findSumOfDevisors
函数错误。此外,IMO sqrt()
函数对于性能而言是压倒性的。相反,您应该使用i <= num / 2
int findSumOfDevisors(int num)
{
int sum = 1, i,n;
//n =(int) sqrt((double)num);
for (i = 2; i <= num / 2; i++)
{
if ((num % i) == 0)
{
sum += i;
}
}
return sum;
}
此外,if (sum > i && sum <= n)
可以简化为i < sum
答案 3 :(得分:0)
问题出在此功能
int findSumOfDevisors(int num)
您要输入num而不是n是输入错误 正确的功能是
int findSumOfDevisors(int num)
{
int sum = 1, i,n;
n =(int) sqrt((double)num);
for (i = 2; i <= n; i++)
{
if ((num % i) == 0)
{
sum += i;
sum += num / i;
}
}
return sum;
}