?? expressi.cpp
字號:
///////////////////////////////////////////////////////////////////////////////////////////////////////
// 附錄 一些典型算法的程序實例
//
// 本附錄中的所有源程序文件可通過e-mail向讀者發送,如有任何問題、要求或建議,歡迎給作者發e-mail,作者的e-mail地址是 bxjsyjs@hotmail.com。請讀者注明e-mail接收地址。
// 以下各節中的程序基本上與本書前面各章節相對應,讀者在學完相關章節后,做對應的上機實習程序。
// 為了保證每個程序的完整性,使得都能單獨運行,下列各節中不同的程序之間有很多重復的代碼和相同的C函數,尤其是一些輸入/輸出函數。這樣安排的好處是讀者可以任意選擇一個范例程序,而不用閱讀這一范例程序以外的其它內容。所以請讀者在輸入程序時注意,對相同的代碼和C函數可直接在文件之間拷貝。
//
// §1 一個用于數學函數值計算的C函數 — 求任意數學函數f(x)和f(x,y)的值
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 任意輸入一個數學函數的表達式,在輸入自變量的值后,計算出數學函數表達式的值,這在很多情況下都會遇到。例如,一元函數y=2sinx+1,求x=5時的函數值y;或二元函數z=3cos(x+1)+y,求x=2,y=3時的函數值z;或三元函數q=2x+3y+sin(z+2x), 求x=1,y=2,z=3時的函數值q。
// 以下程序中的三個C函數float f(float x) 、float f(float x,float y)和float f(float x,float y,float z) 分別實現一元函數、二元函數和三元函數值的計算(因為這三個C函數的名字相同,都為f,只是參數個數不同,這用到了C++中函數重載的功能,所以要用C++編繹,即源程序文件的擴展名應取CPP)。
// 程序實現中用到了“編繹原理”中有關表達式編繹的知識,包括表達式的詞法分析、語法分析和語義生成,有興趣的讀者請參閱有關書籍。
// 程序運行后,數學函數的輸入格式采用C語言算術表達式的格式,例如對于一元函數y=2sinx+1,則輸入2*sin(x)+1;對于二元函數z=3cos(x+1)+y,則輸入3*cos(x+1)+y;對于三元函數q=2x+3(y-2)+sin(z+x),則輸入2*x+3*(y-2)+sin(z+2*x)等等。
// 需要提醒讀者注意的是,本程序的語法分析功能極其有限,僅僅提供了一個語法分析的C函數接口,有興趣的讀者可以自己添加語法分析代碼。所以對錯誤的C語言表達式輸入,大多不能報錯。因此,使用時務必輸入正確的C語言表達式。
// 下列程序是實現C語言算術表達式計算的函數,文件名取為 expressi .cpp。使用方式有二種,一是加入到讀者的project 中;二是用 #include "expressi.cpp" 語句包含到讀者的源程序文件中。本章的范例程序采用后者。所以,如果范例程序中有 #include "expressi.cpp" 語句,則讀者應首先把以下程序輸入到計算機中,并用文件名 expressi.cpp 存盤。
//
//////////////////////////////////////////////////////////////////////////////////////////////////
//計算C語言算術表達式程序,用于一元或多元函數值的計算
//
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
#define ADD 0xff01
#define SUB 0xff02
#define MUL 0xff03
#define DIV 0xff04
#define LEFT_PARENTHESES 0xff05
#define RIGHT_PARENTHESES 0xff06
#define COMMA 0xff07
#define ADD1 0xff07
#define SUB1 0xff08
#define EQU 0xff09
#define SIN 0xff10
#define COS 0xff11
#define TAN 0xff12
#define ASIN 0xff13
#define ACOS 0xff14
#define ATAN 0xff15
#define EXP 0xff16
#define LOG 0xff17
#define POW 0xff18
#define SQRT 0xff19
#define FABS 0xff1a
#define FACTORIAL 0xff1b
#define MINUS 0xff1c
struct OPERATOR_FUNCTION_NAME_LIST{
char Name[32]; //操作符字符串名字
int Code; //代碼
int Pri; //優先級
int NumOfOper; //操作數個數,即是幾元操作符
}OF_Name[]={
{"+", 0xff01,1,2},
{"-", 0xff02,1,2},
{"*", 0xff03,2,2},
{"/", 0xff04,2,2},
{"(", 0xff05,4,0},
{")", 0xff06,0,0},
{",", 0xff07,0,0},
{"sin", 0xff10,3,1},
{"cos", 0xff11,3,1},
{"tan", 0xff12,3,1},
{"asin",0xff13,3,1},
{"acos",0xff14,3,1},
{"atan",0xff15,3,1},
{"exp", 0xff16,3,1},
{"log", 0xff17,3,1},
{"pow", 0xff18,3,2},
{"sqrt",0xff19,3,1},
{"fabs",0xff1a,3,1},
{"factorial", 0xff1b,3,1},
{"minus",0xff1c,5,1},
{"",0,0}
};
//階乘函數
float Factorial(float n)
{
float Result,ftmp;
ftmp=n;
Result=1.;
while(ftmp>1.)
{
Result*=ftmp;
ftmp-=1.;
}
return(Result);
}
//表達式字符串中下一個單詞長度
int NextWordLen(char e[])
{
int i;
if(e[0]=='+'||e[0]=='-'||e[0]=='*'||e[0]=='/'||
e[0]=='('||e[0]==')'||e[0]==',')
return 1;
else
{
i=0;
do{
++i;
}while(e[i]!='+'&&e[i]!='-'&&e[i]!='*'&&e[i]!='/'&&
e[i]!='('&&e[i]!=')'&&e[i]!=','&&e[i]!='\0');
return i;
}
}
//返回單詞在操作符名字表中的下標值
int Check_OF_Name_List(char Word[])
{
int i;
i=0;
while(OF_Name[i].Name[0]!=0)
{
if(strcmp(Word,OF_Name[i].Name)==0)
return(OF_Name[i].Code); //注意,返回的是負數,請看前面OF_Name[i].Code中定義
++i;
}
return 1;
}
//返回單詞在變量名表中下標,如果表中還沒有,則加入這個單詞
int CheckOrAddVarNameList(char Word[],char VarNameList[][32])
{
int i;
i=0;
while(VarNameList[i][0]!=0)
{
if(strcmp(Word,VarNameList[i])==0)
return(i);
++i;
}
strcpy(VarNameList[i],Word);
VarNameList[i+1][0]='\0';
return(i);
}
//格式化表達式,如單詞用固定長的int數來表示
int GetFormated_C_Expression(char C_Expression[],int Fmt_C_Exp[],
char VarNameList[][32])
{
int i,i1,j,WordLen;
char Word[32];
i=0;
j=0;
while(C_Expression[i]!=0)
{
WordLen=NextWordLen(&C_Expression[i]);//取得下一個單詞長度
strncpy(Word,&C_Expression[i],WordLen); //取出單詞
Word[WordLen]='\0';
i1=Check_OF_Name_List(Word); //檢查操作符表,返回下標
if(i1<0)
{ //單詞是一個操作符
Fmt_C_Exp[j] = i1;
if(i1==SUB&&(Fmt_C_Exp[j-1]==LEFT_PARENTHESES||Fmt_C_Exp[j-1]==COMMA))
Fmt_C_Exp[j]=MINUS; // "-" 是不是一個負號而不是減號
}
else
Fmt_C_Exp[j]=CheckOrAddVarNameList(Word,VarNameList); //該單詞是一個變量名,則放入變量名字表
++j;
i+=WordLen;//下一個單詞起始位置
}
Fmt_C_Exp[j]=0xffff; //結束標志
return 0;
}
//返回操作符優先級
int OperNum(int Code)
{
int i;
i=0;
while(OF_Name[i].Code!=0)
{
if(Code==OF_Name[i].Code)
return(OF_Name[i].NumOfOper);
++i;
}
return 0;
}
//表達式是否符合C語言算術表達式,本函數有待改進,按理說用邊詞法分析邊進行語法分析和檢查
//比較好,但現在是事后分析一下有無錯誤,所以這一程序還不大經典。這是后來發現這一缺點。
int IsValidExpression(int Fmt_C_Exp[],char VarNameList[][32])
{
int i,Valid,Parentheses;
Parentheses=0;
Valid=0;
i=0;
while(Fmt_C_Exp[i]!=0xffff)
{
if(((Fmt_C_Exp[i]>=0xff01&&Fmt_C_Exp[i]<=0xff04)||Fmt_C_Exp[i]==MINUS)&&
(((Fmt_C_Exp[i-1]>=0xff01&&Fmt_C_Exp[i-1]<=0xff04)||Fmt_C_Exp[i-1]==MINUS)||
((Fmt_C_Exp[i+1]>=0xff01&&Fmt_C_Exp[i+1]<=0xff04)||Fmt_C_Exp[i+1]==MINUS)))
Valid=1;
if(Fmt_C_Exp[i]==LEFT_PARENTHESES)++Parentheses;
if(Fmt_C_Exp[i]==RIGHT_PARENTHESES)--Parentheses;
/*Other Invalid Case can be added here Or
rewrite this function at all by user!,
Otherwise,You must input a correct C_Expression!*/
/************************************/
++i;
}
if(Parentheses!=0)Valid=1;
return(Valid);
}
//返回優先數
int Pri(int Code)
{
int i;
i=0;
while(OF_Name[i].Code!=0)
{
if(Code==OF_Name[i].Code)
return(OF_Name[i].Pri);
++i;
}
return 0;
}
//實際得到4元組偽指令代碼,用棧來實現的。
int GetOperatorSerials(int Fmt_C_Exp[],int OperatorSerials[][4],int VarP)
{
int OperP;
int i,j;
int O_Stack[200],O_P; //操作符棧
int V_Stack[200],V_P; //變量和常數棧
int itmp1;
OperP=0;
O_P=0;
V_P=0;
i=0;
while(Fmt_C_Exp[i]!=0xffff)
{
if(Fmt_C_Exp[i]<2000&&Fmt_C_Exp[i]>=0)
{
V_Stack[V_P]=Fmt_C_Exp[i];
++V_P;
}
else
{
if(Fmt_C_Exp[i]!=LEFT_PARENTHESES)
while(O_P>0&&Pri(Fmt_C_Exp[i])<=Pri(O_Stack[O_P-1]))
{
if(O_Stack[O_P-1]==LEFT_PARENTHESES&&
Fmt_C_Exp[i]==RIGHT_PARENTHESES)
{
--O_P;
break;
}
if(O_Stack[O_P-1]!=LEFT_PARENTHESES)
{
switch(OperNum(O_Stack[O_P-1]))
{
case 0:
--O_P;
break;
case 1:
OperatorSerials[OperP][0]=O_Stack[O_P-1];
OperatorSerials[OperP][1]=V_Stack[V_P-1];
OperatorSerials[OperP][3]=VarP;
V_Stack[V_P-1]=VarP;
++VarP;
++OperP;
--O_P;
break;
case 2:
OperatorSerials[OperP][0]=O_Stack[O_P-1];
OperatorSerials[OperP][2]=V_Stack[V_P-1];
OperatorSerials[OperP][1]=V_Stack[V_P-2];
OperatorSerials[OperP][3]=VarP;
V_Stack[V_P-2]=VarP;
++VarP;
--V_P;
++OperP;
--O_P;
break;
}
}
else
break;
}
if(Fmt_C_Exp[i]!=RIGHT_PARENTHESES)
{
O_Stack[O_P]=Fmt_C_Exp[i];
++O_P;
}
}
++i;
}
OperatorSerials[OperP][0]=0;
return 0;
}
//變量名個數
int VarNameListLen(char VarNameList[][32])
{
int Length;
Length=0;
while(VarNameList[Length][0]!='\0') ++Length;
return(Length);
}
//生成4元組偽指令代碼總程序
int MakeFunction(char C_Expression[],int OperatorSerials[][4],
char VarNameList[][32])
{
int Fmt_C_Exp[1000];
GetFormated_C_Expression(C_Expression,Fmt_C_Exp,VarNameList);
if(IsValidExpression(Fmt_C_Exp,VarNameList))return 1;
GetOperatorSerials(Fmt_C_Exp,OperatorSerials,VarNameListLen(VarNameList));
return 0;
}
//變量賦值
void SetVarInitValue(char VarNameList[][32],float VarsSpace[])
{
int i;
i=0;
while(VarNameList[i][0]!='\0')
{
if(VarNameList[i][0]>='0'&&VarNameList[i][0]<='9')
VarsSpace[i]=atof(VarNameList[i]);
else
{
//==========================================================
// printf("\nInput: %s=",VarNameList[i]);
// scanf("%f",&VarsSpace[i]);
//===========================================================*/
}
++i;
}
}
//運行4元組偽指令代碼
float CalculationOfSerials(int OperatorSerials[][4],float VarsSpace[])
{
int i;
float a,b;
i=0;
while(OperatorSerials[i][0]!=0)
{
a=VarsSpace[OperatorSerials[i][1]];
b=VarsSpace[OperatorSerials[i][2]];
switch(OperatorSerials[i][0])
{
case EQU:
VarsSpace[OperatorSerials[i][3]]=a;
break;
case ADD:
VarsSpace[OperatorSerials[i][3]]=a+b;
break;
case ADD1:
VarsSpace[OperatorSerials[i][3]]=+a;
break;
case SUB:
VarsSpace[OperatorSerials[i][3]]=a-b;
break;
case SUB1:
VarsSpace[OperatorSerials[i][3]]=-a;
break;
case MUL:
VarsSpace[OperatorSerials[i][3]]=a*b;
break;
case DIV:
VarsSpace[OperatorSerials[i][3]]=a/b;
break;
case SIN:
VarsSpace[OperatorSerials[i][3]]=sin(a);
break;
case COS:
VarsSpace[OperatorSerials[i][3]]=cos(a);
break;
case TAN:
VarsSpace[OperatorSerials[i][3]]=tan(a);
break;
case ASIN:
VarsSpace[OperatorSerials[i][3]]=asin(a);
break;
case ACOS:
VarsSpace[OperatorSerials[i][3]]=acos(a);
break;
case ATAN:
VarsSpace[OperatorSerials[i][3]]=atan(a);
break;
case EXP:
VarsSpace[OperatorSerials[i][3]]=exp(a);
break;
case LOG:
VarsSpace[OperatorSerials[i][3]]=log(a);
break;
case POW:
VarsSpace[OperatorSerials[i][3]]=pow(a,b);
break;
case SQRT:
VarsSpace[OperatorSerials[i][3]]=sqrt(a);
break;
case FABS:
VarsSpace[OperatorSerials[i][3]]=fabs(a);
break;
case FACTORIAL:
VarsSpace[OperatorSerials[i][3]]=Factorial(a);
break;
case MINUS:
VarsSpace[OperatorSerials[i][3]]=-a;
break;
}
++i;
}
/*The value calculated by the last step is the return result.*/
return(VarsSpace[OperatorSerials[i-1][3]]);
}
//輸入一個C語言算術表達式
void InputFx(char String[])
{
printf("\nInput Function(with Varible x): ");
scanf("%s",&String[1]);
String[0]='(';
strcat(String,")");
}
//===============================================
int fx_OperatorSerials[200][4];
float fx_VarsSpace[200];
char fx_VarNameList[200][32]={"x","\0"};
char fx_C_Expression[1000];
//產生f(x)一元函數
int CreateFx(char String[])
{
strcpy(fx_VarNameList[0],"x");
strcpy(fx_VarNameList[1],"\0");
strcpy(&fx_C_Expression[1],String);
fx_C_Expression[0]='(';
strcat(fx_C_Expression,")");
if(MakeFunction(fx_C_Expression,fx_OperatorSerials,fx_VarNameList))
{
printf("\nExpression Wrong!");
return 1;
}
SetVarInitValue(fx_VarNameList,fx_VarsSpace);
return 0;
}
//產生f(x,y)等二元函數
int CreateFxy(char String[])
{
strcpy(fx_VarNameList[0],"x");
strcpy(fx_VarNameList[1],"y");
strcpy(fx_VarNameList[2],"\0");
strcpy(&fx_C_Expression[1],String);
fx_C_Expression[0]='(';
strcat(fx_C_Expression,")");
if(MakeFunction(fx_C_Expression,fx_OperatorSerials,fx_VarNameList))
{
printf("\nExpression Wrong!");
return 1;
}
SetVarInitValue(fx_VarNameList,fx_VarsSpace);
return 0;
}
//一元函數
float f(float x)
{
fx_VarsSpace[0]=x; //if single compute then rem this sentence
return(CalculationOfSerials(fx_OperatorSerials,fx_VarsSpace));
}
//二元函數
float f(float x,float y)
{
fx_VarsSpace[0]=x; //if single compute then rem this sentence
fx_VarsSpace[1]=y;
return(CalculationOfSerials(fx_OperatorSerials,fx_VarsSpace));
}
//您可以同樣方式可以定義3元,4元等任意多元函數
//程序結束
//////////////////////////////////////////////////////////////////////////////////////////////////
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -