关于oo第二次作业优化的一点思考

前情提要---------算了我感觉大家就知道就不说了。 

那么就直接步入正题吧,如何优化结果,即使得输出长度尽可能短一些。

也就是在规定的格式范围并保证等价的情况下,尽量简化一个含有幂函数与三角函数的表达式,化简操作对应的主要是三角函数。(下述优化建立在已经可以实现合并同类项的基础上)

在仅包含正弦与余弦函数的情况下,可以使用的三角关系相当有限,大部分化简都是如下的考量,将形如:

poly*(sin(x)^2+cos(x)^2)

的式子,简化为

poly

其中,poly对应的是多项式,即表达式。

那么,问题就是,怎样在一个多项式中找到一个子多项式,可以化简为上述形式并使得poly的项数尽可能的大呢?

很容易想到的是,先用单个的项与其他的项进行合并。即先把

mono*(sin(x)^2+cos(x)^2)

的式子,简化为

mono

用一个四元组(c,xe,se,ce)表示一个项,各字母的意义分别是,系数、x的指数,sin(x)的指数,cos(x)的指数。

对于一个单项mono1(c1,xe1,se1,ce1),与另外一个单项mono2(c2,xe2,se2,ce2),如果满足以下条件,即可合并。

(1)  xe1=xe2,即,x对应的指数必须相同

(2)  c1与c2符号相同(保证稳定性)

(3)  se1-se2==2  &  ce2-ce1==2  |  se2-se1==2  &  ce1-ce2==2

满足上述条件,不妨设c1与c2均为正,c1为较小的系数,那么就可以将两项合并为(c1,xe1,min(se1,se2),min(ce1,ce2)),再加一个余项(c2-c1,xe2,se2,ce2)。

简单来说,就是把mono2拆成两项,一项与mono1合并,并且提取出公因式mono,另外还有一个余项mono3跟在后面,经过化简,mono1与mono2变成了mono与mono3。

那么长度是否减小了呢?

由于mono的系数与mono1相同,指数小于mono1,故mono的长度必定是小于等于mono1的。

由于mono3的指数与mono2相同,系数小于mono2,故mono3的长度必定是小于等于mono2的。

所以上述化简方法确实可以使得长度逐渐减小,并且在系数相同时,达到了最佳的输出(余项为0)。

那么约定符号相同也很容易理解了,如果两项符号不同,可能出现化简后长度反增的情况:

9*sin(x)^12*cos(x)^12-2*sin(x)^10*cos(x)^14

经上述化简后:

11*sin(x)^12*cos(x)^12-2*sin(x)^10*cos(x)^12

化简后长度反而变长了,这是由于一项系数的绝对值增加,当指数的长度的减小(或不变)不足以抵消掉系数长度的增加时,输出长度可能会增加。

所以如果要保证达到最优效果,上述方法应该放宽符号限制,当系数符号相反时,根据具体的系数与指数的值,决定是否合并。

 

这就是基本的优化思路,但是还不够,因为我们发现:

cos(x)^4-sin(x)^4

用上述方法是无法优化的,但是

cos(x)^4-sin(x)^4=(cos(x)^2-sin(x)^2)*(cos(x)^2+sin(x)^2)

         =cos(x)^2-sin(x)^2

         =1-2*sin(x)^2

是可以化简为更短的一个式子的,但是其不满足上述条件(3),无法使用上述方法优化。

那么怎么优化呢?

回到最前面的问题,我们的目标是找到一个包含尽可能多项的一个poly,将poly*(sin(x)^2+cos(x)^2),化简为poly

在上面,我们采用了分析项与项之间关系的方法,这与直接提取多项式是不同的。

简单来说,因式分解时,以

a^2-b^2=(a-b)*(a+b)

为例,左侧并不直接包含a*(a+b)与-b*(a+b)两项,所以我们去直接提取a+b的话是无法得到结果的。作为人,我们知道可以加上a*b-a*b一项,并不改变左侧等式的值,就可以把左侧变化为右侧的形式,那么能不能以同样的方法去写程序呢?

下面是笔者由于种种原因没有动笔的思路,所以可能会存在一点点问题,如果有的话希望大家及时指出。

-------------------------------------------分割线--------------------------------------------------------

设项(c,xe,se,ce)(c!=0):


若se>=2,定义其sin辅助项为(-c,xe,se-2,ce+2),结果项为(c,xe,se-2,ce)

若ce>=2,定义其cos辅助项为(-c,xe,se+2,ce-2),结果项为(c,xe,se,ce-2)

辅助项的意义与上述a*b的意义相同,在于为合并提供一座“桥梁”,沟通一些本不能合并的项。结果项的意义是与辅助项的相反合并后的公因式。

这样,一个项就可以表示为其对于结果项与辅助项的和。

以cos(x)^4为例,其cos辅助项为-cos(x)^2*sin(x)^2,其结果项为cos(x)^2,过程如下:

cos(x)^4=cos(x)^4+cos(x)^2*sin(x)^2-cos(x)^2*sin(x)^2

     =cos(x)^2*(sin(x)^2-cos(x)^2)-cos(x)^2*sin(x)^2

     =cos(x)^2-cos(x)^2*sin(x)^2

这只是一个辅助理解的式子,并没有使式子得到简化。那么什么条件下才可以简化长度呢?

我们尝试以如下方法去遍历一个多项式中的每个项mono:

若mono的se>=2,依次判断:

(1)查询其sin辅助项能否与其他项进行合并同类项,可以的话将mono更新为其结果项,将辅助项合并。

(2)查询其sin结果项能否与其他项进行合并同类项,可以的话讲mono更新为其辅助项,将结果项合并。特殊地,如果辅助项已在第一步合并,直接合并结果项,将mono项更新为0即可。

若均无法合并,再去同理判断ce即可

那么这样的合并一定会使长度减小吗?

答案其实是不一定的,也需要去判断对应的指数与系数的长度。当结果项与辅助项都可以合并时,长度是一定会减少的,但是当只有其中的一项可以合并时,长度可能会增加也可能会减少。

所以上述方法应该变一下:

(1)若se>=2,判断其sin辅助项与结果项是否均可合并,若是,则合并,判断下一项。

(2)若否,如果ce>=2,判断cos辅助项与结果项是否均可合并,若是,则合并,判断下一项。

(3)若(1)与(2)中的答案均为否,再去判断单独合并的情况。

判断单独合并时,就要判断系数与指数的值,决定是否合并(与刚开始的符号相反的情况原理相同)。

这样的合并已经可以满足大部分情况了,但是好像还不大够,显得有一点“目光短浅”了。

考虑下面这种情况:

若mono的sin结果项可以与其他合并,辅助项不可以,此时合并会使得长度+1,所以拒绝了本次合并。但是有另外一个项mono1,它的cos辅助项可以合并,结果项可以与mono的sin辅助项合并(无法与其他项合并)。

此时,拒绝掉mono的合并会使得后面mono1也无法合并,这样就失去了合并的机会。例如:

sin(x)^8的sin辅助项-sin(x)^6*cos(x)^2可以与sin(x)^6*cos(x)^4的cos结果项sin(x)^6*cos(x)^2合并  (其他项略)

这个时候如果还要想进一步优化该怎么办呢?

细心的你肯定已经注意到了,上述对于合并的概念还停留在合并同类项的层面,如果对于辅助项/结果项与其他项的合并,也采用划分为结果项与辅助项的思路,是不是就可以合并了?

当然,这样一路下去是个无底洞,笔者就不继续分析了。优化方法的复杂度与收益已经远远不成正比了,追求极致的优化几乎是不可能的。

 

转载于:https://www.cnblogs.com/tqnwhz/p/10559893.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值