📄 fprase.cpp
字号:
// And this: mul(x) = x, min(x) = x, max(x) = x, add(x) = x
if(GetArgCount() == 1)
{
if(GetOp() == cMul || GetOp() == cAdd || GetOp() == cMin || GetOp() == cMax)
if(!getp0().getsign())
ReplaceWith(*getp0());
}
OptimizeDoubleNegations();
}
void OptimizeDoubleNegations()
{
if(GetOp() == cAdd)
{
// Eschew double negations
// If any of the elements is cMul
// and has a numeric constant, negate
// the constant and negate sign.
for(pit a=GetBegin(); a!=GetEnd(); ++a)
{
SubTree &pa = *a;
if(pa.getsign()
&& pa->GetOp() == cMul)
{
CodeTree &p = *pa;
for(pit b=p.GetBegin();
b!=p.GetEnd(); ++b)
{
SubTree &pb = *b;
if(pb->IsImmed())
{
pb.Negate();
pa.Negate();
break;
}
}
}
}
}
if(GetOp() == cMul)
{
// If any of the elements is cPow
// and has a numeric exponent, negate
// the exponent and negate sign.
for(pit a=GetBegin(); a!=GetEnd(); ++a)
{
SubTree &pa = *a;
if(pa.getsign() && pa->GetOp() == cPow)
{
CodeTree &p = *pa;
if(p.getp1()->IsImmed())
{
// negate ok for pow when op=cImmed
p.getp1().Negate();
pa.Negate();
}
}
}
}
}
void OptimizeConstantMath1()
{
// This optimization does three things:
// - For adding groups:
// Constants are added together.
// - For multiplying groups:
// Constants are multiplied together.
// - For function calls:
// If all parameters are constants,
// the call is replaced with constant value.
// First, do this:
OptimizeAddMulFlat();
switch(GetOp())
{
case cAdd:
{
ConstList cl = BuildConstList();
FinishConst(cl);
break;
}
case cMul:
{
ConstList cl = BuildConstList();
if(cl.value == 0.0) ReplaceWithConst(0.0);
else FinishConst(cl);
break;
}
#define ConstantUnaryFun(token, fun) \
case token: { const SubTree &p0 = getp0(); \
if(p0->IsImmed()) ReplaceWithConst(fun(p0->GetImmed())); \
break; }
#define ConstantBinaryFun(token, fun) \
case token: { const SubTree &p0 = getp0(); \
const SubTree &p1 = getp1(); \
if(p0->IsImmed() && \
p1->IsImmed()) ReplaceWithConst(fun(p0->GetImmed(), p1->GetImmed())); \
break; }
// FIXME: potential invalid parameters for functions
// can cause exceptions here
ConstantUnaryFun(cAbs, fabs);
ConstantUnaryFun(cAcos, acos);
ConstantUnaryFun(cAsin, asin);
ConstantUnaryFun(cAtan, atan);
ConstantUnaryFun(cCeil, ceil);
ConstantUnaryFun(cCos, cos);
ConstantUnaryFun(cCosh, cosh);
ConstantUnaryFun(cFloor, floor);
ConstantUnaryFun(cLog, log);
ConstantUnaryFun(cSin, sin);
ConstantUnaryFun(cSinh, sinh);
ConstantUnaryFun(cTan, tan);
ConstantUnaryFun(cTanh, tanh);
ConstantBinaryFun(cAtan2, atan2);
ConstantBinaryFun(cMax, Max);
ConstantBinaryFun(cMin, Min);
ConstantBinaryFun(cMod, fmod); // not a func, but belongs here too
ConstantBinaryFun(cPow, pow);
case cNeg:
case cSub:
case cDiv:
/* Unreached (nonexistent operator)
* TODO: internal error here?
*/
break;
case cCot:
case cCsc:
case cSec:
case cDeg:
case cRad:
case cLog10:
case cSqrt:
case cExp:
/* Unreached (nonexistent function)
* TODO: internal error here?
*/
break;
}
OptimizeConflict();
}
void OptimizeAddMulFlat()
{
// This optimization flattens the topography of the tree.
// Examples:
// x + (y+z) = x+y+z
// x * (y/z) = x*y/z
// x / (y/z) = x/y*z
if(GetOp() == cAdd || GetOp() == cMul)
{
// If children are same type as parent add them here
for(pit b, a=GetBegin(); a!=GetEnd(); a=b)
{
const SubTree &pa = *a; b=a; ++b;
if(pa->GetOp() != GetOp()) continue;
// Child is same type
for(pcit c=pa->GetBegin();
c!=pa->GetEnd();
++c)
{
const SubTree &pb = *c;
if(pa.getsign())
{
// +a -(+b +c)
// means b and c will be negated
SubTree tmp = pb;
if(GetOp() == cMul)
tmp.Invert();
else
tmp.Negate();
AddParam(tmp);
}
else
AddParam(pb);
}
Erase(a);
// Note: OptimizeConstantMath1() would be a good thing to call next.
}
}
}
void OptimizeLinearCombine()
{
// This optimization does the following:
//
// x*x*x*x -> x^4
// x+x+x+x -> x*4
// x*x -> x^2
// x/z/z ->
//
// Remove conflicts first, so we don't have to worry about signs.
OptimizeConflict();
bool didchanges = false;
if(GetOp() == cAdd || GetOp() == cMul)
{
Redo:
for(pit a=GetBegin(); a!=GetEnd(); ++a)
{
const SubTree &pa = *a;
list<pit> poslist;
for(pit b=a; ++b!=GetEnd(); )
{
const SubTree &pb = *b;
if(*pa == *pb)
poslist.push_back(b);
}
unsigned min = 2;
if(poslist.size() >= min)
{
SubTree arvo = pa;
bool negate = arvo.getsign();
double factor = poslist.size() + 1;
if(negate)
{
arvo.Negate();
factor = -factor;
}
CodeTree tmp(GetOp()==cAdd ? cMul : cPow,
arvo,
factor);
list<pit>::const_iterator j;
for(j=poslist.begin(); j!=poslist.end(); ++j)
Erase(*j);
poslist.clear();
*a = tmp;
didchanges = true;
goto Redo;
}
}
}
if(didchanges)
{
// As a result, there might be need for this:
OptimizeAddMulFlat();
// And this:
OptimizeRedundant();
}
}
void OptimizeLogarithm()
{
/*
This is basic logarithm math:
pow(X,Y)/log(Y) = X
log(X)/log(Y) = logY(X)
log(X^Y) = log(X)*Y
log(X*Y) = log(X)+log(Y)
exp(log(X)*Y) = X^Y
This function does these optimizations:
pow(const_E, log(x)) = x
pow(const_E, log(x)*y) = x^y
pow(10, log(x)*const_L10I*y) = x^y
pow(z, log(x)/log(z)*y) = x^y
And this:
log(x^z) = z * log(x)
Which automatically causes these too:
log(pow(const_E, x)) = x
log(pow(y, x)) = x * log(y)
log(pow(pow(const_E, y), x)) = x*y
And it does this too:
log(x) + log(y) + log(z) = log(x * y * z)
log(x * exp(y)) = log(x) + y
*/
// Must be already in exponential form.
// Optimize exponents before doing something.
OptimizeExponents();
if(GetOp() == cLog)
{
// We should have one parameter for log() function.
// If we don't, we're screwed.
const SubTree &p = getp0();
if(p->GetOp() == cPow)
{
// Found log(x^y)
SubTree p0 = p->getp0(); // x
SubTree p1 = p->getp1(); // y
// Build the new logarithm.
CodeTree tmp(GetOp(), p0); // log(x)
// Become log(x) * y
ReplaceWith(cMul, tmp, p1);
}
else if(p->GetOp() == cMul)
{
// Redefine &p nonconst
SubTree &p = getp0();
p->OptimizeAddMulFlat();
p->OptimizeExponents();
CHECKCONSTNEG(p, p->GetOp());
list<SubTree> adds;
for(pit b, a = p->GetBegin();
a != p->GetEnd(); a=b)
{
SubTree &pa = *a; b=a; ++b;
if(pa->GetOp() == cPow
&& pa->getp0()->IsImmed()
&& pa->getp0()->GetImmed() == CONSTANT_E)
{
adds.push_back(pa->getp1());
p->Erase(a);
continue;
}
}
if(adds.size())
{
CodeTree tmp(cAdd, *this);
list<SubTree>::const_iterator i;
for(i=adds.begin(); i!=adds.end(); ++i)
tmp.AddParam(*i);
ReplaceWith(tmp);
}
}
}
if(GetOp() == cAdd)
{
// Check which ones are logs.
list<pit> poslist;
for(pit a=GetBegin(); a!=GetEnd(); ++a)
{
const SubTree &pa = *a;
if(pa->GetOp() == cLog)
poslist.push_back(a);
}
if(poslist.size() >= 2)
{
CodeTree tmp(cMul, 1.0); // eek
list<pit>::const_iterator j;
for(j=poslist.begin(); j!=poslist.end(); ++j)
{
const SubTree &pb = **j;
// Take all of its children
for(pcit b=pb->GetBegin();
b!=pb->GetEnd();
++b)
{
SubTree tmp2 = *b;
if(pb.getsign()) tmp2.Negate();
tmp.AddParam(tmp2);
}
Erase(*j);
}
poslist.clear();
AddParam(CodeTree(cLog, tmp));
}
// Done, hopefully
}
if(GetOp() == cPow)
{
const SubTree &p0 = getp0();
SubTree &p1 = getp1();
if(p0->IsImmed() && p0->GetImmed() == CONSTANT_E
&& p1->GetOp() == cLog)
{
// pow(const_E, log(x)) = x
ReplaceWith(*(p1->getp0()));
}
else if(p1->GetOp() == cMul)
{
//bool didsomething = true;
pit poslogpos; bool foundposlog = false;
pit neglogpos; bool foundneglog = false;
ConstList cl = p1->BuildConstList();
for(pit a=p1->GetBegin(); a!=p1->GetEnd(); ++a)
{
const SubTree &pa = *a;
if(pa->GetOp() == cLog)
{
if(!pa.getsign())
{
foundposlog = true;
poslogpos = a;
}
else if(*p0 == *(pa->getp0()))
{
foundneglog = true;
neglogpos = a;
}
}
}
if(p0->IsImmed()
&& p0->GetImmed() == 10.0
&& cl.value == CONSTANT_L10I
&& foundposlog)
{
SubTree base = (*poslogpos)->getp0();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -