通用的数学表达式编译计算动态库FORCAL.DLL
为了进行某些数值计算,您是否还在不得不借助于FORTRAN(或C/C++)编译器?虽然,对于运算量特别巨大的工程,您还是需要这么做的,但是,对于众多的中小型运算,您可能早已不胜其烦。令人欣喜的是,现在有了FORCAL.DLL,您可以在软件中自由地添加各种数值计算功能,享受到一劳永逸之乐趣。
FORCAL.DLL是基于FORCAL技术构建的,可以获得最优化的执行代码和最快的执行速度。在这里,我们可以把FORCAL.DLL和FORCAL看成一回事而不加以区分。
以下是有关FORCAL的详细说明。
导读:
1、认识FORCAL.DLL:介绍FORCAL的主要功能和用法,包括FORCAL动态库的输出函数说明。
2、FORCAL的二级函数[实数]:包括数据类型函数、逻辑函数、流程控制函数和一些常用数学函数等,极大地扩展了FORCAL的数值计算功能。FORCAL的复数和整数二级函数说明请阅读complexANDinteger.txt。
3、FORCAL中的字符数据处理。
4、实例程序及源代码[forcaltest.exe]:这是一个由FORCAL.DLL支持的数值计算程序,用于全面演示FORCAL的函数包括所有的二级函数以及自定义外部函数的用法。在该程序中,你可以看到如何向FORCAL添加可由FORCAL调用的外部函数。同时,该程序中的一个自定义外部函数speed()比较了FORCAL和VC的执行速度。
另一个更好的实例程序是开放式数值计算程序OpenFC,请从作者网站或者华军软件园http://www.onlinedown.net/等站点下载。
正文:
--------------------------------1--------------------------------------
一、认识FORCAL.DLL
FORCAL.DLL是一个通用的数学表达式编译计算动态库,基于FORCAL技术构建。
(一)、FORCAL表达式:
FORCAL可以编译计算的数学表达式格式如下:
格式1:F(x,y,x1,... ...)=1-x+sin[x1]-... ...
格式2:()=2+3*ln[3.45]
格式3:2+3*ln[3.45]
格式4:F(x,y)=2+sin[aa]+cos[aa-x]+bb,aa=3*ln[y-bb],bb=x+y+x*y
格式5:{F(x,y)=2+sin[aa]+cos[aa-x]+bb,aa=3*ln[y-bb],bb=x+y+x*y}
格式1:F 为函数名,可为任意字符,或者缺省;自变量放在小括号( )内,有多个自变量时,自变量间以逗号分隔,自变量为以小写英文字母开头的任意小写英文字母与数字的组合,自变量个数可以为零;等号后为函数式,不可缺省。
格式2和格式3是等效的,均表示无参函数。
格式4:数学表达式的可优化表示形式。aa、bb为符号定义名,其命名方式与自变量相同且不能与任何一个自变量同名。该格式的计算顺序为从右向左,即:先计算bb,然后计算aa,最后计算F(x,y)并把该值作为整个表达式的值。
格式5表示可以将表达式放在一对括号( )、[ ]或{ }内。
函数式中的运算符有加号'+'、减号'-'、乘号'*'、除号'/'和乘方'^'五种。注意数字与自变量相乘时,乘号不可省略;在进行乘方运算时,底数应为非负数。函数式中可以用三对括号( )、[ ]和{ }。
FORCAL表达式有实数表达式、复数表达式和整数表达式三种。表达式中的函数均分为一级函数和二级函数,其中一级函数为单变量函数,运算速度较快,而二级函数功能较为丰富,非常容易扩充。
实数表达式中可以使用的基本函数如下:
一级函数:平方根sq,指数函数exp,常用对数lg,自然对数ln,正弦sin,余弦cos,正切tg,反正弦as,反余弦ac,反正切at,双曲正弦sh,双曲余弦ch,双曲正切th,取整函数int,绝对值abs,重置自变量函数mov(用法见说明的第二部分)。
二级函数:请参见说明的第二部分。这些二级函数包括数据类型函数、逻辑函数、流程控制函数和一些常用数学函数等,极大地扩展了FORCAL的数值计算功能。
复数表达式中可以使用的基本函数如下:
一级函数:平方根sq,指数函数exp,自然对数ln,正弦sin,余弦cos,取整函数int,绝对值abs,共轭函数con,实部虚部交换函数xy,实部为0函数x0,虚部为0函数y0,重置自变量函数mov。
二级函数:请参见complexANDinteger.txt。
复数举例:2+3i。
复数表达式举例:F(x,y,... ...)=2+3i-sin[x-i]*ln[y]- ... ... 。
在复数表达式中不能使用 i 作为自变量,因为 i 已经用来表示虚数。
整数表达式中可以使用的基本函数如下:
一级函数:平方根sq,指数函数exp,常用对数lg,自然对数ln,绝对值abs,重置自变量函数mov。
二级函数:请参见complexANDinteger.txt。
注意:若整数表达式中有实数,在编译时将全部转化为整数,同时在进行乘方运算以及一级函数运算时,将把整数转化为双精度实数后进行运算,最后再把运算结果转化为整数。
另外,FORCAL编译器在编译表达式时能进行两种形式的代码优化,其一是预先计算表达式中可以计算的部分,其二是采用格式4表示的数学表达式的可优化形式。
FORCAL将最大限度地进行第一种代码优化,但这种自动进行的优化并不彻底,若要获得最优化的代码,您需要将表达式中可以计算的部分用括号括起来(一般情况下不需要这样做)。
例如:要想进行彻底的第一种代码优化,需要将式子:
F(x,y)=x-5-7+y
写成:F(x,y)=x-[5+7]+y或F(x,y)=x+[-5-7]+y
需要注意的是,在进行第一种代码优化时,只有一级函数(mov()函数除外)可以进行预先计算,二级函数的计算始终只能在编译后的表达式中进行。
FORCAL的第二种代码优化可以保证表达式中的任何相同部分只进行一次计算,从而最大限度地提高了计算速度。
(二)、FORCAL的速度:
FORCAL是由C/C++的编译程序生成的,所以它的速度要稍慢些,约为FORTRAN(或C/C++)的执行速度的50%左右。
(三)、FORCAL.DLL共享版与正式版的区别:
在共享版中FORCAL编译表达式的长度受到一定限制,除此之外,共享版与正式版没有任何区别。
(四)、FORCAL.DLL中的动态库函数说明:
(1)、版本信息函数:const char *ver(void) [序列号:1]。
(2)、表达式个数设置函数:bool setfornum(int m) [序列号:2]:
设置FORCAL.DLL可同时使用的表达式的个数为m个,设置成功函数返回true。可多次调用该函数。
注意:表达式从0开始编号,取值范围为0到m-1,编号为i的表达式称第i个表达式或者表达式i。
(3)、编译表达式:int rcom(int m,char a[],int &n) [序列号:3]:
编译第m个表达式a,返回的自变量个数为n个,当n=-1时表示有0个自变量,当n=0时表示有1个自变量,当n=1时表示有2个自变量,依次类推。
该函数返回值的意义如下:
0:表达式正确,编译通过;
1:不正确的运算方式;
2:无表达式;
3:自变量说明错,等号前有非法字符;
4:自变量应放在 ( ) 内;
5:非法自变量字符(以小写英文字母开头的小写英文字母与数字的组合);
6:自变量以小写英文字母开头;
7:自变量重复说明;
8:括号不成对;
9:在复数计算时,不能用 i 作为自变量(该返回值在编译复数表达式时使用);
10:不可识别函数名;
11:数学表达式太长,接近32766个字符;
12:不可识别自变量;
13:数字错误;
14:不可识别字符、函数名、自变量或者一级函数有多个自变量;
15:内存分配失败;
16:二级函数错误;
17:符号定义错误或无表达式或括号不成对;
18:表达式中的字符串无效,即"..."不匹配;
19:没有启用forcal的字符串处理功能;
20:表达式中的字符串太多或表达式太长;
21:内存分配失败;
22:找不到字符串$"..."所表示的表达式的类型;
23:找不到字符串#"..."所表示的表达式的序号;
24:找不到字符串&"..."的地址;
25:字符串数组不够用,需重新设置;
26:超出共享版允许的字符限制,请注册使用正式版。[在正式版中无此返回值]
(4)、计算表达式的值:double rcal(int m,double a[]) [序列号:4]:
计算第m个表达式的值,数组a中依次存放自变量。
(5)、释放动态库所申请的空间:void freedll(void) [序列号:5]。
该函数仅释放实数表达式所占用的空间。
(6)、动态库错误函数:int fcerr(char *&errname) [序列号:6]:
该函数在使用rcal或rcals函数后调用,返回动态库的第一个运行错误,fcerr返回错误类型,errname返回出错函数名,该函数被调用后,将把错误类型重新设置为0。
通常,可以在主程序中用int matherr(struct _exception *err)检测标准数学错误,用int fcerr(*&)检测FORCAL运行错误。
(7)、获得自变量数组指针函数:double *getin(int m) [序列号:7]:
该函数获得指向第m个表达式的自变量数组的指针,可用来输入自变量。
(8)、计算表达式的值:double rcals(int m) [序列号:8]:
计算第m个表达式的值,假定自变量已经通过自变量数组指针getin或getallin输入。该函数与getin或getallin配合使用,计算速度比rcal要快。
(9)、获得一维存储数组double的指针:double *getfcdoubles(long &n) [序列号:9]:
整数n返回该数组的大小。
(10)、获得多维存储数组doublearray的指针:double **getfcdoublearrays(long &n,long *&m) [序列号:10]:
整数n返回该数组的大小,m返回存放各维数组长度的整数组的指针。
(11)、设置可由FORCAL调用的外部函数:bool setfcfun(char **pch,int *n,double (**fun)(int k,double *dd)) [序列号:11]:
字符串表指针pch指出外部函数名(由英文字母a...z,A...Z、下划线_和数字0...9组成,但第一个字符不能为数字,同时不能用单个英文小写字母作外部函数名),串表的最后应是一个空名,表示该串表的结束;整数数组n的对应项存放每个函数的自变量个数,其中-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,依次类推;指向函数指针数组的指针fun指出每一个对应的函数,每个函数有两个相同的变量,其中dd为一个存放自变量的双精度数组,k为该数组的长度-1。
设置成功函数返回true,否则返回false。
例如:
char *pch[]={"asd","aa2a",""}; file://asd和aa2a为两个函数名;
int n[]={1,0}; file://1表示有2个自变量,0表示有1个自变量;
double (*fun[])(int ,double *)={asd,aa2a}; file://asd和aa2a为两个完成某种计算的函数;
利用该函数可以向FORCAL无缝地添加各种基本函数,FORCAL将把这些函数当作二级函数进行处理。在设计这些函数时,需要注意两个问题,一是要用setfcerr()向FORCAL报告运行错误,二是函数的参数中若使用表达式作自变量[例如:simpintegrate()],要注意避免无穷递归调用。
(12)、设置自定义外部函数的运行错误:void setfcerr(int n,char *ch) [序列号:12]:
整数n指出错误类型号,字符串指针ch指向出错函数名。该函数向FORCAL报告运行错误。
(13)、获得指向存放各表达式的自变量的指针数组的指针:double **getallin(void) [序列号:13]:
例如:double **aa=getallin();
则aa[3]为第3个表达式的自变量数组指针,可用来输入自变量。
(14)、获得动态库运行错误的类型:int fcerrnum(void) [序列号:14]:
该函数不改变错误类型的设置。
(15)、获得指向表示表达式是否编译成功的数组的指针:bool *getfortrue(void) [序列号:15]:
该数组记录了表达式的编译状态,当数组元素为true时,表示其对应的表达式编译通过。
(16)、获得指向存放各个表达式的自变量的个数的整数数组的指针:int *getvarnum(void) [序列号:16]:
该数组记录了各个表达式的自变量个数。
以下17~32函数使用_stdcall修饰符输出,可以在VB、delphi等高级语言中使用,用法参见1~16函数:
(17)、const char * _stdcall STDver(void); [序列号:17]
(18)、bool _stdcall STDsetfornum(int); [序列号:18]
(19)、void _stdcall STDfreedll(void); [序列号:19]
(20)、int _stdcall STDrcom(int ,char [],int &); [序列号:20]
(21)、double _stdcall STDrcal(int ,double []); [序列号:21]
(22)、double * _stdcall STDgetin(int ); [序列号:22]
(23)、double _stdcall STDrcals(int ); [序列号:23]
(24)、double * _stdcall STDgetfcdoubles(long &); [序列号:24]
(25)、double ** _stdcall STDgetfcdoublearrays(long &,long *&); [序列号:25]
(26)、bool _stdcall STDsetfcfun(char **,int *,double (**)(int ,double *)); [序列号:26]
(27)、double ** _stdcall STDgetallin(void); [序列号:27]
(28)、bool * _stdcall STDgetfortrue(void); [序列号:28]
(29)、int * _stdcall STDgetvarnum(void); [序列号:29]
(30)、int _stdcall STDfcerr(char *&); [序列号:30]
(31)、int _stdcall STDfcerrnum(void); [序列号:31]
(32)、void _stdcall STDsetfcerr(int ,char *); [序列号:32]
以下33~47和48~62函数将使您能使用复数表达式,用法请参见2~16和18~32函数:
(33)、bool Csetfornum(int); [序列号:33]
(34)、void Cfreedll(void); [序列号:34]
(35)、int Ccom(int ,char [],int &); [序列号:35]
(36)、_complex Ccal(int ,_complex []); [序列号:36]
(37)、_complex * Cgetin(int ); [序列号:37]
(38)、_complex Ccals(int ); [序列号:38]
(39)、_complex * Cgetfccomplexs(long &); [序列号:39]
(40)、_complex ** Cgetfccomplexarrays(long &,long *&); [序列号:40]
(41)、bool Csetfcfun(char **,int *,_complex (**)(int ,_complex *)); [序列号:41]
(42)、_complex ** Cgetallin(void); [序列号:42]
(43)、bool * Cgetfortrue(void); [序列号:43]
(44)、int * Cgetvarnum(void); [序列号:44]
(45)、int Cfcerr(char *&); [序列号:45]
(46)、int Cfcerrnum(void); [序列号:46]
(47)、void Csetfcerr(int ,char *); [序列号:47]
(48)、bool _stdcall STDCsetfornum(int); [序列号:48]
(49)、void _stdcall STDCfreedll(void); [序列号:49]
(50)、int _stdcall STDCcom(int ,char [],int &); [序列号:50]
(51)、_complex _stdcall STDCcal(int ,_complex []); [序列号:51]
(52)、_complex * _stdcall STDCgetin(int ); [序列号:52]
(53)、_complex _stdcall STDCcals(int ); [序列号:53]
(54)、_complex * _stdcall STDCgetfccomplexs(long &); [序列号:54]
(55)、_complex ** _stdcall STDCgetfccomplexarrays(long &,long *&); [序列号:55]
(56)、bool _stdcall STDCsetfcfun(char **,int *,_complex (**)(int ,_complex *)); [序列号:56]
(57)、_complex ** _stdcall STDCgetallin(void); [序列号:57]
(58)、bool * _stdcall STDCgetfortrue(void); [序列号:58]
(59)、int * _stdcall STDCgetvarnum(void); [序列号:59]
(60)、int _stdcall STDCfcerr(char *&); [序列号:60]
(61)、int _stdcall STDCfcerrnum(void); [序列号:61]
(62)、void _stdcall STDCsetfcerr(int ,char *); [序列号:62]
以下63~77和78~92函数将使您能使用整数表达式,用法请参见2~16和18~32函数:
(63)、bool Isetfornum(int); [序列号:63]
(64)、void Ifreedll(void); [序列号:64]
(65)、int Icom(int ,char [],int &); [序列号:65]
(66)、long Ical(int ,long []); [序列号:66]
(67)、long * Igetin(int ); [序列号:67]
(68)、long Icals(int ); [序列号:68]
(69)、long * Igetfclongs(long &); [序列号:69]
(70)、long ** Igetfclongarrays(long &,long *&); [序列号:70]
(71)、bool Isetfcfun(char **,int *,long (**)(int ,long *)); [序列号:71]
(72)、long ** Igetallin(void); [序列号:72]
(73)、bool * Igetfortrue(void); [序列号:73]
(74)、int * Igetvarnum(void); [序列号:74]
(75)、int Ifcerr(char *&); [序列号:75]
(76)、int Ifcerrnum(void); [序列号:76]
(77)、void Isetfcerr(int ,char *); [序列号:77]
(78)、bool _stdcall STDIsetfornum(int); [序列号:78]
(79)、void _stdcall STDIfreedll(void); [序列号:79]
(80)、int _stdcall STDIcom(int ,char [],int &); [序列号:80]
(81)、long _stdcall STDIcal(int ,long []); [序列号:81]
(82)、long * _stdcall STDIgetin(int ); [序列号:82]
(83)、long _stdcall STDIcals(int ); [序列号:83]
(84)、long * _stdcall STDIgetfclongs(long &); [序列号:84]
(85)、long ** _stdcall STDIgetfclongarrays(long &,long *&); [序列号:85]
(86)、bool _stdcall STDIsetfcfun(char **,int *,long (**)(int ,long *)); [序列号:86]
(87)、long ** _stdcall STDIgetallin(void); [序列号:87]
(88)、bool * _stdcall STDIgetfortrue(void); [序列号:88]
(89)、int * _stdcall STDIgetvarnum(void); [序列号:89]
(90)、int _stdcall STDIfcerr(char *&); [序列号:90]
(91)、int _stdcall STDIfcerrnum(void); [序列号:91]
(92)、void _stdcall STDIsetfcerr(int ,char *); [序列号:92]
(93)、使实数、复数和整数表达式可以相互调用:void userci(void); [序列号:93]
该函数在setfornum(int)、Csetfornum(int)和Isetfornum(int)后使用。
(94)、使实数、复数和整数表达式可以相互调用:void STDuserci(void); [序列号:94]
userci函数的_stdcall修饰符输出,用法同userci。
(95)、释放动态库所申请的全部空间:void deletedll(void); [序列号:95]
(96)、释放动态库所申请的全部空间:void STDdeletedll(void); [序列号:96]
deletedll函数的_stdcall修饰符输出,用法同deletedll。
(97)、设置forcal所用的字符串最大数目:bool setfcstrmax(long ); [序列号:97]
(98)、设置forcal所用的字符串最大数目:bool _stdcall STDsetfcstrmax(long ); [序列号:98]
(99)、获得forcal的字符串数组指针,同时获得存放每个子串长度的长整型数组指针:char **getfcstr(long *& ); [序列号:99]
(100)、获得forcal的字符串数组指针,同时获得存放每个子串长度的长整型数组指针:char ** _stdcall STDgetfcstr(long *& ); [序列号:100]
(101)、初始化字符串空间:void initfcstr(void); [序列号:101]
(102)、初始化字符串空间:void _stdcall STDinitfcstr(void); [序列号:102]
----------------------------------2------------------------------------
二、FORCAL的二级函数[实数部分]
说明:
在以下说明中,fcerr为动态库函数运行错误代码,int(m)表示取实数m的整数部分。
FORCAL可设置同时使用多个表达式,假如设置了n个表达式,则表达式的序号分别为0、1、2、...、 i、 ...、n-1,第i个表达式简称为表达式i。
部分函数的举例请参见本文第四部分:实例程序及源代码[forcaltest.exe]。
0、一个特殊的一级函数 mov(x):
mov(x)函数将x值传送至最近使用的一个自变量,因此对该自变量进行了重新赋值。注意该函数实际上有两个参数,源参数为x,但目的参数即“最近使用的一个自变量”却是隐含的。“最近使用的一个自变量”即按照表达式的计算顺序,在mov函数执行之前最后使用的自变量。详见下面的例子:
例1:(x)=x+mov[5]+x 当x为2时表达式的值为12而不是9。
例2:(x)=x+mov[x+5]+x 当x为2时表达式的值为16。
例3:(a,b,c)=one(a,mov[5],b,mov[8],mov[a+b+(c-c)],mov[a+b]) 不论计算开始时a,b,c为何值,计算结束时a为5,b为13,c为13,可以用para(n,m)函数(详见para的介绍)获取这些自变量参数。
可以看出mov函数的重要用途是可以把表达式的自变量当作真正的变量来使用。
1、数据类型函数:
1.1、设置多个双精度实数 newdoubles(m):
该函数设置int(m)个双精度实数,若int(m)<1,则删除这些双精度实数,该函数总是返回0。
这些双精度实数从0开始编号,即:0,1,2,3,... ...,m-1。
若fcerr=1,设置失败。
以下这些函数可以对这些双精度实数进行各种运算操作。
1.1.1、对一个双精度实数进行赋值 setd(n,x):
将第int(n)个双精度实数的值设为x,该函数返回x的值。
若fcerr=1,表示不存在第int(n)个双精度实数。
1.1.2、获得一个双精度实数的值 getd(n):
获得第int(n)个双精度实数的值。
若fcerr=1,表示不存在第int(n)个双精度实数。
1.1.3、将一个数加到一个双精度实数上并返回相加后的值 addgetd(n,x):
先将x加到第int(n)个双精度实数上,然后返回相加后的值。
若fcerr=1,表示不存在第int(n)个双精度实数。
1.1.4、获得一个双精度实数的值后再将另一个数加到该双精度实数上 getdadd(n,x):
该函数先返回第int(n)个双精度实数的值,然后将x加到第int(n)个双精度实数上。
若fcerr=1,表示不存在第int(n)个双精度实数。
1.2、设置多个一维双精度实数数组 newdoublearrays(m):
该函数设置int(m)个一维双精度实数数组,若int(m)<1,则删除这些双精度实数数组,该函数总是返回0。
这些双精度实数数组从0开始编号,即:0,1,2,3,... ...,m-1。
若fcerr=1,设置失败。
以下这些函数可以对这些双精度实数数组或数组元素进行各种运算操作。
1.2.1、设置一维双精度实数数组的长度 newdoublearray(n,m,x1,x2,... ...):
将第int(n)个数组长度设为int(m),可以存储int(m)个数组元素,若int(m)<1,则删除该数组,该函数总是返回0。
这些数组的元素从0开始编号,即:0,1,2,3,... ...,m-1。
设置成功将x1,x2,... ...存储到该数组。
若fcerr=1:参数个数不能少于两个;fcerr=2:未设置多个一维双精度实数数组;fcerr=3:不存在第int(n)个双精度数组;fcerr=4:数组设置失败;fcerr=5:x1,x2,... ...的个数大于m。
1.2.2、对一个数组元素进行赋值 setda(n,m,x):
该函数将x值存储到第int(n)个数组的第int[m]个元素位置并返回x的值。
若fcerr=1:未设置多个一维双精度实数数组;fcerr=2:不存在第int(n)个双精度数组;fcerr=3:未对该数组进行设置或不存在第int(m)个数组元素。
1.2.3、获得一个数组元素的值 getda(n,m):
该函数获得第int(n)个数组的第int[m]个数组元素的值。
若fcerr=1:未设置多个一维双精度实数数组;fcerr=2:不存在第int(n)个双精度数组;fcerr=3:未对该数组进行设置或不存在第int(m)个数组元素。
1.2.4、将一个数加到一个数组元素上并返回相加后的值 addgetda(n,m,x):
先将x加到第int(n)个数组的第int[m]个数组元素上,然后返回相加后的值。
若fcerr=1:未设置多个一维双精度实数数组;fcerr=2:不存在第int(n)个双精度数组;fcerr=3:未对该数组进行设置或不存在第int(m)个数组元素。
2、逻辑函数:
FORCAL用大于0的数表示逻辑真,小于等于0的数表示逻辑假。
2.1、gt(x,y):如果x>y返回1,否则返回-1。
2.2、ge(x,y):如果x>=y返回1,否则返回-1。
2.3、lt(x,y):如果x<y返回1,否则返回-1。
2.4、le(x,y):如果x<=y返回1,否则返回-1。
2.5、eq(x,y):如果x==y返回1,否则返回-1。
2.6、ne(x,y):如果x!=y返回1,否则返回-1。
2.7、and(x,y):如果x>0同时y>0返回1,否则返回-1。
2.8、or(x,y):如果x<0同时y<0返回-1,否则返回1。
2.9、not(x):如果x>0返回-1,否则返回1。
2.10、xor(x,y):如果x和y符号相同返回-1,否则返回1。
3、表达式相互调用及流程控制函数:
3.1、for循环函数 for(x,y1,y2,...,break(),...,continue(), ...,z):
自变量x为逻辑表达式,y1,y2,...,break(),...,continue(), ...为执行语句,z为增量语句。当x的值为真时,依次执行这些表达式,直到x的值为假时退出循环。当执行到break()函数时,跳出for循环,执行for循环后面的函数;当执行到continue()函数时,返回到for循环的开始语句x处继续执行。
for(x,y1,y2,...,break(),...,continue(), ...,z)即for(判断语句x,多个执行语句y1,y2,...,break(),...,continue(), ...,增量语句z)。
该函数至少要有2个自变量参数,其中第一个参数为逻辑表达式。
该函数总是返回0值。
若fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用,或者嵌套太深;fcerr=1:循环次数超出限制。
该函数中continue()的使用会导致fcerr=1:循环次数超出限制。
3.2、dowhile循环函数 dowhile(x1,x2,...,break(),...,continue(),...,y):
dowhile为先执行后判断的循环函数。即先执行多个表达式x1,x2,...,break(),...,continue(),...,然后计算逻辑表达式y的值,直到y的值为假时退出循环。当执行到break()函数时,跳出dowhile循环,执行dowhile循环后面的函数;当执行到continue()函数时,返回到dowhile循环的开始语句x1处继续执行。
dowhile(x1,x2,...,break(),...,continue(),...,y)即dowhile(多个执行语句x1,x2,...,break(),...,continue(),...,判断语句y)。
该函数至少要有2个自变量参数,其中最后一个参数为逻辑表达式。
该函数总是返回0值。
若fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用,或者嵌套太深;fcerr=1:循环次数超出限制。
该函数中continue()的使用会导致fcerr=1:循环次数超出限制。
3.3、判断函数 if(x,y1,y2,... ...,yn):
当逻辑值x为真时,依次执行表达式y1,y2,... ...,yn,否则,不执行表达式y1,y2,... ...,yn。
该函数至少要有2个自变量参数,其中第一个参数为逻辑表达式。
该函数总是返回0值。
3.4、自定义分段函数 which(逻辑值1,表达式1,逻辑值2,表达式2,... ...,逻辑值n,表达式n,缺省表达式):
FORCAL从前往后检测逻辑值,当检测到逻辑真时,计算与此逻辑真对应的表达式并返回该表达式的值,如果没有检测到逻辑真,则计算缺省表达式的值作为返回值,若此时没有缺省表达式,则产生一个运行错误。
例如下式定义了一个分段函数:(x)=which[gt(x,0),2*x-1,x*x-1]。
若fcerr=1:没有参数或找不到返回值。
如果舍弃该函数的返回值,则该函数可以作为一个选择计算函数使用。
3.5、计算指定序号的表达式的值 calfor(n,x1,x2,... ...):
int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。
3.6、获取表达式的自变量参数的值 para(n,m):
int(n)指出该表达式的序号,int(m)指出自变量参数的序号。
若fcerr=-1:未对可接受表达式的二级函数进行设置,fcerr=1:指定的表达式不存在,fcerr=2:表达式未进行编译,fcerr=3:指定的自变量参数不存在。
3.7、计算指定序号的复数表达式的值 calcfor(n,x1,y1,x2,y2,... ...):
int(n)指出该表达式的序号,x1,y1,x2,y2,... ...为该表达式的参数,其中xi为复数的实部,yi为复数的虚部。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。
3.8、计算指定序号的整数表达式的值 califor(n,x1,x2,... ...):
int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。
3.9、合并表达式函数one(x1,x2,... ...,xn):
该函数可将多个无参表达式合并为一个表达式,以减少表达式个数,节约内存,并可提高执行速度。
该函数总是返回0值。
3.10、return返回函数 return(x):
结束计算并返回表达式的值为x。
3.11、执行过程函数 call(n):
int(n)指出该表达式的序号,如果该表达式有参数,则按缺省值进行计算。
执行过程通常是指不需要传递一个表达式的参数而执行这个表达式,但一般该表达式的自变量返回值有意义,可以用para(n,m)获取该表达式的自变量参数值。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译。
该函数总是返回0值。
4、其他常用函数:
4.1、反正切函数 at2(x,y):
求x/y的正切值,所在象限由x和y的符号确定。
4.2、最大值函数 max(x1,x2,x3,... ...):
若fcerr=1:没有参数。
4.3、最小值函数min(x1,x2,x3,... ...):
若fcerr=1:没有参数。
4.4、余数函数 fmod(x,y):
求x/y的余数。
4.5、取小数部分函数 modf(x):
该函数把x分解成整数和小数部分,并返回小数部分。
4.6、符号传送函数 sign(x,y):
该函数的符号取y的符号,数值取x的绝对值,若y=0无符号传送,返回x值。
4.7、正差函数 dim(x,y):
当x>y时得x-y,否则返回0。
4.8、数值测试函数 testdouble(x,y,z):
该函数测试z是否在x和y之间,如果不在x和y之间,可由fcerr()函数检查到这个错误,该函数总是返回z值。
若fcerr=1:z值超出范围。
4.9、随机数发生器种子设置 srand(x):
该函数用来建立由rand()所产生的序列值的启始点,该函数总是返回0。
4.10、随机数 rand():
该函数产生一个随机数,每调用一次,就返回一个0到RAND_MAX之间的整数,RAND_MAX的值由C++定义。
4.11、变步长辛卜生一元积分 simpintegrate(a,b,eps,n,x2,x3,... ...):
a为积分下限,b为积分上限,eps为积分精度要求,int(n)指出被积函数所在的表达式序号,x2,x3,... ...表示可以向被积函数传递多个参数。
例1:
将下式编译为2号表达式:(x)=sin[x]+0.8
编译并计算2号表达式:(a,b,eps,x)=x-simpintegrate(a,b,eps,2)+... ...
该例子中没有多余的参数传递。
例2:
将下式编译为3号表达式:(x,y,z)=x+y-z
编译并计算3号表达式:(a,b,eps,x1,x2)=x1-simpintegrate(a,b,eps,3,x1,x2)+... ...
该例子中x1和x2将被传递给3号表达式的y和z。
注意:被积函数的第一个参数为积分变量,x2,x3,... ...与被积函数的其余参数要匹配;
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配;fcerr=4:循环次数超出限制。
4.12、获取流逝过去的时钟脉冲次数 clock()。
4.13、求和函数 sum(n,m,x1,x2,... ...,xm,y1min,y1max,y1dy,y2min,y2max,y2dy... ...):
int(n)指出求和函数所在的表达式序号,m指出向求和函数传递的参数个数为x1,x2,... ...,xm;y1min,y1max,y1dy为第一个自变量的初值、终值和参数增量[初值<终值,参数增量>0],依次类推。
例1:
将下式编译为2号表达式:(x,y)=sin[x]+0.8-y
编译并计算2号表达式:(a,b,dx)=2-sum(2,0,a,b,dx,2,5,0.1)+... ...
该例子中没有多余的参数传递。
例2:
将下式编译为3号表达式:(x,y,z)=x+y-z
编译并计算3号表达式:(a,b,dx)=2-sum(3,1,7,a,b,dx,2,5,0.1)+... ...
该例子中sum将7传递给3号表达式的参数z。
fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配;fcerr=4:常量表达式,无法求和;fcerr=5:内存分配失败;fcerr=6:自变量参数非法。
4.14、求积函数 pro(n,m,x1,x2,... ...,xm,y1min,y1max,y1dy,y2min,y2max,y2dy... ...):
用法请参见sum(),用于求积。
fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配;fcerr=4:常量表达式,无法求积;fcerr=5:内存分配失败;fcerr=6:自变量参数非法。
4.15、数据求和函数 datasum(n,m,x1,x2,... ...,xm,y11,y12,... ...,y21,y22,... ...):
int(n)指出求和函数所在的表达式序号,m指出向求和函数传递的参数个数为x1,x2,... ...,xm;y11,y12,... ...为第一组自变量数据,依次类推。
例1:
将下式编译为2号表达式:(x,y)=x+y
编译并计算2号表达式:datasum[2,0,1,2,3,4,5,1,2,3,4,5]
datasum计算结果为30,该例子中没有多余的参数传递。
例2:
将下式编译为2号表达式:(x,y,z)=x+y+z
编译并计算2号表达式:datasum[2,1,10,1,2,3,4,5,1,2,3,4,5]
datasum计算结果为80,该例子中datasum将10传递给2号表达式的参数z。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配;fcerr=4:常量表达式,无法求和。
4.16、数据求积函数 datapro(n,m,x1,x2,... ...,xm,y11,y12,... ...,y21,y22,... ...):
用法请参见datasum(),用于数据求积。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配;fcerr=4:常量表达式,无法求积。
4.17、设定函数递归调用的最大次数 setstackmax(n):
int(n)是1到32766之间的一个整数,函数递归调用最大次数的缺省值为16,该函数返回0。
若fcerr=1:设置错误,int(n)为非法数据。
4.18、设定某些函数内循环的最大次数 setcyclemax(n):
int(n)是2到2147483647之间的一个整数,函数内循环的最大次数的缺省值为1000000,该函数返回0,for、dowhile和simpintegrate函数将受到该参数的影响。
若fcerr=1:设置错误,int(n)为非法数据;fcerr=2:内存分配错误。
4.19、数组数据求和函数 dataarraysum(n,m,x1,x2,... ...,xm,nn,n1,n2,... ...):
该函数以数组中的数据为自变量,对某个表达式进行累计求和。int(n)指出求和函数所在的表达式序号,m指出可以向求和函数传递m个参数,即x1,x2,... ...,xm。nn指出有nn组数据,n1,n2,... ...为与自变量相对应的多个数组。
若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配;fcerr=4:常量表达式,无法求和;fcerr=5:数据组数int(nn)应大于0;fcerr=6:数组n1,n2,... ...中的某个数组长度小于nn。
4.20、数值测试函数 finite(x):
测试x的值是否是有限的。
若fcerr=1:x的值是无限的或为非数值数据。
----------------------------------3------------------------------------
三、FORCAL中的字符数据处理
FORCAL在编译表达式时,将表达式中的字符串用一个整数代替,这个整数即该字符串的地址,使用字符串的二级函数可以根据这个地址存取这些字符串。用法请参考forcaltest.cpp中的printstr( )函数。
在编译时,对于以下几种字符串形式,FORCAL将作如下处理:
"...":为该字符串开辟存储空间,并在表达式中用一个整数即该空间的地址代替该字符串;
&"...":不为该字符串开辟存储空间,仅仅取存储空间中相同字符串的地址,如果存储空间中没有相同字符串,则返回一个出错信息,出错码为24;
$"...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的表达式中的第一个字符串,如果找到这个表达式,则取该表达式的类型(1为整型、2为实型、3为复型),否则返回一个出错信息,出错码为22。
#"...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的相同类型的表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
#"#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的表达式(可为任何类型)中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
#"i#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的整数表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
#"r#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的实数表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
#"c#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的复数表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
具体使用请参考以下例子。
----------------------------------4------------------------------------
四、实例程序及源代码[forcaltest.exe]
(一)、使用说明:
1、该程序使用简单,请参考程序运行时的说明。
2、建议先在文本编辑器例如记事本中输入数学表达式及自变量,然后将表达式及自变量复制粘贴到forcaltest.exe中,这样改写表达式较为方便。请将以下几行表达式及自变量数据逐行复制粘贴或全部复制粘贴到forcaltest.exe中,观察程序运行情况:
"F1"(x,y)=x+y ? !! 下一行为该表达式的两个自变量;
2 3
"F2"(x)=2*x ? !! 下一行为该表达式的自变量;
3
simpintegrate[0,5,0.00001,#"F2"] ? !! 对F2表达式进行积分;
(二)、计算实例:
1、FORCAL与VC的速度比较:在非0号表达式中使用自定义外部函数speed[]即可进行比较。
2、一个字符串函数的例子:
"aa ""*"" bb"(i,j)=one
{i,mov[20],
for{i,
printstr[&"aa "],
j,mov[0],
for{i-j,
printstr[&"*"],
mov[j+1]
},
printstr[&" bb"],
end[],
mov[i-1]
}
} ?
0 0
3、mov函数用法及速度:
"ff"(x,y,z)=-clock()+one(x,mov[0],z,mov[0])+
for{le{x,1000}, !! 外for循环的逻辑表达式;
y,mov[0],
for{le{y,1000}, !! 内for循环的逻辑表达式;
mov[sin(x)+cos(x-y)+z], !! 内for循环的执行语句;
mov[y+1] !! 内for循环的增量语句;
},
mov[x+1] !! 外for循环的增量语句;
}
+clock() ? !! 计算结果为运行时间[此语句要单独复制粘贴执行,否则运行时间不准确];
para[#"ff",2] ? !!获得以上表达式中的z值,假定该表达式为0号表达式;
4、for循环的用法及速度:
one{newdoubles(10), !!用newdoubles申请10个双精度数;
setd[0,0]+setd[2,0] !! 将双精度数0设为0,双精度数2设为0;
} ?
-clock()+ !!获得现在的时间;
for{le{getd[0],1000}, !! 外for循环的逻辑表达式;
setd[1,0],
for{le{getd[1],1000}, !! 内for循环的逻辑表达式;
addgetd[2,sin(getd[0])+cos(getd[0]-getd[1])], !! 内for循环的执行语句;
addgetd[1,1] !! 内for循环的增量语句;
},
addgetd[0,1] !! 外for循环的增量语句;
}
+clock() ? !! 计算结果为运行时间[此语句要单独复制粘贴执行,否则运行时间不准确];
getd[2] ? !!获得双精度数2终值;
5、dowhile循环的用法及速度:
newdoubles(10) ? !!用newdoubles申请10个双精度数;
setd[0,1001]+setd[2,0] ?
-clock()+
dowhile{setd[1,1001],
dowhile{addgetd[2,sin(getd[0]-1)+cos(getd[0]-getd[1])],
addgetd[1,-1]
},
addgetd[0,-1]
}
+clock() ? !! 计算结果为运行时间[此语句要单独复制粘贴执行,否则运行时间不准确];
getd[2] ? !!获得双精度数2终值;
6、求和函数sum的用法:
"F3"(x,y)=cos{1-sin[1.2*[x+0.1]^(y/2-x)+cos{1-sin[1.2*[x+0.2]^(y/3-x)]}]-cos{1-sin[1.2*[x+0.3]^(y/4-x)]}-cos{1-sin[1.2*[x+0.4]^(y/5-x)+cos{1-sin[1.2*[x+0.5]^(y/6-x)]}]-cos{1-sin[1.2*[x+0.6]^(y/7-x)]}}} ?
1 2
sum[#"F3",0;0,1,0.0011;1,2,0.0011] ?
7、数据求和函数datasum的用法:
"F4"(x,y)=x*y ?!! 求和公式;
1 2
datasum[#"F4",0,1,2,3,4,5,6,7,8,9,10] ?
说明:对于式子F(x,y)=x*y,求x,y分别取1,2、3,4、5,6、7,8、9,10时的值的和。即求F[1,2]+F[3,4]+F[5,6]+F[7,8]+F[9,10]的值。
8、实数、复数、整数表达式混合运算实例:
"F5"(x,y)=x+y ? ! F5为实数表达式;
1 2
c"F6"(x1,x2,x3)=x1+x2+x3+7.7-8.8i ? ! F6为复数表达式;
1 2 3 4 5 6
i"F7"(x,y)=x+y ? ! F7为整数表达式;
1 2
1+calcfor[#"#F6",1,2,3,4,5,6]+califor[#"#F7",1,2] ? ! 在实数表达式中使用复数表达式和整数表达式;
calrfor[#"#F5",1,2]+califor[#"#F7",1,2]*i ? ! 在复数表达式中使用实数表达式和整数表达式;
i()=1+calcfor[#"c#F6",1,2,3,4,5,6]+calrfor[#"r#F5",1,2] ? ! 在整数表达式中使用复数表达式和实数表达式;
9、break()和continue()函数的用法:
newdoubles(10) ? !!用newdoubles申请10个双精度数;
setd[0,0]+setd[1,0]+setd[2,999]?
dowhile{if [ge[getd(0),100], break()],
dowhile{addgetd[1,1],
which {le[getd(1),200], continue(), break()},
setd[2,888]
},
addgetd[0,1]
}?
getd[0] ? !!获得双精度数0终值:100;
getd[1] ? !!获得双精度数1终值:300;
getd[2] ? !!获得双精度数2终值:999。
10、试试这个函数,该函数将给出所有目前正在使用的字符串:fcstr[]。
(三)、源代码:请参见 forcaltest.cpp。
=================================================================
本软件下载请到作者主页或者在csdn下载:http://www.csdn.net/cnshare/soft/11/11030.shtm
作者主页:http://forcal.yeah.net/ 或 http://wangluwanglu.yeah.net/
E-mail:wanglu@shareware.com.cn 或 wanglu71641@sina.com 或 wangluwanglu@163.com
山东省工业学校工艺教研室(255070) 王 禄
2002.2-2003.10