吧务
level 11
situxuming
楼主
Project Euler上第47道题目,链接如下:
http://projecteuler.net/problem=47
最小的两个具有两个不同质数因子的连续整数是:
14 = 2

7
15 = 3

5
最小的三个具有三个不同质数因子的连续整数是:
644 = 2^2

7

23
645 = 3

5

43
646 = 2

17

19.
找出最小的四个具有四个不同质数因子的整数。它们之中的第一个是多少?
******************************************************************************
最容易想到的是用NestWhile,自己写的程序如下:
NestWhile[{Length@FactorInteger[
#[[2]] + 1], #
[[2]] + 1} &, {2, 209}, (
#1[[1]] != 4 || #
2[[1]] != 4 ||
#3[[1]] != 4 || #
4[[1]] != 4) &, 4]
运行时间:1.36 sec
***********************************************************************
然后看到直接有内部函数PrimeNu可以算不同质数因子的个数,就改了下:
NestWhile[{PrimeNu[
#[[2]] + 1], #
[[2]] + 1} &, {2, 209}, (
#1[[1]] != 4 || #
2[[1]] != 4 ||
#3[[1]] != 4 || #
4[[1]] != 4) &, 4]
结果运行时间变为: 3.9 sec,
慢了3倍。
Trace看了一下,慢的原因是
PrimeNu会有一系列的判断过程,不像Length@FactorInteger这般直接。
***************************************************************************
然后在这道题的Forum上看到有人贴出下面NestWhile版本:
NestWhile[# + 1 &, 209, ! (And @@ Thread[4 == Length /@ FactorInteger[# + {0, 1, 2, 3}]]) &]
运行时间是: 3.32 sec
推测这个慢的原因是,相比我自己写的Nest程序,每一次Nest运算,
后面的判断都要进行较多的计算
这原因是从下面的改写得到的:
NestWhile[# + 1 &, 209, ! ({4, 4, 4, 4} === Length /@ FactorInteger[# + {0, 1, 2, 3}]) &]
后面的判断减少了计算,运行时间提高到2.85sec
********************************************************************************
但
这里最快的
却是
While循环:
(a = 210; While[Length@FactorInteger[a] != 4 || Length@FactorInteger[a + 1] != 4 || Length@FactorInteger[a + 2] != 4 || Length@FactorInteger[a + 3] != 4, a++]; a)
运行时间:0.81 sec
*********************************************************************************
For循环最慢:
(For[i = 1, Not[{4, 4, 4, 4} === Length /@ FactorInteger[i + {0, 1, 2, 3}]], i++]; i)
2.76 sec
如果Length/@FactorInteger替换成PrimeNu,时间突增到13s。足见,并不是任何内部函数都比自己编的函数要有效率的。。
。记得之前 @xzcyr 好像也发过一个帖子,是说怎么让NestWhile快过While,现在找不到了~
对于这个具体问题,MMA函数式编程有什么改善的方法,使得其运行效率比单纯While循环快?
2013年06月19日 05点06分
1
http://projecteuler.net/problem=47
最小的两个具有两个不同质数因子的连续整数是:
14 = 2
715 = 3
5最小的三个具有三个不同质数因子的连续整数是:
644 = 2^2
7
23645 = 3
5
43646 = 2
17
19.找出最小的四个具有四个不同质数因子的整数。它们之中的第一个是多少?
******************************************************************************
最容易想到的是用NestWhile,自己写的程序如下:
NestWhile[{Length@FactorInteger[
#[[2]] + 1], #
[[2]] + 1} &, {2, 209}, (
#1[[1]] != 4 || #
2[[1]] != 4 ||
#3[[1]] != 4 || #
4[[1]] != 4) &, 4]
运行时间:1.36 sec
***********************************************************************
然后看到直接有内部函数PrimeNu可以算不同质数因子的个数,就改了下:
NestWhile[{PrimeNu[
#[[2]] + 1], #
[[2]] + 1} &, {2, 209}, (
#1[[1]] != 4 || #
2[[1]] != 4 ||
#3[[1]] != 4 || #
4[[1]] != 4) &, 4]
结果运行时间变为: 3.9 sec,
慢了3倍。
Trace看了一下,慢的原因是
PrimeNu会有一系列的判断过程,不像Length@FactorInteger这般直接。
***************************************************************************
然后在这道题的Forum上看到有人贴出下面NestWhile版本:
NestWhile[# + 1 &, 209, ! (And @@ Thread[4 == Length /@ FactorInteger[# + {0, 1, 2, 3}]]) &]
运行时间是: 3.32 sec
推测这个慢的原因是,相比我自己写的Nest程序,每一次Nest运算,
后面的判断都要进行较多的计算
这原因是从下面的改写得到的:
NestWhile[# + 1 &, 209, ! ({4, 4, 4, 4} === Length /@ FactorInteger[# + {0, 1, 2, 3}]) &]
后面的判断减少了计算,运行时间提高到2.85sec
********************************************************************************
但
这里最快的
却是
While循环:
(a = 210; While[Length@FactorInteger[a] != 4 || Length@FactorInteger[a + 1] != 4 || Length@FactorInteger[a + 2] != 4 || Length@FactorInteger[a + 3] != 4, a++]; a)
运行时间:0.81 sec
*********************************************************************************
For循环最慢:
(For[i = 1, Not[{4, 4, 4, 4} === Length /@ FactorInteger[i + {0, 1, 2, 3}]], i++]; i)
2.76 sec
如果Length/@FactorInteger替换成PrimeNu,时间突增到13s。足见,并不是任何内部函数都比自己编的函数要有效率的。。
。记得之前 @xzcyr 好像也发过一个帖子,是说怎么让NestWhile快过While,现在找不到了~
对于这个具体问题,MMA函数式编程有什么改善的方法,使得其运行效率比单纯While循环快?