公告:本站正式转型为非交互式静态网站!
转型:本站将通过笔记和博客的形式继续为大家服务,关于 Mathematica 问答服务请移步至QQ群:365716997
联系:如有问题请联系QQ群管理员,或发送邮件至:lixuan.xyz@qq.com。
感谢:最后非常感谢大家多年来的支持与帮助!
参考《互联网跟帖评论服务管理规定》《中华人民共和国网络安全法》《网络信息内容生态治理规定》《互联网用户账号信息管理规定》

—— 2022-11-27

欢迎来到 Mathematica 问答社区

提问时请贴上文本代码

语法高亮:在编辑器中点击

被禁止的话题:广告破解

请阅读:《提问的智慧》

备用域名:mma.ooo

支持LaTex数学公式
行内公式标识符:\$ 或“$\backslash ($”+“$\backslash )$”,
行间公式标识符:\$\$ 或 “$\backslash [$”+“$\backslash ]$”

社区建议QQ群:365716997

分类

+1 投票
2.5k 浏览

有一个分段函数,每段编译之后速度将近是原函数的十倍,然后打包成一个完整的分段函数(也编译的),速度只有原函数的一半了,折腾了半天只有这么点效果,好难过啊。

下面用一个类似的例子说明,每段编译后速度是原函数的5倍左右,打包后比原函数还慢了。

f1[x_] := Sin[x] + x^2 - 1/(1 + x);
f2[x_] := Sin[x] - x^2 - 1/(1 + x);
f3[x_] := Sin[x] - x^2 + 1/(1 + x);
cf1 = Compile[{{x, _Real}}, Sin[x] + x^2 - 1/(1 + x)];
cf2 = Compile[{{x, _Real}}, Sin[x] - x^2 - 1/(1 + x)];
cf3 = Compile[{{x, _Real}}, Sin[x] - x^2 + 1/(1 + x)];
Do[f1[0.01], {10^6}]; // AbsoluteTiming
Do[cf1[0.01], {10^6}]; // AbsoluteTiming
Do[f2[0.01], {10^6}]; // AbsoluteTiming
Do[cf2[0.01], {10^6}]; // AbsoluteTiming
Do[f3[0.01], {10^6}]; // AbsoluteTiming
Do[cf3[0.01], {10^6}]; // AbsoluteTiming
{2.554146, Null}
{0.448026, Null}
{2.836162, Null}
{0.462026, Null}
{2.487142, Null}
{0.440025, Null}

合并之后,

f[x_] := Which[x > 0, Sin[x] + x^2 - 1/(1 + x),
              -1 < x <= 0, Sin[x] - x^2 - 1/(1 + x),
              x <= -1, Sin[x] - x^2 + 1/(1 + x) ];
cf = Compile[{{x, _Real}}, Which[x > 0, Sin[x] + x^2 - 1/(1 + x),
                                -1 < x <= 0, Sin[x] - x^2 - 1/(1 + x),
                                x <= -1,  Sin[x] - x^2 + 1/(1 + x) ]];
Do[f[0.01], {10^6}]; // AbsoluteTiming
Do[cf[0.01], {10^6}]; // AbsoluteTiming
{4.692268, Null}
{7.180411, Null}

难道是因为which吗,which也在可编译函数这中啊,这可怎么办啊。

分类:其它 | 用户: 随堂测验 (606 分)

1个回答

+1 投票
 
已采纳

改用Piecewise会好很多。

cf = Compile[{{x, _Real}},
   Piecewise[{
     {Sin[x] + x^2 - 1/(1 + x), x > 0},
     {Sin[x] - x^2 - 1/(1 + x), -1 < x <= 0},
     {Sin[x] - x^2 + 1/(1 + x), x <= -1}
     }], CompilationTarget -> "C", RuntimeOptions -> "Speed"
   ];
Do[cf[0.01], {10^6}]; // AbsoluteTiming

 

用户: 野鹤 (5.1k 分)
采纳于 用户:随堂测验
赞,谢谢,站长威武
另外,苹果指出这个问题确实出在Which上,虽然Which是可以编译的。但是有个坑。Which默认有个Null的返回选择(当所有条件为假),Null的类型(Symbol)是和实数(Real)不同,所以无法编译成功。可以强制加上判断True,并且返回实数(这里填的是1.,随意修改)。
cf2 = Compile[{{x, _Real}},
   Which[x > 0, Sin[x] + x^2 - 1/(1 + x), -1 < x <= 0,
    Sin[x] - x^2 - 1/(1 + x), x <= -1, Sin[x] - x^2 + 1/(1 + x), True,
     1.]];
谢谢野鹤和苹果!
嗯。学习了。
但是对于实数x来说,你这里Which已经包含了x的所有可以情况啊,怎么还会返回Null呢?
人为判断是包含了所有可以的情况,但是mma无法预先判断,所有需要设置当全部不满足的情况下(默认或手动设置)该返回什么。
之所以Piecewise能直接编译成功,是因为他的默认全部不满足的情况返回的是0,估计0直接赋值给浮点数变量是允许的。
嗯。找到了。
Piecewise[conds] 自动计算 Piecewise[conds,0].
...