C# 我的代码中可能的优化?
为了解决这个问题,我编写了以下程序:C# 我的代码中可能的优化?,c#,math,C#,Math,为了解决这个问题,我编写了以下程序: class p5 { const int maxNumber = 20; static void Main(string[] args) { Job(); // First warm-up call to avoid Jit latency var sw = Stopwatch.StartNew(); var result = Job(); sw.Stop();
class p5
{
const int maxNumber = 20;
static void Main(string[] args)
{
Job(); // First warm-up call to avoid Jit latency
var sw = Stopwatch.StartNew();
var result = Job();
sw.Stop();
Debug.Assert(result == 232792560);
Console.WriteLine(result);
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
private static int Job()
{
var result = Enumerable.Range(1, int.MaxValue - 1)
.Where(
n => Enumerable.Range(maxNumber / 2 + 1, maxNumber / 2).All(c => n % c == 0)
).First();
return result;
}
}
然而,我发现这有点长(17秒,在释放模式下),即使它工作
是否有任何可能的优化
仅供参考,我尝试了AsParallel
方法,但正如预期的那样,工作内容太小,上下文切换比好处更重(超过1分钟):
[编辑]根据martin的建议,此版本除以10所需时间:
private static int Job()
{
var n =2;
bool result;
do
{
result = true;
for (int c = maxNumber / 2; c <= maxNumber; c++)
{
if (n % c > 0)
{
result = false;
break;
}
}
n ++;//= 2;
} while (!result);
return n;
}
private static int Job()
{
var n=2;
布尔结果;
做
{
结果=真;
对于(int c=maxNumber/2;c 0)
{
结果=假;
打破
}
}
n++;//=2;
}而(!结果);
返回n;
}
[编辑]总结我的所有测试,大致执行时间:
- 我的第一个实现:20秒
- 删除了内部可枚举范围调用(替换为简单的for循环):3秒
- 已删除外部和内部可枚举。范围调用:1.5秒
- 仅取偶数:(仅限循环,无可枚举范围):小于1秒
- 使用drhirsch建议的Gcd/LCm欧几里德算法:0.004 ms
int maxNumber = 21;
int n = 1;
bool found = false;
while(!found)
{
found = true;
for(int i = 1; i < maxNumber; i++)
{
if(n % i != 0)
{
found = false;
break;
}
}
n++;
}
return n-1;
时间降到了2秒以下
一个数学上的洞察是,我们只需要测试那些不是我们已经测试过的数字的倍数的数字的可分性。在我们的情况下,我们可以写:
private int[] p = { 19, 17, 16, 13, 11, 9, 7, 5, 4, 3, 2 };
int Job()
{
int n = 1;
bool found = false;
while (!found)
{
found = true;
foreach (int i in p)
{
if (n % i != 0)
{
found = false;
break;
}
}
n++;
}
return n - 1;
}
然而,这实际上要慢一些,大约2.5秒。好的,有一件事是你只需要测试偶数,所以从0开始,增加2。 这是因为事实上,偶数永远不会平均地分成奇数。 你也可以从10的阶乘开始搜索,所以 10*9*8*7..以此类推,其他单词从10开始!也就是362800。
这可能有助于加快运行速度。另外,我在C语言中的平均速度是10秒,所以你的代码实际上很好。一个好的优化应该是使用更好的算法 这是求数字1..20的最小公倍数,可以通过求lcm(1,2),然后求lcm(lcm(1,2),3)等直到20来连续计算 求lcm的一个简单算法是将两个数的乘积除以最大公约数。众所周知,gcd可以在很短的时间内找到
#include <iostream>
long gcd(long a, long b) {
if (!b) return a;
return gcd(b, a-b*(a/b));
}
long lcm(long a, long b) {
return (a*b)/gcd(a, b);
}
int main(int argc, char** argv) {
long x = 1;
for (long i=2; i<20; ++i)
x = lcm(x, i);
std::cout << x << std::endl;
}
#包括
长gcd(长a、长b){
如果(!b)返回a;
返回gcd(b,a-b*(a/b));
}
长lcm(长a、长b){
报税表(a*b)/gcd(a、b);
}
int main(int argc,字符**argv){
长x=1;
for(long i=2;iYou是对的。通过用for循环替换我的内部可枚举的.Range
,我将所需时间除以5,这看起来是Jon Skeet的12倍,但我不知道我会称之为“极端”在这种情况下,它可能会有所不同,但通常我会使用最容易阅读的内容。除以10,使用可枚举的。范围。难以置信的答案。基准测试本身就说明了问题(放在我的原始问题中)
private int[] p = { 19, 17, 16, 13, 11, 9, 7, 5, 4, 3, 2 };
int Job()
{
int n = 1;
bool found = false;
while (!found)
{
found = true;
foreach (int i in p)
{
if (n % i != 0)
{
found = false;
break;
}
}
n++;
}
return n - 1;
}
#include <iostream>
long gcd(long a, long b) {
if (!b) return a;
return gcd(b, a-b*(a/b));
}
long lcm(long a, long b) {
return (a*b)/gcd(a, b);
}
int main(int argc, char** argv) {
long x = 1;
for (long i=2; i<20; ++i)
x = lcm(x, i);
std::cout << x << std::endl;
}