标题:[原创]函数型计算器(VC++6.0,win32 console)
只看楼主
yu_hua
Rank: 2
等 级:论坛游民
帖 子:222
专家分:95
注 册:2006-8-10
结帖率:71.43%
 问题点数:0 回复次数:4 
[原创]函数型计算器(VC++6.0,win32 console)

/*---------------------------------------
函数型计算器(VC++6.0,Win32 Console)
程序由 yu_hua 于2007-07-27设计完成
功能:目前提供了10多个常用数学函数:
⑴正弦sin ⑵余弦cos ⑶正切tan
⑷开平方sqrt ⑸反正弦arcsin
⑹反余弦arccos ⑺反正切arctan
⑻常用对数lg ⑼自然对数ln
⑽e指数exp ⑾乘幂函数∧
用法:如果要求2的32次幂,可以打入
2^32<回车>如果要求30度角的正切可
键入tan(Pi/6)<回车>注意不能打入:
tan(30)<Enter>如果要求1.23弧度的
正弦,有几种方法都有效:
sin(1.23)<Enter>
sin 1.23 <Enter>
sin1.23 <Enter>
如果验证正余弦的平方和公式,可打入
sin(1.23)^2+cos(1.23)^2 <Enter>或
sin1.23^2+cos1.23^2 <Enter>此外两
函数表达式连在一起,自动理解为相乘
如:sin1.23cos0.77+cos1.23sin0.77
就等价于
sin(1.23)*cos(0.77)+cos(1.23)*sin(0.77)
当然你还可以依据三角变换,再用
sin(1.23+0.77)也即sin2验证一下。
本计算器充分考虑了运算符的优先级
因此诸如:2+3*4^2 实际上相当于:
2+(3*(4*4))另外函数名前面如果是
数字,那么自动认为二者相乘.同理,
如果某数的右侧是左括号,则自动
认为该数与括弧项之间隐含一乘号。
如:3sin1.2^2+5cos2.1^2 相当于
3*sin2(1.2)+5*cos2(2.1) 又如:
4(3-2(sqrt5-1)+ln2)+lg5 相当于
4*(3-2*(√5 -1)+loge(2))+log10(5)
此外,本计算器提供了圆周率 Pi
键入字母时不区分大小写,以方便使用。
----------------------------------------*/
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
using namespace std;

const char Tab=0x9;
const int DIGIT=1;

double fun(double x,char op[],int *iop)
{
while(op[*iop-1]<32) //本行使得函数嵌套调用时不必加括号
// 如 arc sin(sin(1.234)) 只需键入arc sin sin 1.234<Enter>
switch(op[*iop-1])
{
case 7: x=sin(x); (*iop)--;break;
case 8: x=cos(x); (*iop)--;break;
case 9: x=tan(x); (*iop)--;break;
case 10: x=sqrt(x); (*iop)--;break;
case 11: x=asin(x); (*iop)--;break;
case 12: x=acos(x); (*iop)--;break;
case 13: x=atan(x); (*iop)--;break;
case 14: x=log10(x);(*iop)--;break;
case 15: x=log(x); (*iop)--;break;
case 16: x=exp(x); (*iop)--;break;
}
return x;
}

double calc(char *expr,char **addr)
{
static deep; //递归深度
static char *fname[]={ "sin","cos","tan","sqrt",
"arcsin","arccos","arctan","lg","ln","exp",NULL};
double ST[10]={0.0}; //数字栈
char op[10]={'+'}; //运算符栈
char c,*rexp,*pp,*pf;
int ist=1,iop=1,last;
if(!deep)
{
pp=pf=expr;
do
{
c = *pp++;
if(c!=' '&& c!=Tab)
*pf++ = c;
}
while(c!='\0');
}
pp=expr;
if((c=*pp)=='-'||c=='+')
{
op[0] = c;
pp++;
}
last = !DIGIT;
while((c=*pp)!='\0')
{
if(c=='(')//左圆括弧
{
deep++;
ST[ist++]=calc(++pp,addr);
deep--;
ST[ist-1]=fun(ST[ist-1],op,&iop);
pp = *addr;
last = DIGIT;
if(*pp == '('||isalpha(*pp) && strnicmp(pp,"Pi",2))
{ ////目的是:当右圆括弧的
op[iop++]='*'; ////右恻为左圆括弧或函数
last = !DIGIT; ////名字时,默认其为乘法
c = op[--iop]; /////////////////////////////
goto operate ; /////////////////////////////
}
}
else if(c==')')//右圆括弧
{
pp++;
break;
}
else if(isalpha(c))
{
if(!strnicmp(pp,"Pi",2))
{
if(last==DIGIT){cout<< "π左侧遇)" <<endl;exit(1);}
ST[ist++]=3.14159265358979323846;
ST[ist-1]=fun(ST[ist-1],op,&iop);
pp += 2;
last = DIGIT;
if(!strnicmp(pp,"Pi",2)){cout<< "两个π相连" <<endl;exit(2);}
if(*pp=='('){cout<< "π右侧遇(" <<endl;exit(3);}
}
else
{
for(int i=0; (pf=fname[i])!=NULL; i++)
if(!strnicmp(pp,pf,strlen(pf)))break;
if(pf!=NULL)
{
op[iop++] = 07+i;
pp += strlen(pf);
}
else {cout<< "陌生函数名" <<endl;exit(4);}
}
}
else if(c=='+'||c=='-'||c=='*'||c=='/'||c=='^')
{
char cc;
if(last != DIGIT){cout<< "运算符粘连" <<endl;exit(5);}
pp++;
if(c=='+'||c=='-')
{
do
{
cc = op[--iop];
--ist;
switch(cc)
{
case '+': ST[ist-1] += ST[ist];break;
case '-': ST[ist-1] -= ST[ist];break;
case '*': ST[ist-1] *= ST[ist];break;
case '/': ST[ist-1] /= ST[ist];break;
case '^': ST[ist-1] = pow(ST[ist-1],ST[ist]);break;
}
}
while(iop);
op[iop++] = c;
}
else if(c=='*'||c=='/')
{
operate: cc = op[iop-1];
if(cc=='+'||cc=='-')
{
op[iop++] = c;
}
else
{
--ist;
op[iop-1] = c;
switch(cc)
{
case '*': ST[ist-1] *= ST[ist];break;
case '/': ST[ist-1] /= ST[ist];break;
case '^': ST[ist-1] = pow(ST[ist-1],ST[ist]);break;
}
}
}
else
{
cc = op[iop-1];
if(cc=='^'){cout<< "乘幂符连用" <<endl;exit(6);}
op[iop++] = c;
}
last = !DIGIT;
}
else
{
if(last == DIGIT){cout<< "两数字粘连" <<endl;exit(7);}
ST[ist++]=strtod(pp,&rexp);
ST[ist-1]=fun(ST[ist-1],op,&iop);
if(pp == rexp){cout<< "非法字符" <<endl;exit(8);}
pp = rexp;
last = DIGIT;
if(*pp == '('||isalpha(*pp))
{
op[iop++]='*';
last = !DIGIT;
c = op[--iop]; /////////////////////////////
goto operate ; /////////////////////////////
}
}
}
*addr=pp;
if(iop>=ist){cout<< "表达式有误" <<endl;exit(9);}
while(iop)
{
--ist;
switch(op[--iop])
{
case '+': ST[ist-1] += ST[ist];break;
case '-': ST[ist-1] -= ST[ist];break;
case '*': ST[ist-1] *= ST[ist];break;
case '/': ST[ist-1] /= ST[ist];break;
case '^': ST[ist-1] = pow(ST[ist-1],ST[ist]);break;
}
}
return ST[0];
}

int main()
{
char s[128],*end;
system("chcp 936"); //中文代码页
while(1)
{
cout << "请输入表达式:";
cin.getline(s,128);
cout << setprecision(17) << calc(s,&end) << endl;
}
return 0;
}

[此贴子已经被作者于2007-7-27 17:25:18编辑过]

搜索更多相关主题的帖子: 计算器 console 函数 
2007-07-27 14:23
bluecomputer
Rank: 1
等 级:新手上路
帖 子:12
专家分:0
注 册:2007-7-18
得分:0 
,xuexiing
2007-07-27 16:29
yu_hua
Rank: 2
等 级:论坛游民
帖 子:222
专家分:95
注 册:2006-8-10
得分:0 

对一楼的程序又做了改进:
⑴用C语言书写,与TC兼容
⑵改进了程序使代码更短
[CODE]
/*--------------------------------------
函数型计算器
(C语言精简版)

---------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

double(*func[])()={sin,cos,tan,sqrt,asin,acos,atan,log10,log,exp};
char*fname[]={"sin","cos","tan","sqrt","arcsin","arccos","arctan","lg","ln","exp",NULL};

double calc(char *epr,char **pe)
{
char op[10]={+1}; int iop=1;//运算符栈
char fn[10]; int ifn=0;//函数名栈
double ST[10]={0}; int ist=1;//浮点数栈
char*pp=epr,*qq,ch,sta=0;
pp+=strspn(pp," \t");
if(*pp=='+')op[0]=+1,pp++;else
if(*pp=='-')op[0]=-1,pp++;
do
{
int j,length=1; double xx;
pp+=strspn(pp," \t");
ch=tolower(*pp);
if((sta=='y'||sta=='p')&& (ch=='('))exit(1);
if((sta=='y'||sta==')')&& (ch=='p'))exit(2);
if(sta=='y'&&(isalpha(ch)&&ch!='p')){ch='*';length=0;}
if(sta=='x'&&(isalpha(ch)||ch=='(')){ch='*';length=0;}
if(sta==')'&&(isalpha(ch)||ch=='(')){ch='*';length=0;}
switch(ch)
{
case'\0': case'\n': case'=': case ')':
op[iop++]=0;//视它们为最低优先级的运算符
sta=0;
break;
case '(': ST[ist++]=calc(pp+1,pe);
length=*pe-pp;
sta=')';
break;
case '+': op[iop++]=+1; sta='@'; break;
case '-': op[iop++]=-1; sta='@'; break;
case '*': op[iop++]=+2; sta='@'; break;
case '/': op[iop++]=-2; sta='@'; break;
case '^': op[iop++]=+3; sta='@'; break;
case 'p': if(strnicmp(pp,"Pi",2))exit(3);
if(sta=='p')exit(4);
ST[ist++]=3.14159265358979323846;
length=2;
sta='p';
break;
case 'a': case's': case'c':
case 't': case'l': case'e':
for(j=0;(qq=fname[j])!=NULL;j++)
if(!strnicmp(pp,qq,strlen(qq)))break;
if(qq==NULL)exit(5);
fn[ifn++]=j+0x7;
length=strlen(qq);
sta='f';
break;
default: xx=strtod(pp,&qq);
if(pp==qq)exit(6);
if(sta=='x'||sta=='y')exit(7);
if(sta=='p'||sta==')')exit(7);
ST[ist++]=xx;
length=qq-pp;
sta='x';
break;
}
if(ist>iop) //刚刚输入的是数
{
xx=ST[ist-1];
while(ifn)//使得函数嵌套调用时可不加括号
{
xx=func[fn[--ifn]-0x7](xx);
sta='y';
}
ST[ist-1]=xx;
}
else //刚刚输入的是四则(含幂)运算符或')'或NUL
while(op[0])
{
char old=0,now=op[iop-1];
if(iop > 1)old=op[iop-2];
if(abs(now)>abs(old))break;//优先级的考虑
if(+3==now && now==old)exit(8);
if(--ist==0)exit(9);
--iop;op[iop-1]=now;
switch(old)
{
case +1: ST[ist-1] += ST[ist]; break;
case -1: ST[ist-1] -= ST[ist]; break;
case +2: ST[ist-1] *= ST[ist]; break;
case -2: ST[ist-1] /= ST[ist]; break;
case +3: ST[ist-1] = pow(ST[ist-1],ST[ist]);
}
}
pp+=length;
}
while(ch!=')'&& ch!='='&& ch!='\n'&& ch!='\0');
*pe=pp;
return ST[0];
}

int main( )
{
while(1)
{
char src[128],*end;
printf("待求表达式? ");
fgets(src,128,stdin);
printf("%.16lf\n",calc(src,&end));
}
return 0;
}
[/CODE]

[此贴子已经被作者于2007-8-3 18:43:08编辑过]

2007-08-01 08:07
yu_hua
Rank: 2
等 级:论坛游民
帖 子:222
专家分:95
注 册:2006-8-10
得分:0 
s7JbtU8J.rar (23.34 KB)



您解压后得到的EXE文件是将三楼的代码在VC6.0

Release模式下编译、连接的产物,如果用TC对它

编译、连接,估计生成的EXE文件更小。


[此贴子已经被作者于2007-8-1 20:16:59编辑过]



6QmXX0Rp.rar (23.39 KB) [原创]函数型计算器(VC++6.0,win32 console)

2007-08-01 08:22
yu_hua
Rank: 2
等 级:论坛游民
帖 子:222
专家分:95
注 册:2006-8-10
得分:0 
/*--------------------------------------
四则(含括号)表达式计算器
例如:75/3+25*3= 100.000000
3*(10-(5+(-2))*2)=12.000000
---------------------------------------*/
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main( )
{ double calc(char*,char**);
while(1){char src[128],*end;
printf("Expression: ");gets(src);
printf("%.16lf\n",calc(src,&end));}
return 0;
}
double calc(char *epr,char **pe)
{ char op[10]={1}; int iop=1;
double ST[10]={0}; int ist=1;
char*pp=epr,*qq,ch;
pp+=strspn(pp," \t");
if(*pp=='+')op[0]=+1,pp++;else
if(*pp=='-')op[0]=-1,pp++;
do
{ int length=1;
pp+=strspn(pp," \t");
switch(ch=*pp)
{ case'\0': case'\n': case'=': case')':
op[iop++] =0; break;
case '(': ST[ist++]=calc(pp+1,pe);
length=*pe-pp;break;
case '+': op[iop++]=+1; break;
case '-': op[iop++]=-1; break;
case '*': op[iop++]=+2; break;
case '/': op[iop++]=-2; break;
default: ST[ist++]=strtod(pp,&qq);
if(qq==pp)exit(1);
length=qq-pp;break;
}
if(ist<=iop)
while(op[0])
{ char old=0,now=op[iop-1];
if(iop > 1)old=op[iop-2];
if(abs(now)>abs(old))break;
if(--ist==0)exit(2);
--iop;op[iop-1]=now;
switch(old)
{ case +1: ST[ist-1] += ST[ist]; break;
case -1: ST[ist-1] -= ST[ist]; break;
case +2: ST[ist-1] *= ST[ist]; break;
case -2: ST[ist-1] /= ST[ist]; break;
}
}
pp+=length;
}
while(ch!=')'&& ch!='='&& ch!='\n'&& ch!='\0');
*pe=pp;return ST[0];
}

下面这个exe文件是TC下生成的,仅13K。

IqT7MdC0.rar (8.69 KB)

[此贴子已经被作者于2007-8-3 18:44:49编辑过]



45sSTxm1.rar (8.68 KB) [原创]函数型计算器(VC++6.0,win32 console)

2007-08-01 10:23



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-158577-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.459616 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved