最近我一直在寻找数字的除数,因此决定尝试制作一个程序,该程序以各种方式打印将数字N表示为两个整数的乘积。我写了一篇关于正数的文章,只考虑了正数来构成乘积。
#include <iostream>
#include <cmath>
int main()
{
int n;
std::cin >> n;
int root = std::sqrt(n);
for(int i = 1; i <= root; i++)
{
if(n % i != 0)
continue;
int j = n / i;
std::cout << i << ", " << j << std::endl;
}
return 0;
}
上面的代码只是找到N的所有因数并将它们成对打印。效果很好,但我想尝试使其找到所有可能的方法,不仅获得正数,而且还可以达到N。
例如,如果我在上面的程序中输入10,结果将是(1,10),(2,5);这些是正确的,但是还有其他方法可以将两个数字相乘并得到10。它涉及负数:(-1,-10),(-2,-5)也是解决方案,因为当您将两个负数相乘时,最后得到一个积极的结果。
如果我希望程序只对正N值起作用,而且还能找到负数倍数,那么我可以只打印i和j的负数,因为您只能通过将两个正数或两个负数相乘来获得正数在一起。
那行得通,但是现在我想让此代码在负N值上运行。例如,N = -10的预期输出为:(-1,10),(1,-10),(2,-5),(-2,5);
问题是,上述算法只能找到正数的正因数,因为它涉及平方根(仅针对正数定义),并且循环从正数开始并以正数结束。
我注意到我可以只计算N的绝对值的平方根,然后使循环从-root开始,然后从root结束,从而遍历N的负除数。但是,我必须确保跳过0,因为未定义0除法,这使其崩溃。我最终得到的代码如下:
#include <iostream>
#include <cmath>
int main()
{
int n;
std::cin >> n;
int root_n = std::sqrt(std::abs(n));
for(int i = -root_n; i <= root_n; i++)
{
if(i == 0 || n % i != 0)
continue;
int j = n / i;
std::cout << i << ", " << j << std::endl;
}
return 0;
}
它对我提出的所有测试均正常工作,但我不确定这是否是编写它的最佳方法。有什么我可以改善的吗?
谢谢!
编辑:根据Caleth的建议使用std :: div进行了尝试(还使用了VS中的ReSharper插件为我提供了重构建议):
#include <iostream>
#include <cstdlib>
int main()
{
int n;
std::cin >> n;
const int sqrt_n = std::sqrt(std::abs(n));
for(auto i = -sqrt_n; i <= sqrt_n; i++)
{
if (i == 0)
continue;
const auto div_res = std::div(n, i);
if (div_res.rem)
continue;
std::cout << i << ", " << div_res.quot << std::endl;
}
return 0;
}
我可以只计算一次std :: div而不是计算余数,再计算商,它返回一个包含两个值的结构。
答案 0 :(得分:0)
一个主要的观察结果是,除符号外,数字的负除数和正除数相同。如果只看正数并自己处理符号,则可以节省一半的时间。例如,
int main()
{
int n;
std::cin >> n;
int root_n = std::sqrt(std::abs(n));
for(int i = 1; i <= root_n; i++) \\ don't loop over negative numbers now
{
if(n % i != 0) \\ not necessary to check for 0 anymore
continue;
int j = n / i;
std::cout << i << ", " << j << "\n";
std::cout << -i << ", " << -j << "\n"; \\ corresponding negative
}
return 0;
}
您可能会注意到我删除了std::endl
---您实际上并不需要经常刷新流。让输出缓冲随心所欲更快。
如果您正在寻找其他方法来修改程序,则可以尝试查找素因数分解,然后从中计算除数列表。对于大型,高度复合的输入,这将更快。但这也完全不同。