【〇疼】【讨论?】Mathematica,VBA,C++蒙特卡洛法算圆周率对
mathematica吧
全部回复
仅看楼主
吧务
level 15
xzcyr 楼主
(类似的讨论以往有过多次,不过当前老帖几乎全被百度隐藏,发出来权当补充吧。)
因为新电脑里预装了正版的Office,就稍微折腾了下VBA,四处翻找相关文章的时候,知乎的某主题引起了我的兴趣:
《为什么 C++ 只比 VBA 快 4倍?》(链接就不贴了,否则八成又要被吞。直接搜索这个标题就可以找到。)
那么Mathematica(在不改变算法实质的情况下)的速度怎么样?——基本可以肯定比C++慢(即便编译,Mathematica在大规模低级运算上也往往不及精心编写过的C/C++/Fortran),但和VBA比呢?(当年学VB时我曾不止一次听到过“VB速度慢”的说法,但我从没正经研究过。)
总之先试试C++和VBA的速度。C++快得意料之中,51毫秒(编译器是TDM-GCC 5.1.0-2 64位,编译选项-Ofast):
VBA约279毫秒,和文中所述速度基本一致:
然后是Mathematica(测试版本9.0.1):
(自认为)写的比较好的非编译版本:
(*
可以借助
Simplify`PWToUnitStep@PiecewiseExpand@If[x < 1, 1, 0]
计算出所需的UnitStep组合
*)
With[{a = RandomReal[1, {25 10^5}], b = RandomReal[1, {25 10^5}]},
1/(2.5 10^6) ((Total[1. - UnitStep[-1 + (a^2 + b^2)]] +
Total[1. - UnitStep[-1 + ((1 - a)^2 + (1 - b)^2)]])) 2] // AbsoluteTiming
(* {0.295614, 3.14008} *)
和VBA纯循环版本的速度差不多。
然后是编译版:
Compile[{},
With[{a = RandomReal[1, {25 10^5}], b = RandomReal[1, {25 10^5}]},
1/(2.5 10^6) ((Total[1. - UnitStep[-1 + (a^2 + b^2)]] +
Total[1. - UnitStep[-1 + ((1 - a)^2 + (1 - b)^2)]])) 2]][] // AbsoluteTiming
(* {0.126434, 3.14154} *)
比VBA快了,不过还是只有C++的一半。
让我有些惊讶的是,高维列表会导致代码略微变慢:
Compile[{},
With[{n = 25 10^5},
With[{lst = RandomReal[1, {2, n}]},
1./n ((Total[1. - UnitStep[-1. + Total[lst^2]]] +
Total[1. - UnitStep[-1. + Total[(1. - lst)^2]]])) 2]]][] // AbsoluteTiming
(* {0.152793, 3.14172} *)
编译为C的话又能榨出一点速度来,当然了,调用C编译器挺慢的……:
cf = Compile[{},
Module[{c = 0., n = 25 10^5},
Do[With[{a = RandomReal[], b = RandomReal[]}, If[a^2 + b^2 < 1., c += 1.];
If[(1. - a)^2 + (1. - b)^2 < 1., c += 1.];], {n}]; c 2/(n)],
CompilationTarget -> C, RuntimeOptions -> "Speed"];//AbsoluteTiming
(* {0.296880, Null} *)
cf[] // AbsoluteTiming
(* {0.110118, 3.14154} *)
上面的代码还有优化余地吗?
2019年10月05日 15点10分 1
吧务
level 9
不编译的版本,使用Clip或Unitize比UnitSteps略快
With[{a=RandomReal[1,{25 10^5}],b=RandomReal[1,{25 10^5}],f=Clip[#,{1,0},{1,0}]&},
1/(2.5 10^6) (Total[f[a^2+b^2]]+Total[f[((1-a)^2+(1-b)^2)]]) 2]//AbsoluteTiming
(* f = Unitize[1, #] & *)
2019年10月06日 07点10分 2
对于这个问题If[x < 1, 1, 0]和If[x <=1, 1, 0]没啥区别,用UnitStep[1 - x]稍微简单一点
2019年10月06日 07点10分
吧务
level 9
生成随机数的方法可以加快一点
SeedRandom[Method -> {"MKL", Method -> {"Niederreiter", "Dimension" -> 3}}]
2019年10月06日 07点10分 3
吧务
level 9
用在Compile里Random比RandomReal略快,只是生成的随机数可能质量不高,不太建议使用
2019年12月13日 14点12分 4
level 1
之前回复“数值计算还是 MATLAB 比较快”被删了,理由是没给代码,那就给一下好了[阴险]
上边每种方法都试过了(包括下边回复提到的改进方法),且都跑三次,取最快的一次, 所有方法中最快的是:
SeedRandom[Method -> {"MKL", Method -> {"Niederreiter", "Dimension" -> 3}}]
Compile[{},
With[{a = RandomReal[1, {25 10^5}], b = RandomReal[1, {25 10^5}]},
1/(2.5 10^6) ((Total[1. - UnitStep[-1 + (a^2 + b^2)]] +
Total[1. -
UnitStep[-1 + ((1 - a)^2 + (1 -
b)^2)]])) 2]][] // AbsoluteTiming
(* {0.0415543, 3.14067} *)
(编译到 C 的方法在我这里反而更慢何况编译也挺慢就不贴了,编译器为 vs 2019)
环境是 win10 1909 x64, Mathematica 12.0.0, Intel 9900k @ 4.7GHz
相同环境的 MATLAB R2020a prerelease:
% foo.m
function foo
timeit(@璐村惂鐢ㄦ埛_05NCUJN馃惥 computePi)
function p = computePi
a = rand(25e5, 1);
b = rand(25e5, 1);
p = (sum(a .^ 2 + b .^ 2 < 1) + sum((1 - a) .^ 2 + (1 - b) .^ 2 < 1)) / 25e5 * 2;
>> rng(0, 'threefry')
>> foo
ans =
0.0108385555
用时大约是 Mathematica 的四分之一
考虑到这里随机数生成器不同,单独对比下随机数生成性能:
SeedRandom[
Method -> {"MKL", Method -> {"Niederreiter", "Dimension" -> 3}}]
a = RandomReal[1, {25 10^5}]; // AbsoluteTiming
(*{0.004575, Null}*)
>> rng(0, 'threefry'); timeit(@() rand(25e5, 1))
ans =
0.0038504555
可以看到两者随机数生成性能是差不多的,所以应该主要差别在计算上:
0.0415543-0.004575*2 = 0.0324043
0.0108385555 - 0.0038504555*2 = 0.0031376445
这样估算,排除随机数生成器的影响后,计算性能可能相差 10 倍以上。
当然也可以写个对于提前计算得到的 a,b 进行计算的实现进行比较:
function foo
a = rand(25e5, 1);
b = rand(25e5, 1);
timeit(@() computePi(a, b))
function p = computePi(a, b)
p = (sum(a .^ 2 + b .^ 2 < 1) + sum((1 - a) .^ 2 + (1 - b) .^ 2 < 1)) / numel(a) * 2;
>> foo
ans =
0.00272264175
比上边计算出来的 0.0031376445 还快一些
2020年02月11日 04点02分 6
matlab的数值计算不见得总比Mathematica快,试试这个帖子里tieba.baidu.com/p/6530781068 N皇后和四阶幻方的例子
2020年05月07日 10点05分
@孺子剑牛不群 里边mma的代码又是编译又是剪枝,编译的话matlab也能编译,之后还是比mma快(之前试过)。剪枝的话算法都变了没对比价值,要对比应该都做同样的剪枝。n皇后matlab代码我没看到。
2020年05月07日 17点05分
@flaycatc matlab代码同样可以剪枝嘛,既然要比肯定是比同样的算法,我这里测试编译后的代码matlab并没有更快(不信楼下可以贴运行结果截图)。还有,你好像用的是VC,编译时间比GCC慢,速度也经常不如GCC。
2020年05月08日 03点05分
@孺子剑牛不群 我测试的是没有剪枝的算法编译,MATLAB要比同样没有剪枝的mma编译的结果要快。
2020年05月08日 06点05分
level 8
计算卷积
欧拉计划249,matlab代码很难在10秒内完成,zhuanlan.zhihu.com/p/53416615
2020年05月08日 04点05分 9
就先测试了第一个1维卷积,mma算出的结果前几位是这样的: {0.96875, 4., 9.9375, 20.0313, 35.0313....,MATLAB算出来的是前几位是1 4 10 20 35 56 84 120 ...,虽说数值计算有误差是正常的,但是mma显然这里也差太多了吧,这种精度下的性能优势[汗]
2020年05月08日 06点05分
测试了一下把改成 Range[1, 10^5] 之后 mma 的结果就正确了,速度虽然慢了但确实比 MATLAB 要快。后边的欧拉问题你发的链接里边也没有涉及到编译,我等下编译下试试。
2020年05月08日 06点05分
>> tic, c = foo_mex(pSet, pSet2); toc Elapsed time is 0.250256 seconds. cf[pSet, pSet2] // AbsoluteTiming {1.96523, 9275262564250418} 就算你说vs比较慢,按照你的时间0.78算好了,我的电脑应该没有比你快三倍
2020年05月08日 07点05分
关于二重卷积的部分,MATLAB可以这么算: tic, c = ifft2(fft2(rand(600), 1399, 1399) .* fft2(rand(800), 1399, 1399)); toc Elapsed time is 0.065890 seconds. 和我电脑上MMA用时差不多:{0.0633728, {1399, 1399}} 我怀疑mma算1维卷积的时候估计也用 fft 类似技术加速了,matlab应该直接算所以慢
2020年05月08日 07点05分
1