不同质数因子NestWhile的改善
mathematica吧
全部回复
仅看楼主
吧务
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
吧务
level 9
“For循环最慢”其实不太恰当的,要比较的话,要保持一致性,不仅仅是算法,还有写法,这样写的话,For和While的速度几乎一样
(For[i = 1, Length@FactorInteger[i] != 4 || Length@FactorInteger[i + 1] != 4 || Length@FactorInteger[i + 2] != 4 || Length@FactorInteger[i + 3] != 4, i++]; i) // AbsoluteTiming
2013年06月19日 05点06分 2
吧务
level 9
下面几个用NestWhile的速度快了一点(其实是等价的),但比While还是慢了些,
NestWhile[(# + 1) &, 0,
Length@FactorInteger[#] != 4 || Length@FactorInteger[# + 1] != 4 ||
Length@FactorInteger[# + 2] != 4 ||
Length@FactorInteger[# + 3] != 4 &] // AbsoluteTiming
NestWhile[(# + 1) &, 0,
Evaluate[Or @@ Table[fun[# + i] != 4, {i, 0, 3}]] & /.
fun :> Composition[Length, FactorInteger]] // AbsoluteTiming
NestWhile[(# + 1) &, 0,
Evaluate[ Or @@ Table[ With[{j = i}, Hold@Length@FactorInteger[# + j] != 4], {i, 0, 3}]] & // ReleaseHold] // AbsoluteTiming
2013年06月19日 06点06分 3
上面的代码还等价于,NestWhile[(# + 1) &, 0, Or @@ Table[ Length@FactorInteger[# + i] != 4, {i, 0, 3}] &] // AbsoluteTiming
2013年06月19日 06点06分
NestWhile[(# + 1) &, 0, Evaluate[! And @@ Table[fun[# + i] == 4, {i, 0, 3}]] & /. fun :> Composition[Length, FactorInteger]] // AbsoluteTiming
2013年06月19日 06点06分
吧务
level 15
咦,我发过讨论NestWhile和While的帖吗……我自己都不记得了……搜一搜也只有这帖九楼搭点边的,是草红样讨论的……:
https://tieba.baidu.com/p/2052726090
2013年06月19日 07点06分 5
印象中有这么一个帖子,不是你的话就是mm_酱
2013年06月19日 08点06分
1