您的位置:首页 > 编程语言 > C语言/C++

MATCOM & C++ &数学表达式计算

2015-08-03 19:23 567 查看
时间是2015年8月3号,这么样开始一片技术类博文,真真的是..醉到不行,话不多说,开始主题。

上周开始着手一个用C++ 实现各种自定义函数(仅限初高中)的二维图形,一开始就没想过说要自己通过计算,采点来重构这些函数图形,因为感觉不同函数图形受采点个数和函数重构方法不同,而且对于再次差分拟合这一步来说,确实有些心悸。

所以,一开始就想好matlab&C++混编的路子,但是实在想不来从C++ 到matlab 到底要传什么参数去自定义的m文件,后来有幸看到篇C++ MATCOM混编的博文,于是心有所感。所以我的思路就是:

1:安装MATCOM 4.5,因为只是用到它的库函数,所以在选择编译器的时候我直接选择VS2010的cl.exe然后直接取出lib下的matlab.h,v4501v.lib文件和系统路径下v4501v.dll和ago4501.dll,同样放置在自己项目路径下。这样就配置好运行matcom环境,可以直接绘制函数图形,而不必依赖matlab环境。

2:表达式计算,采用的是一般的中缀变后缀的数学计算。整个过程大致包含两个部分,1:表达式的转化,即从中缀表达式入栈转化为后缀表达式,2:后缀表达式的计算。

中缀变后缀的一般思想:

从左端开始扫描字符串

1、遇到操作数(判断取完整个的操作数),然后压入元素栈、。

2、如果读取的是运算符

a、如果是'(' 直接压入运算符栈

b、如果是')'则将运算符栈中的运算符逐个压入元素栈,直到遇到'('

c、若运算符栈栈顶元素是括号,直接入运算符栈

d、若比运算符栈栈顶元素的优先级高或者相等,直接存入运算符栈

e、若比栈顶元素的优先级低,则输出运算符栈顶元素到 元素栈,并将当前运算符压入运算符栈。

3、当表达式读取完成后,运算符栈中尚有运算符,依次取出运算符栈中元素压入到操作数中直到运算符栈中元素为空。

4、方便下一步计算,在此将运算符栈元素逆序。

计算:

假如遇到的是操作数,放入数组,

假如遇到二元运算符,则取出栈中的两个元素进行计算。

因为计算过程包含两个不确定内容.1:变量X ,在此处将变量X也作为一个数字来进行处理。2:整个表达式夹杂了三角函数,指数,对数等函数,所以在处理过程中,首先将整个的函数作为一个单独块,之后计算的时候将sin后面的表达式块 递归调用表达式转化,然后再进行计算。

然后还有对于,MATCOM里面的计算都是针对Mm型变量,故而在计算前需要将所有操作数转化成Mm型变量。

此附代码:

void CMatComDlg::GetUintFuncFromStr(Mm& y,CString str)
{
Stack_CString m1,m2,m3;
/*
运算符表达式中必须先检测大中小括号,先小后中,最后大
之后才判断"+、-、*、/"运算
2015-07-31 增加针对指数的检查。现在指数的情况分三部分.
0:  指数只考虑一级指数的情况
1:  x^3
2: (x+2)^3

对于情况1:需要在每个单元的后面检测是否包han^
情况2:需要判断')'括号是否是^

如果包含^ 则需要把包含...^(...)的整个字符串都进行处理。  
暂时不考虑log之后,还有^之后还包含其他指数的情况。
*/

//if (-1 ==str.Find(L"sin") || -1 ==str.Find(L"cos") ||-1 ==str.Find(L"tan")||
// -1 ==str.Find(L"cot")||-1 ==str.Find(L"sec")||-1 ==str.Find(L"csc")||
// -1 ==str.Find(L"log")||-1 ==str.Find(L"^"))//
{
int str_len = str.GetLength();
for (int i=0;i<str_len;i++)
{
switch (str[i])
{
case '(':
{
/*考虑指数情况,则需要针对 (处特殊判断  在出现(的地方判断与其相对应的)后面是否有^
如果不包含,一般处理。
如果包含,则把整个字串传递出去,之后分化处理
*/ 
CString temp,temp_1;
temp_1 = str.Right(str.GetLength()-i);//从最左端包含'('开始的字串
int Count = CountBetweenBrackets(temp_1);
if (Count< temp_1.GetLength() && temp_1[Count+1] != '^')
{
temp.AppendChar(str[i]);
m1.push(temp);
}
else//包含
{
while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
{
m2.push(m1.top());
m1.pop(); 
}
// temp = str.Left(Count);
Count++;
temp = str.Left(Count);
temp_1 = temp_1.Right(temp_1.GetLength()-Count-1);//获取指数后面的字符串
temp_1 = GetIndexStr(temp_1);
temp = temp+'^'+temp_1; 
int i_Count = temp.GetLength();
i+=i_Count;
m1.push(temp);
}
}
break;
case ')':
{
while (m1.top() != '(')
{
m2.push(m1.top()); 
m1.pop();
}
m1.pop();
}
break;
case '+':
case '-':
{
while (m1.size()!=0 && m1.top()!= '(')
{
m2.push(m1.top());
m1.pop();
}
CString temp;
temp.AppendChar(str[i]);
m1.push(temp);
}
break;
case '*': 
case '/':
{
while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'
&&m1.top()!='-')
{
m2.push(m1.top());
m1.pop();
}
CString temp;
temp.AppendChar(str[i]);
m1.push(temp);
break;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
CString temp;
temp.AppendChar(str[i]);
//判断出所有的...
while (str[i+1]>='0' && str[i+1]<= '9')
{
temp.AppendChar(str[i+1]);
i++;
}//得到整个整数
//在这里判断下一个字符是否包含^
if (str[i+1] != '^' )
{
m2.push(temp);
}else
{
while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
{
m2.push(m1.top());
m1.pop(); 
}
i++;
CString temp_1 = str.Right(str.GetLength()-i-1);//获取指数后面的字符串
temp_1 = GetIndexStr(temp_1);
temp = temp+'^'+temp_1; 
int i_Count = temp_1.GetLength();
i+=i_Count;
m1.push(temp);
}

}
break;
case 'x'://变量,把变量和数字当做同一级对待
{
  CString temp;
temp.AppendChar(str[i]);
//判断下一个字符是否是'^'
if (str[i+1] != '^')
{
m2.push(temp);
}
else
{
i++;
while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
{
m2.push(m1.top());
m1.pop(); 
}
CString temp_1 = str.Right(str.GetLength()-i-1);//获取指数后面的字符串
temp_1 = GetIndexStr(temp_1);
temp = temp+'^'+temp_1; 
int i_Count = temp_1.GetLength();
// int i_Count = temp.GetLength();
i+=i_Count;
m1.push(temp);
}

}
break;
case 'c'://cos cot csc
case 't'://tan
case 's'://遇到特殊字符说明开始特殊函数 sin sec
{
while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
{
m2.push(m1.top());
m1.pop(); 
}
/*
因为是个表达式,所以在这里需要把sin()后面的内容当做整体,
还是在之后的计算部分,在做处理??
//
先当做整体,之后计算的时候,再次调用转化,将括号里面的内容转化成Mm.
再和sin一起,作为一个对象进行计算。
*/
CString temp;
for (int j=0;j<3;j++)//取到完整的函数名
{ 
temp.AppendChar(str[i]);
i++;
} 

//假如'sin('从i开始,找到第一个(和与之相对应的最后一个)
if (str[i] == '(')
{
//如果有括号。找到与之对应的最后一个')'
CString temp_1 = str.Right(str.GetLength()-i);
int Count = CountBetweenBrackets(temp_1);

i+=Count;//到后括号
//判断下一个字符是否是'^'
if (str[i+1]!='^')
{
temp += temp_1.Left(Count+1);
}
else
{
//while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
//{
// m2.push(m1.top());
// m1.pop();
//}
i++;
temp += temp_1.Left(Count+1);
CString temp_1 = str.Right(str.GetLength()-i-1);//获取指数后面的字符串
temp_1 = GetIndexStr(temp_1);
temp = temp+'^'+temp_1; 
int i_Count = temp_1.GetLength();
i+=i_Count;
// m1.push(temp);
}
}
else if(str[i]>='0' && str[i]<= '9')//sin 后面没有括号-没有表达式,直接是个数字
{
//如果是数字,应当取到完整的数字,暂时不考虑数字后面会出现指数的情况
while (str[i]>='0' && str[i]<= '9')
{
temp.AppendChar(str[i]);
i++;
}
//判断下一个字符是否是'^'
if (str[i] == '^')
{
//while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
//{
// m2.push(m1.top());
// m1.pop();
//}
CString temp_1 = str.Right(str.GetLength()-i-1);//获取指数后面的字符串
temp_1 = GetIndexStr(temp_1);
temp = temp+'^'+temp_1; 
int i_Count = temp.GetLength();
i+=i_Count;
// m1.push(temp);
}
}
else//或者'x'
{
temp.AppendChar(str[i]);
//判断下一个字符是否是'^'
if (str[i+1] == '^')
{
i++;
//while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
//{
// m2.push(m1.top());
// m1.pop();
//}
CString temp_1 = str.Right(str.GetLength()-i-1);//获取指数后面的字符串
temp_1 = GetIndexStr(temp_1);
temp = temp+'^'+temp_1; 
int i_Count = temp.GetLength();
i+=i_Count;
// m1.push(temp);
}
}
m1.push(temp);
}
break;
case 'l'://对数,现要求对数的一般格式log(3)^(x+3)
{
while (m1.size()>0 && m1.top()!='(' && m1.top()!='+'&& m1.top()!='-')
{
m2.push(m1.top());
m1.pop(); 
}
//同样,假如^后第一个字符是'(' 需要找到与其相对应的')'.然后把整个的 log(3)^(x+3)作为一个对象进行处理
CString temp,temp_1;
temp_1 = str.Right(str.GetLength()-i);//取到以log开头的字符串
int lgCount = temp_1.Find('^');
temp = temp_1.Left(lgCount+1);//获取到^左边的字符

temp_1= temp_1.Right(temp_1.GetLength()-lgCount - 1);//获取到^右边的字符串

if (temp_1.Find('(') != 0)
{
//当下的第一个字符不是(,说明幂集不是个表达式。此处就不再判断幂集之上还有幂集的情况,剩余的应该就当做x或者一个数字处理
if (temp_1[0]=='x')
{
temp.AppendChar('x');
i+=lgCount+1;

}else
{
CString temp_2;
int lelei=0;
while (temp_1[lelei]>'0' && temp_1[lelei]<'9')
{
temp_2.AppendChar(temp_1[lelei]);
lelei++;
}
i += lelei;
temp+=temp_2;
}
}
else
{
//包含括号,找到与第一个括号相对应的字符个数,然后直接截取
int Count = CountBetweenBrackets(temp_1);
temp_1.Left(Count);
i+=lgCount+Count;
temp+=temp_1;
}

m1.push(temp);
}
break;
}
}
}

while(m1.size()!=0)
{
m2.push(m1.top());
m1.pop();
}
ReverseStack(m2,m3);
y = ComputeMm(m3);
}

表达式计算
Mm CMatComDlg::ComputeMm(Stack_CString& m2)
{
int top = 0;
Mm mm,m_TempMm[128];
while(m2.size()!=0)
{
if (m2.top() == '+')
{
top--;//因为最前面的一个是空值
mm = m_TempMm[top]+m_TempMm[top-1];
m_TempMm[--top]=mm;
//
top++;
// 
m2.pop();
}
else if (m2.top() == '-')
{
top--;
mm = m_TempMm[top-1]-m_TempMm[top];
m_TempMm[--top]=mm;
m2.pop();
//
top++;
//
}
else if (m2.top() == '*')
{
top--;
// mm = m_TempMm[top]*m_TempMm[top-1];
mm = times(m_TempMm[top],m_TempMm[top-1]);
m_TempMm[--top]=mm;
m2.pop();
//
top++;
//
}
else if (m2.top() == '/')
{
top--;
// mm = m_TempMm[top-1]/m_TempMm[top];
// rdivide
mm = rdivide(m_TempMm[top-1],m_TempMm[top]);//m_TempMm[top-1]/m_TempMm[top];
m_TempMm[--top]=mm;
m2.pop();
//
top++;
//
}
else //判断str是不是数字,是的话直接赋给Mm
{
//m2.top()是一个类似 sin(...)的格式
/*
2015-07-31 增加对存在指数的情况进行处理.
*/
CString str_temp = m2.top().GetBuffer();
//处理括号后面带^的情况
if (str_temp[0] == '(' && str_temp.Find('^') > 0)
{
CString temp_str1,temp_str2;
Mm temp_Mm1,temp_Mm2;
//从 str 里面找到^的前后两部分.
int Index_Count = str_temp.Find('^');
temp_str1 = str_temp.Left(Index_Count);
temp_str2 = str_temp.Right(str_temp.GetLength()-Index_Count-1);
GetUintFuncFromStr(temp_Mm1,temp_str1);
GetUintFuncFromStr(temp_Mm2,temp_str2);
m_TempMm[top++] = power(temp_Mm1,temp_Mm2);
}
else if (-1 != m2.top().Find('s')||
-1 != m2.top().Find('c')||
-1 != m2.top().Find('t'))//包含特殊函数,需要进行转化
{
CString temp = m2.top().Left(3);
if (temp == "sin")
{
Mm temp_Mm;
//获取后面的字符串
CString temp_1 = m2.top().Right(m2.top().GetLength()-3);
GetUintFuncFromStr(temp_Mm,temp_1);
m_TempMm[top++] = sin(temp_Mm);
}
else if (temp == "cos")
{
Mm temp_Mm;
//获取后面的字符串
CString temp_1 = m2.top().Right(m2.top().GetLength()-3);
GetUintFuncFromStr(temp_Mm,temp_1);
m_TempMm[top++] = cos(temp_Mm);
}
else if (temp == "tan")
{
Mm temp_Mm;
//获取后面的字符串
CString temp_1 = m2.top().Right(m2.top().GetLength()-3);
GetUintFuncFromStr(temp_Mm,temp_1);
m_TempMm[top++] = tan(temp_Mm);
}
else if (temp == "cot")
{
Mm temp_Mm;
//获取后面的字符串
CString temp_1 = m2.top().Right(m2.top().GetLength()-3);
GetUintFuncFromStr(temp_Mm,temp_1);
m_TempMm[top++] = cot(temp_Mm);
}
else if (temp == "csc")
{
Mm temp_Mm;
//获取后面的字符串
CString temp_1 = m2.top().Right(m2.top().GetLength()-3);
GetUintFuncFromStr(temp_Mm,temp_1);
m_TempMm[top++] = csc(temp_Mm);
}
else if (temp == "sec")
{
Mm temp_Mm;
//获取后面的字符串
CString temp_1 = m2.top().Right(m2.top().GetLength()-3);
GetUintFuncFromStr(temp_Mm,temp_1);
m_TempMm[top++] = sec(temp_Mm);
}
}
else if (-1 != m2.top().Find('l'))//对数
{
//对数的处理包括两部分log(x1)^(x2) 只要分别获取两部分的内容然后计算到Mm,然后就可以直接计算。
CString temp1,temp2,temp=m2.top();
Mm temp_Mm1,temp_Mm2;
int m_Count = temp.Find('^');
temp1 = temp.Left(m_Count);
temp1 = temp1.Right(temp1.GetLength()-3);//去掉log
temp2 = temp.Right(temp.GetLength()-m_Count-1);
GetUintFuncFromStr(temp_Mm1,temp1);
GetUintFuncFromStr(temp_Mm2,temp2);
//一般对数需要换底公式进行求取
m_TempMm[top++] = rdivide(log(temp_Mm2),log(temp_Mm1));
}
else if(m2.top().Find('x') >= 0)
{
CString temp_index_x = m2.top();
if (temp_index_x.Find('^') < 0)//不存在指数
{
m_TempMm[top++] = m_Mmx;
}
else
{
temp_index_x = temp_index_x.Right(temp_index_x.GetLength()-2);
Mm temp_Index_mm;
GetUintFuncFromStr(temp_Index_mm,temp_index_x);
m_TempMm[top++] = power(m_Mmx,temp_Index_mm);
}
}
else//数字
{
CString Count = m2.top();
if (Count.GetLength()!=0 && Count.Find('^')<0)//没有发现^
{
int m_nCount = CStringToInt(Count);
m_TempMm[top++] = m_nCount;
}
else
{
int Count_Index_nu = Count.Find('^');
CString temp_str1,temp_str2;
Mm temp_Mm_Count;
temp_str1 = Count.Left(Count_Index_nu);
temp_str2 = Count.Right(Count.GetLength()-Count_Index_nu-1);
int m_nCount = CStringToInt(temp_str1);
GetUintFuncFromStr(temp_Mm_Count,temp_str2);
m_TempMm[top++] = power(m_nCount,temp_Mm_Count);
}
}
m2.pop();
} 
}
return m_TempMm[0];
}


因为只研究到一般表达式计算,对于矩阵计算基本没有涉及。所以计算比较简单,之后附MATCOM的使用手册,方便交流学习。
http://download.csdn.net/detail/tingtings324/8957033
之后,有涉及另外进程访问这个绘制图像,所以在绘制完成后增加一个绘制函数,将当前函数保存成图片,然后将图片保存地址通过WM_COPYDATA消息发送到另外进程,因为进程间字符串传递WM_COPYDATA这个消息还是蛮有用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: