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型变量。
此附代码:
因为只研究到一般表达式计算,对于矩阵计算基本没有涉及。所以计算比较简单,之后附MATCOM的使用手册,方便交流学习。
http://download.csdn.net/detail/tingtings324/8957033
之后,有涉及另外进程访问这个绘制图像,所以在绘制完成后增加一个绘制函数,将当前函数保存成图片,然后将图片保存地址通过WM_COPYDATA消息发送到另外进程,因为进程间字符串传递WM_COPYDATA这个消息还是蛮有用的。
上周开始着手一个用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这个消息还是蛮有用的。
相关文章推荐
- C++ 计蒜客算法基础入门最长上升子序列
- c/c++----------虚函数、虚继承、纯虚函数
- C语言深度解剖——读书笔记-11、指针和数组
- 黑马程序员 c语言的基础
- C++中的c_str()
- C++面试题
- C语言中输入输出重定,freopen()妙用
- 矩形面积求并
- C++中的多态
- C/C++之回调函数
- 2.2&2.3 Variables
- 用C语言写猜数字游戏
- C++ 命名空间
- c/c++ 笔试题 各种 a++
- 基于c++强制类型转换的(总结)详解
- 表达式求值 c++语言
- 深入解析C语言声明
- Introduce to algorithm--------pseudo code to C/C++ code(chapter 15)
- LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- C++中的堆和栈