FORCAL.DLL V7.0 用户指南
|
1 简单的例子 2 FORCAL标识符 3 表达式和数据 4 常量和变量 5 赋值语句 6 算术运算符 7 关系运算符和逻辑运算符 8 逗号运算符和括号运算符 9 运算符及优先级 10 函数概述 11 函数的传值调用和传址调用 12 用表达式作为函数的参数 13 FORCAL表达式的完整定义 14 流程控制 15 字符数据处理 |
16 关于数组 17 关于递归调用 18 关于模块化编译 19 二级函数 20 效率 21 主要技术指标 |
正文:
F(x,y)=x+y;
//函数定义;
2+F[2,3]+5;
//简单的计算式;
在这个例子中,分号表示一个表达式的结束,两个反斜杠//后的内容表示注释,本文中将一直采用这种表示和注释方法。
在第一个表达式中定义了一个函数 F ,小括号( )内的x,y为函数的自变量,等号后为函数体,即可执行的部分,该函数计算并返回两个参数的和。在第二个表达式中调用了上面定义的函数
F 。
需要注意,在测试程序ForcalTest中,只计算无自变量的表达式。因此,对第一个表达式只编译,不计算。
在FORCAL中,一个标识符可以用来表示一个表达式的名字,或者是一个函数的名字,或者是一个变量,或者是一个符号常量。标识符可由一个或多个字符组成,可以任意一个英文字母或者下划线开头,后面可以接英文字母、数字或者下划线(下划线的使用可以增加标识符的可读性,如first_name)。在FORCAL中,大写与小写是相同的,count和COUNT是两个相同的名字。下面给出一些合法的标识符:
first last Addr1 top _of_file name23 _temp a23e3 MyVar
表达式是FORCAL的编译单元,如果没有语法错误,编译后将生成可执行的代码。FORCAL表达式可以很简单,例如只有一个数字;FORCAL表达式也可以很复杂,例如是一段复杂的程序。
以下是一些简单的表达式的例子:
2;
2+3;
2+sin(3)-ln[6];
可以给表达式起一个名字,这样做的好处是:以后可以用函数调用的方式通过该名字调用该表达式。表达式的名字是一个标识符,必须位于表达式的开头。例如,上面三个表达式可按如下方式定义:
A()=2;
B()=2+3;
C()=2+sin(3)-ln[6];
表达式定义的一般形式是:
Name(a,b)={a=a+2,b=10,a+b}
其中 Name 为表达式的名字,不可与其它已经定义的表达式名字相同,但可以缺省;如果定义了表达式名字,表达式名字后必须跟一对小括号(只能用小括号),用来定义自变量,自变量个数可以为零,也可以有任意多个,有多个自变量时,自变量间以逗号分隔;如果用小括号定义了自变量,小括号后必须跟一个等号,该等号标志表达式可执行部分的开始,等号及等号后的可执行部分均不可缺省。表达式的可执行部分由多个语句组成,多个语句之间用逗号分隔,表达式总是返回最后一个语句的值;另外花括号不是必须的,但有了花括号后,表达式更易读。
用这种方式定义表达式时,实际上就是自定义了一个函数,可以在任意的表达式中使用该函数(只要给该函数起了名字),由于这个原因,我们常常将表达式说成是函数,或者说表达式就是一个函数,但反过来并不成立。
下面是一个函数定义及使用的例子。
F(x,y)=x+y; //函数定义;
2+F[2,3]+5;
//函数调用;
以下是一些合法的表达式例子:
2;
//常量(无参)表达式(函数);
()=2;
//常量(无参)表达式(函数);
A()=2;
//常量(无参)表达式(函数),但定义了函数名字,在其它表达式中可以调用该函数;
B(x)=2; //有一个自变量的表达式(函数);
C(x,y)=x+y; //有二个自变量的表达式(函数);
下面说一下表达式的类型和数据的类型,FORCAL表达式有三种类型:整数表达式、实数表达式和复数表达式;相应地,FORCAL中有三种基本的数据类型:整数、实数和复数。例如:
i:2+3; //整数表达式,在测试程序ForcalTest中,整数表达式以i:开头;
2.2+3;
//实数表达式,在测试程序ForcalTest中,缺省是实数表达式;
c:2+3i;
//复数表达式,在测试程序ForcalTest中,复数表达式以c:开头;
FORCAL编译器在编译表达式时,将整数表达式中的数据都转换成整数,如果是有小数部分将截断取整;将实数表达式中的数据都转换成实数;将复数表达式中的数据都转换成复数,如果数字后有i,表示一个虚数。
在FORCAL中,小数的表示非常灵活,小数点前面的零或后面的零可省,例如:5.6、5.、.6都是合法的数据表示。在FORCAL中,还可以使用科学记数法表示数字,例如:10.3E8、2E-10等,其中用E表示以10为底的指数部分,但指数不能为小数,例如:3E5.6、8.6E-6.7不合法。
常量是指那些不需要程序计算的固定值。有数值常量和符号常量两种。如100就是一个数值常量。在FORCAL中,也可以用标识符表示一个符号常量,但符号常量的定义与具体的软件有关,在这里无法给出具体的例子。
变量是指在程序运行时,其值可以改变的量。FORCAL有五种变量,即:自变量、动态变量、静态变量、模块变量和全局变量。自变量、动态变量和静态变量只能被定义该变量的表达式所访问;模块变量可被同一模块的所有表达式所访问,其他模块的表达式无法访问;全局变量可被所有的表达式所访问。自变量用于向表达式传递参数 ,因此自变量也称为形式参数。动态变量只在表达式执行时起作用,一旦表达式执行完毕,动态变量也随之失效。静态变量存在于表达式的整个生命周期,每次表达式执行完毕,静态变量的值被保留。FORCAL在编译表达式时,将所有静态变量初始化为0,其余的变量均不进行初始化。在FORCAL表达式中,变量要先定义后使用,变量在表达式的开头进行定义,格式如下:
F(a,b:x,y,static,u:s,t,common,v)=
{x=1,y=2,
a+b+x+y+static+u+s+t+common+v
}
F是表达式的名字,a和b是自变量,x和y是动态变量,static和u是静态变量,s和t是模块变量,common和v是全局变量。自变量、动态变量和静态变量以及模块变量和全局变量之间用冒号分隔 ,即第一个冒号前为自变量,两个冒号之间为动态变量和静态变量,第二个冒号后为模块变量和全局变量。两个冒号之间用关键字static分隔动态变量和静态变量,static之前为动态变量,static及以后变量均为静态变量,关键字static只 能用在两个冒号之间。第二个冒号后用关键字common分隔模块变量和全局变量,common之前为模块变量,common及以后变量均为全局变量,关键字common只能用在第二个冒号后。FORCAL中的所有变量均可缺省。以下都是合法的变量定义的例子:
F()= ...
... //没有使用任何变量,称无参表达式;
F(::)= ...
... //没有使用任何变量,称无参表达式;
F(a,b)= ...
... //定义了两个自变量a和b;
F(:x,y)= ...
... //定义了两个动态变量x和y;
F(:static,u)= ...
... //定义了两个静态变量static和u;
F(::s,t)= ...
... //定义了两个模块变量s和t;
F(::common,v)= ...
...//定义了两个全局变量common和v;
F(a,b:x,y)= ...
... //定义了两个自变量a和b,两个动态变量x和y;
F(a,b::s,t)= ... ... //定义了两个自变量a和b,两个模块变量s和t;
F(:x,y:s,t)= ... ... //定义了两个动态变量x和y,两个模块变量s和t;
变量的使用见下面的例子:
F(a,b:x,y,static,u:s,t,common,v)={a=1,b=2,x=3,y=4,static=5,u=6,s=7,t=8,common=9,v=10};//函数定义及变量赋值;
A(a,b:x,y,static,u:s,t,common,v)=a;//函数定义;
B(a,b:x,y,static,u:s,t,common,v)=b;//函数定义;
X(a,b:x,y,static,u:s,t,common,v)=x;//函数定义;
Y(a,b:x,y,static,u:s,t,common,v)=y;//函数定义;
_S(a,b:x,y,static,u:s,t,common,v)=static;//函数定义;
U(a,b:x,y,static,u:s,t,common,v)=u;//函数定义;
S(a,b:x,y,static,u:s,t,common,v)=s;//函数定义;
T(a,b:x,y,static,u:s,t,common,v)=t;//函数定义;
_C(a,b:x,y,static,u:s,t,common,v)=common;//函数定义;
V(a,b:x,y,static,u:s,t,common,v)=v;//函数定义;
F(11,22);//函数调用,进行变量赋值
,返回值=10;
A(11,22);//函数调用,返回值=11;
B(11,22);//函数调用,返回值=22;
X(11,22);//函数调用,返回值=随机数值;
Y(11,22);//函数调用,返回值=随机数值;
_S(11,22);//函数调用,返回值=0;
U(11,22);//函数调用,返回值=0;
S(11,22);//函数调用,返回值=7;
T(11,22);//函数调用,返回值=8;
_C(11,22);//函数调用,返回值=9;
V(11,22);//函数调用,返回值=10;
赋值语句的作用是将一个值赋给一个变量。在FORCAL中,可以用等号对变量进行赋值。例如:
F(x)= x=5; //函数定义,将数值5赋给变量x;
F[2]; //函数调用,返回值为5;
上面进行变量赋值的例子很简单,但等号后部分可以是任意复杂的表达式。
FORCAL中共有七个算术运算符,即:+(加或正)、-(减或负)、*(乘)、/(除)、^(乘方)、++(自增)、--(自减)。
运算符*、/和^是双目运算符。注意数字与变量相乘时,乘号不可省略;在进行乘方运算时,底数应为非负数;在整数表达式中进行乘方运算时,将把整数转化为双精度实数后进行运算,最后再把运算结果转化为整数。
运算符+、-作加、减运算时,是二元运算符,当作正、负运算时,是单目运算符。
运算符++、--是单目运算符,仅能对变量使用。++使变量的值加1,如果++在变量之前,那么运算符在程序语句访问该值之前执行加法运算,这时的++运算符称为“前置自增运算符”;如果把该运算符放在变量之后,那么运算符在程序语句访问该值之后执行加法运算,这时的++运算符被称为“后置自增运算符”。--使变量的值减1,如果--在变量之前,那么运算符在程序语句访问该值之前执行减法运算,这时的--运算符称为“前置自减运算符”;如果把该运算符放在变量之后,那么运算符在程序语句访问该值之后执行减法运算,这时的--运算符被称为“后置自减运算符”。例如:
(:x)=
x=2,++x; //返回值为3;
(:x)= x=2,++x,x;
//返回值为3;
(:x)= x=2,x++;
//返回值为2;
(:x)= x=2,x++,x;
//返回值为3;
(:x)= x=2,--x; //返回值为1;
(:x)= x=2,--x,x;
//返回值为1;
(:x)= x=2,x--; //返回值为2;
(:x)= x=2,x--,x; //返回值为1;
如果在复数表达式中使用自增减运算符,则仅对复数的实部作运算,复数的虚部保持不变。例如:
c:(:x)= x=2+3i,++x;
//返回值为3+3i;
c:(:x)= x=2+3i,--x;
//返回值为1+3i;
单目运算符的优先级比双目运算符的优先级高,后置单目运算符的优先级比前置单目运算符的优先级高。对于同一优先级的运算,按从左到右的优先顺序进行。
注意:单目运算符-(负)的优先级高于双目运算符^(乘方)的优先级。例如:
-2^2;
//返回值为4;
-(2^2);
//返回值为-4;
算术运算符的优先级如表6-1所示。在表中,同一行中运算符优先级相同,不同行中运算符的优先级从上往下依次降低。
表6-1:算术运算符及优先级
|
运 算 符 |
说 明 |
| ++、-- | 后置单目运算符,自增减运算符 |
| +、-、++、-- | 前置单目运算符,“++、--”为自增减运算符 |
| ^ | 乘方 |
| *、/ | 乘、除 |
| +、- | 加、减 |
7 关系运算符和逻辑运算符 [返回页首] [返回目录]
关系运算是对两个值的大小进行比较,返回一个逻辑值。逻辑值只有两个:逻辑真和逻辑假。在FORCAL中用0表示逻辑假,其他任何非0值表示逻辑真。例如:
3>2;
//返回逻辑真;
2>3; //返回逻辑假;
关系运算符共有6个:>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、==(等于)、!=(不等于)。
逻辑值之间的运算称逻辑运算,逻辑运算的结果仍然是一个逻辑值。有三个逻辑运算符:&(逻辑与)、|(逻辑或)、!(逻辑非)。通过表7-1给出的真值表可以掌握这三种运算。表中用1代表逻辑真,0代表逻辑假。
表7-1 真值表
| p | q | p&q | p|q | !p |
| 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 0 |
在FORCAL中,仅使用复数的实部表示逻辑值,逻辑值的虚部没有任何意义。所以,如果在复数表达式中使用关系运算符或逻辑运算符,则仅取复数的实部作运算,复数的虚部对运算结果没有任何影响;在运算结果中,仅复数的实部有意义,虚部没有意义,但其值为参与运算的第一个参数的虚部值。例如:
c:2+3i>5+6i;
//返回值为0+3i;
c:!(2+3i);
//返回值为0+3i;
c:2+3i==2+6i; //返回值为1+3i;
c:2+3i!=2+6i;
//返回值为0+3i;
FORCAL的这种规定使得不能直接用==、!=运算符对两个复数作相等或不等的比较。如果要比较两个复数相等或者不等,应对复数的实部和虚部都进行比较,见下面的例子。
c:(:a,b)=
a=2+3i,b=2+3i,a==b&xy(a)==xy(b);
//返回值为1+3i;
c:(:a,b)= a=2+3i,b=2+5i,a==b&xy(a)==xy(b);
//返回值为0+3i;
在上面的例子中,xy(a)是一个复数函数,该函数用于交换复数a的实部和虚部。
关系运算符和逻辑运算符的优先级如表7-2所示。在表中,同一行中运算符优先级相同,不同行中运算符的优先级从上往下依次降低。
表7-2 关系运算符和逻辑运算符及优先级
|
运 算 符 |
说 明 |
| ! | 逻辑非 |
| >、>=、<、<=、==、!= | 关系运算符 |
| & | 逻辑与 |
| | | 逻辑或 |
8 逗号运算符和括号运算符 [返回页首] [返回目录]
表达式中如果有多个语句,可以用逗号进行分隔,FORCAL将按从左到右的顺序计算各个语句,并返回最后一个语句的值。也可以将多个用逗号分隔的语句放在一个括号内,FORCAL也将按从左到右的顺序计算各个语句,并返回最后一个语句的值。例如:
(:x)= x=2,x=5,x;
//返回值为5;
(:x)={x=2,x=5,x};
//返回值为5;
(:x,y)={x=2,y=5,x=[x=x+1,y=y+1,x+y],x};
//返回值为9;
(:x,y)={x=2,y=5,[x=x+1,y=y+1,x+y]};
//返回值为9;
FORCAL中的运算符及优先级如表9-1所示,在表中,同一行中运算符优先级相同,不同行中运算符的优先级从上往下依次降低。
表9-1:FORCAL运算符及优先级
|
运 算 符 |
说 明 |
| ( )、[ ]、{ } | 括号运算符 |
| ++、-- | 后置单目运算符(自增、自减) |
| !、+、-、++、-- | 前置单目运算符(非、正、负、自增、自减) |
| ^ | 算术运算符(乘方) |
| *、/ | 算术运算符(乘、除) |
| +、- | 算术运算符(加、减) |
| >、>=、<、<=、==、!= | 关系运算符(大于、大于等于、小于、小于等于、等于、不等于) |
| & | 逻辑与 |
| | | 逻辑或 |
| = | 赋值运算符 |
| , | 逗号运算符 |
注意在FORCAL中,通常运算符不能连用,例如 !-2 是错误的,应当添加括号分隔开各个运算符,即应当写成 !(-2) 形式。
还有一个FORCAL运算符在表8-1中没有列出:&(取变量的地址)。取地址运算符&只能用于(被逗号隔开的)单独的变量,与其他运算符不发生任何关系,所以这个运算符在表8-1中没有列出,其用法我们将在下面详细介绍。
函数是FORCAL的构成模块,是FORCAL最为重要的特性。一个函数,通过传递给它的参数完成一个特定的功能。通常函数都有一个名字,可通过调用函数名并传递参数来使用函数。所有的函数都将返回一个函数值。典型的函数调用方法如下:
函数名(参数1,参数2,... ...)
函数可以有零个或多个参数,但即便有零个参数,函数名后的括号也不能缺省。函数调用时,参数一定要匹配。
在FORCAL中可以使用的函数有三种:一级函数、二级函数和自定义函数(表达式)。其中一级函数为系统内置的函数,都是单变量函数,运算速度快;二级函数部分为系统内置的函数,部分为软件为提高性能扩充的函数,功能非常丰富;自定义函数实际上就是一个表达式,由用户定义,但只有有名字的自定义函数才能被其他表达式所调用。
实际上,FORCAL还有一类为数不多的函数,称为流程控制函数,不过对于它们,函数的意义并不明显,更多的是流程控制的意义,因此我们不把它们包括在上面的分类中。
FORCAL函数有三种类型,即整数函数、实数函数和复数函数,分别对应着FORCAL的三种表达式。FORCAL规定:一级函数和二级函数只能应用在同类型的表达式中(不过可以用CalFun(...)函数间接调用其他类型的二级函数),而自定义函数可以应用在任意的表达式中,FORCAL将 自动为自定义函数的调用进行类型转换。如果在整数或实数表达式中调用复数自定义函数,传递的参数个数应是复数自定义函数的自变量个数的两倍,即对复数自变量参数的实部和虚部都要进行赋值,且只能返回复数自定义函数的实部的值。如果在复数表达式中调用整数或实数类型的自定义函数,和一般的函数调用一样,参数要匹配,调用时只将复数的实部传递给整数或实数自定义函数,而函数返回值只传递给复数的实部。例如:
c:a(x,y)=x+y;
//复数自定义函数,有两个参数;
a(1,2,5,6);
//调用函数a时,要传递四个参数;
b(x,y)=x+y;
//实数自定义函数,有两个参数;
c:b(1+2i,5+6i); //调用函数b时,仍然传递两个参数;
在整数表达式中进行一级函数运算时,将把整数转化为双精度实数后进行运算,最后再把运算结果转化为整数。
FORCAL中的一级函数见表10-1。
表10-1:一级函数
| 函数类型 | 实数函数 | 整数函数 | 复数函数 | 说明 |
| 正弦函数 | sin(x) | sin(x) | ||
| 余弦函数 | cos(x) | cos(x) | ||
| 正切函数 | tan(x) | |||
| 反正弦函数 | asin(x) | |||
| 反余弦函数 | acos(x) | |||
| 反正切函数 | atan(x) | |||
| 平方根函数 | sqrt(x) | sqrt(x) | sqrt(x) | |
| 指数函数 | exp(x) | exp(x) | exp(x) | |
| 自然对数函数 | ln(x) | ln(x) | ln(x) | |
| 常用对数函数 | lg(x) | lg(x) | lg(x) | |
| 双曲正弦函数 | sinh(x) | [exp(x)-exp(-x)]/2 | ||
| 双曲余弦函数 | cosh(x) | [exp(x)+exp(-x)]/2 | ||
| 双曲正切函数 | tanh(x) | [exp(x)-exp(-x)]/[exp(x)+exp(-x)] | ||
| 取整函数 | int(x) | int(x) | 截去x的小数部分 | |
| 绝对值函数 | abs(x) | abs(x) | abs(x) | |
| 共轭函数 | con(x) | |||
| 实部虚部交换函数 | xy(x) | |||
| 实部为0函数 | x0(x) | |||
| 虚部为0函数 | y0(x) |
11 函数的传值调用和传址调用 [返回页首] [返回目录]
传值调用是把变量值拷贝到被调函数的形式参数中,函数在执行时,参数的改变不会影响到调用函数时所用的变量。
传址调用(也叫引用调用)是把变量的地址拷贝到被调函数的形式参数中,函数在执行时,参数的改变会影响到调用函数时所用的变量。
通常,FORCAL是按传值调用的,除非你用取地址运算符&(也叫引用运算符)显示地通知FORCAL编译器,要按传址方式使用参数。在使用运算符&时,&只能放到(用逗号隔开的)单独存在的变量的前面。如下列:
a(x,y)= x=2,y=3;
(:x,y)=
x=5,y=6,a(x,y),x; //传值调用,x=5;
(:x,y)=
x=5,y=6,a(x,y),y; //传值调用,y=6;
(:x,y)=
x=5,y=6,a(&x,y),x;
//传址调用,x=2;
(:x,y)= x=5,y=6,a(x,&y),y;
//传址调用,y=3;
12 用表达式作为函数的参数 [返回页首] [返回目录]
在函数调用时,有时候需要用表达式的名称(即自定义函数名)作为函数的参数,此时将表达式的名称作为字符串(两个双引号"..."之间的内容为一个字符串)传给函数即可。见下面的例子:
f(x)=x+1;
//定义一元函数;
g(x)=sin[x]+0.8;
//定义一元函数;
SimpIntegrate(0,2,0.0001,"f");
//变步长辛卜生一元积分,对函数f从0到2进行积分,精度为0.0001;
SimpIntegrate(1,2,0.0001,"g"); //变步长辛卜生一元积分,对函数g从1到2进行积分,精度为0.0001;
13 FORCAL表达式的完整定义 [返回页首] [返回目录]
在这里,我们总结性地给出FORCAL表达式的完整定义,以帮助用户更好地理解FORCAL,为了定义的完整性,部分地重复了前面所叙述过的内容。FORCAL表达式的完整定义如下:
F(a,b:x,y,static,u:s,t,common,v)=
{x=1,y=2,[x+y,x*y],(x-y),
a+b+x+y+static+u+s+t+common+v
}
F是表达式的名字,必须位于表达式的开头,该名字必须是一个标识符。给表达式起一个名字,主要是以后可以通过该名字来调用该表达式。表达式也可以没有名字,但这样,在其它的表达式中将无法调用它。在FORCAL中,一般表达式的名字是唯一的,不能给两个表达式起同一个名字(模块内表达式的名字除外,模块的定义将在后面介绍)。
如果定义了表达式名字,表达式名字后必须跟一对小括号(只能用小括号),用来定义变量。变量个数可以为零,也可以有任意多个。有多个变量时,变量间以逗号或冒号分隔。用冒号隔开的变量,从前往后依次为
自变量、动态变量、静态变量、模块变量和全局变量,即第一个冒号前为自变量,两个冒号之间为动态变量和静态变量,第二个冒号后为模块变量和全局变量。两个冒号之间用关键字static分隔动态变量和静态变量,static之前为动态变量,static及以后变量均为静态变量,关键字static只
能用在两个冒号之间。第二个冒号后用关键字common分隔模块变量和全局变量,common之前为模块变量,common及以后变量均为全局变量,关键字common只能用在第二个冒号后。
自变量、动态变量和静态变量只能被定义该变量的表达式所访问;模块变量可被同一模块的所有表达式所访问,其他模块的表达式无法访问;全局变量可被所有的表达式所访问。自变量用于向表达式传递参数
,因此自变量也称为形式参数。动态变量只在表达式执行时起作用,一旦表达式执行完毕,动态变量也随之失效。静态变量存在于表达式的整个生命周期,每次表达式执行完毕,静态变量的值被保留。FORCAL在编译表达式时,将所有静态变量初始化为0,其余的变量均不进行初始化。
所有变量以及冒号均可缺省。在这个例子中,a和b是自变量,x和y是动态变量,static和u是静态变量,s和t是模块变量,common和v是全局变量。
即便表达式没有名字,也可以用一对小括号(只能用小括号)来定义变量,这时,小括号必须位于表达式的开头。
如果用小括号定义了变量,小括号后必须跟一个等号,该等号标志表达式可执行部分的开始,等号及等号后的可执行部分均不可缺省。
表达式中可以不定义变量,这时,表达式中只有可执行部分,称常量表达式,或者称无参表达式。
表达式的可执行部分任何情况下都不可缺省。
表达式的可执行部分由多个语句组成,多个语句之间用逗号分隔,多个语句可以放在一对括号内。可执行部分中可以使用三对括号( )、[ ]和{ },括号必须成对使用。在FORCAL中,括号是一种运算符,具有一个值,即该括号内最后一个语句的值。表达式总是返回(最外层括号中)最后一个语句的值。另外,最外层的括号不是必须的,但表达式若有逗号隔开的多个语句,有了最外层的括号后,表达式更易读。
用这种方式定义表达式时,实际上就是自定义了一个函数,可以在任意的表达式中使用该函数(只要给该函数起了名字),由于这个原因,我们常常将表达式说成是函数,或者说表达式就是一个函数,但反过来并不成立。
以下都是合法的表达式定义的例子:
2;
//常量(无参)表达式(函数);
()=2;
//常量(无参)表达式(函数);
(::)=2;
//常量(无参)表达式(函数);
A()=2;
//常量(无参)表达式(函数),但定义了函数名字,在其它表达式中可以调用该函数;
A(::)=2;
//常量(无参)表达式(函数),但定义了函数名字,在其它表达式中可以调用该函数;
B(x)=2;
//有一个自变量的表达式(函数);
(x)=23;
//有一个自变量的表达式(函数),但没有函数名,不能在其他表达式中调用该函数;
F(a,b)= ...
... //定义了两个自变量a和b;
F(:x,y)= ...
... //定义了两个动态变量x和y;
F(:static,u)= ...
... //定义了两个静态变量static和u;
F(::s,t)= ...
... //定义了两个模块变量s和t;
F(::common,v)= ...
... //定义了两个全局变量common和v;
F(a,b:x,y)= ...
...
//定义了两个自变量a和b,两个动态变量x和y;
F(a,b::s,t)= ... ...
//定义了两个自变量a和b,两个模块变量s和t;
F(:x,y:s,t)= ... ...
//定义了两个动态变量x和y,两个模块变量s和t;
在FORCAL中,表达式的各个语句一般是顺序执行的。但是某些函数可以改变语句执行的顺序,称为流程控制函数。
14.1 立即返回函数 return(x)
结束计算并立即返回表达式的值为x。
14.2 判断函数 if(x,y1,y2,... ...,yn)
当逻辑语句x的值为真时,依次执行语句y1,y2,...
...,yn,否则,不执行语句y1,y2,... ...,yn。
该函数至少要有2个自变量参数,其中第一个参数为逻辑语句。
该函数的返回值无意义。
14.3 自定义分段函数
which{逻辑语句1,语句1,
逻辑语句2,语句2,
... ...,
逻辑语句n,语句n,
缺省语句
};
FORCAL从前往后计算并检测逻辑语句的值,当检测到逻辑真时,计算与此逻辑真对应的语句并返回该语句的值,如果没有检测到逻辑真,则计算缺省语句的值作为返回值,若此时没有缺省语句,则产生一个运行错误(错误代码为1)。
该函数至少要有2个自变量参数。
例如下式定义了一个分段函数:
(x)=which{x>0,2*x-1,
x*x-1
};
如果舍弃该函数的返回值,则该函数可以作为一个选择计算函数使用。
14.4 while循环函数
while循环是“当型”循环,其特点是:先判断条件是否成立,当条件成立时,则执行循环体,否则退出循环体,即“当条件成立时执行循环”。“当型”循环的循环体有可能一次也不执行。
while循环函数的格式如下:
while{x,
y1,y2,
...,
break(),
...,
continue(),
...,
yn
};
其中x为逻辑语句;y1,y2,...,break(),...,continue(),
...yn为循环体语句。当x的值为真时,依次执行循环体语句,直到x的值为假时退出循环。当执行到break()函数时,跳出while循环,执行while循环后面的语句部分;当执行到continue()函数时,返回到while循环的开始语句x处继续执行。
在循环体语句中,必须有能修改逻辑语句x的值的语句,使x的值为假,退出循环体,否则将产生无限循环。
该函数至少要有2个自变量参数,其中第一个参数为逻辑语句。
该函数的返回值无意义。
以下是一个while循环的例子:
(:i,k)=
{i=0,k=0,
while{i<=1000000,k=k+i,i++}, //当i<=1000000时,计算k=k+i,然后i++;
k
};
14.5 until循环函数
until循环是“直到型”循环,其特点是:先执行循环体,再判断条件是否成立,当条件成立时,退出循环体,否则继续执行循环体,即“执行循环直到条件成立”。“直到型”循环的循环体至少执行一次。
until循环函数的格式如下:
until{x1,x2,
...,
break(),
...,
continue(),
...,
y
};
until为先执行后判断的循环函数。即先执行循环体语句x1,x2,...,break(),...,continue(),...,然后计算逻辑语句y的值,直到y的值为真时退出循环。当执行到break()函数时,跳出until循环,执行until循环后面的语句部分;当执行到continue()函数时,返回到until循环的开始语句x1处继续执行。
在循环体语句中,必须有能修改逻辑语句y的值的语句,使y的值为真,退出循环体,否则将产生无限循环。
该函数至少要有2个自变量参数,其中最后一个参数为逻辑语句。
该函数的返回值无意义。
以下是一个until循环的例子:
(:i,k)=
{i=0,k=0,
until{k=k+i,i++,i>1000000},
//计算k=k+i,i++,当i>1000000时退出;
k
};
注意:
(1)break()和continue()是两个无参函数,只能用在while和until两个循环函数中。
(2)FORCAL支持多线程,在多线程的程序中,如果不慎进入了无限循环,可以通过另一个线程退出。
在FORCAL中,用两个双引号定义一个字符串,即"..."表示一个字符串。在FORCAL字符串中,还可以用反斜杠转义字符输入一些特殊字符,见表15-1。
表15-1 反斜杠转义字符
| \\ | 反斜杠“\” |
| \" | 双引号“"” |
| \NNN | 任意字符,NNN是该字符ASCII码的10进制值,NNN必须是三个数字,例如ASCII码为9的字符,应写成\009 |
除了表中定义的之外,FORCAL没有定义其它的转义字符(“\”和其他字符的组合都是非法的)。
可以看出,反斜杠“\”和双引号“"”只能通过转义字符输入。
例如:
PrintStr("字符串!!!"); //用PrintStr函数输出字符串,PrintStr是测试程序ForcalTest的一个函数;
FORCAL在编译表达式时,将同一个表达式中的字符串连续存放,同时将每一个字符串都转换成一个整数,该整数即该字符串的首字符所在的位置。因而,两个相邻字符串的差即前一个字符串的长度的负值。
例如:
(:i,j)={i="Hello Forcal !",j="end",PrintStr(i),j-i}; //该函数返回第一个字符串的长度;
可以用字符串标识任意类型的数据值,这是FORCAL除数值计算外的另一大特色。如前所述,字符串形式的表达式的名称可以作为参数传给函数,此时,该字符串标识一个表达式。再如,下面语句中的字符串"aa"标识一个实数数组,"str"标识一个一维字符数组:
NewRealArray("aa",10);
//用NewRealArray函数申请一个实数数组"aa",数组长度为10;
NewStr("str",10);
//用NewStr函数申请一个一维字符数组"str",数组长度为10;
注意:一维字符数组实际上也是一个字符串,不过该字符串需要用专门的函数进行存取,在FORCAL中没有定义这些函数。
在表达式中,可以通过相应的函数定义数组,这些数组是全局性的,可以被任何一个表达式访问到。
考虑到不是所有的软件都操作数组,FORCAL只提供了定义数组的函数,没有提供存取数组的函数,存取数组的函数由使用数组的应用程序提供。
16.1 定义一维整数数组 NewIntArray("aa",m,x1,x2,...,xn):整数函数
该函数只能在整数表达式中直接使用。该函数定义一个一维整数数组"aa",数组长度为m,可存储m个整数,可用x1,x2,...,xn对数组赋初值,初值个数应小于或等于数组的长度,多余的初值将被忽略。该函数返回值的意义如下:
0:定义成功。
1:该数组已存在。
2:内存分配失败。
3:不能用空字符串作为数组名。
4:该函数至少需要2个参数。
5:应使用字符串作为数组名。
6:数组长度m应大于等于1。
16.2 定义一维双精度实数数组 NewRealArray("aa",m,x1,x2,...,xn):实数函数
该函数只能在实数表达式中直接使用。该函数定义一个一维双精度实数数组"aa",数组长度为m,可存储m个实数,可用x1,x2,...,xn对数组赋初值,初值个数应小于或等于数组的长度,多余的初值将被忽略。该函数返回值的意义如下:
0:定义成功。
1:该数组已存在。
2:内存分配失败。
3:不能用空字符串作为数组名。
4:该函数至少需要2个参数。
5:应使用字符串作为数组名。
6:数组长度m应大于等于1。
16.3 定义一维双精度复数数组 NewComplexArray("aa",m,x1,x2,...,xn):复数函数
该函数只能在复数表达式中直接使用。该函数定义一个一维双精度复数数组"aa",数组长度为m,可存储m个复数,可用x1,x2,...,xn对数组赋初值,初值个数应小于或等于数组的长度,多余的初值将被忽略。该函数返回值的意义如下:
0:定义成功。
1:该数组已存在。
2:内存分配失败。
3:不能用空字符串作为数组名。
4:该函数至少需要2个参数。
5:应使用字符串作为数组名。
6:数组长度m应大于等于1。
16.4 定义一维字符数组 NewStr("aa",m,"..."):
该函数可在任意的表达式中使用。该函数定义一个一维字符数组"aa",数组长度为m,可存储m-1个字符,可用"..."对数组赋初值,"..."的长度应小于或等于数组的长度,多余的字符将被忽略。该函数返回值的意义如下:
0:定义成功。
1:该数组已存在。
2:内存分配失败。
3:不能用空字符串作为数组名。
4:该函数只能有2个或3个参数。
5:应使用字符串作为数组名。
6:数组长度m应大于等于1。
注意:一维字符数组实际上是一个字符串。由于字符串总是以标志0结尾,故长度为m的字符数组最多存储m-1个字符。
16.5 释放数组 DeleteArray(Type,"Name"):
该函数可在任意的表达式中使用。其中Type表示数组的类型,Type=7:一维整数数组,Type=8:一维实数数组,Type=9:一维复数数组,Type=10:一维字符数组;Name为数组名。该函数返回值的意义如下:
0:成功释放了数组占据的空间。
1:应使用字符串作为数组名。
2:数组类型非法。
如果一个函数直接或者间接地调用了自己,称作函数的递归调用。FORCAL支持函数的递归调用。
为了在FORCAL中使用递归,需要在相应类型的表达式中设置好相应类型的堆栈。在整数表达式中用SetIntStackMax(n)进行设置,在实数表达式中用SetRealStackMax(n)进行设置,在复数表达式中用SetComplexStackMax(n)进行设置。注意n的值不能取得太大,当n取得很大时,函数递归调用虽不会溢出FORCAL的堆栈,但会使系统堆栈溢出,这样会使程序运行中断,丢失数据(作者还没有很好的解决这个问题!希望朋友们能够帮助解决,深表谢意。)。并不需要每次运行程序都进行堆栈的设置,如果堆栈设置的合适,可以只设置一次堆栈。
下面就是递归的最简单的例子:
SetRealStackMax(10000);
//设置实数堆栈为10000;
a()=a();
//函数a递归地调用自己,属于无穷递归调用。
直接运行上面的表达式,将会返回一个堆栈溢出的运行错误。虽然溢出FORCAL的堆栈不会中断程序的运行,但对于上面的程序,无论设置多大的堆栈都会溢出,因为函数a的递归定义是错误的。递归函数应当包含一条控制该函数是继续调用其本身还是返回的语句。如果没有这样的语句,递归函数将用完分配给堆栈的所有内存空间,导致堆栈溢出错误。
下面举一个能正常递归调用返回的例子。
SetRealStackMax(1000);
//设置实数堆栈为1000;
Fact(n)=which{n<=1,1,n*Fact(n-1)};
//阶乘函数Fact的递归实现;
Fact(3);
//计算3!;
Fact(5);
//计算5!;
Fact(10);
//计算10!;
Fact(100);
//计算100!;
以下是一个交叉递归的例子。
SetRealStackMax(1000);
//设置实数堆栈为1000;
//以下语句中,CalFor()是测试程序ForcalTest中定义的函数,可在运行时调用实型自定义函数;
a(x)=PrintStr["a..."],if(x<1,return[x]),CalFor["b",x-1];
//a(...)函数中调用了b(...)函数;
b(x)=PrintStr["b..."],if(x<1,return[x]),CalFor["a",x-1];
//b(...)函数中调用了a(...)函数;
a[10]; //启动递归程序;
FORCAL支持表达式的模块化编译。由于测试程序ForcalTest很简单,没有使用FORCAL的模块化编译功能,因此在这里仅对模块化作一简单介绍。
在用FORCAL编译表达式时,要给该表达式指定模块号,模块号用一个整数进行标识。
在FORCAL中,一个模块由一个或多个表达式组成。模块用一个整数标识,整数可正可负,只要绝对值相等,就属于同一个模块。一般用正整数表示该模块名。模块共有两类,即主模块(0#模块)和普通模块(其他标号的模块)。
同一模块中,模块号为负的表达式只能访问(即调用)本模块的表达式,同时也只有本模块的表达式能访问到;模块号为正的表达式,既可以访问本模块内的表达式,也可以访问其他模块中(主模块除外)所有模块号为正的表达式。FORCAL的这种规定说明,具有负模块号的表达式在其他模块中是不可见的,起到了信息保护的作用。
FORCAL规定,主模块可以访问本模块中或其他模块中所有模块号为正的表达式。因此,主模块常常用在主程序中。
在下面的说明中,FcErr表示相应函数的运行错误代码。
19.1 整数二级函数
19.1.1、最大值函数 max(x1,x2,x3,... ...):
若FcErr=1:没有参数。
19.1.2、最小值函数 min(x1,x2,x3,... ...):
若FcErr=1:没有参数。
19.1.3、余数函数 mod(x,y):
求x/y的余数。
19.1.4、符号传送函数 sign(x,y):
该函数的符号取y的符号,数值取x的绝对值,若y=0无符号传送,返回x值。
19.1.5、正差函数 dim(x,y):
当x>y时得x-y,否则返回0。
19.1.6、设置整数堆栈最大数目 SetIntStackMax(n):
在使用递归函数之前,需要先设置一定数目的堆栈。通常n的值不能取得太大,当n取得很大时,函数递归调用虽不会溢出FORCAL的堆栈,但会使系统堆栈溢出,这样会使程序运行中断。该函数返回实际设置的堆栈数目。
若FcErr=1:内存分配失败。
19.1.7、调用二级函数 CalFun(m,"aa",x1,x2,...,xn):
只能调用实数或复数二级函数,整数二级函数可直接调用,无需使用该函数。m=5时调用实数二级函数;m=6时调用复数二级函数。"aa"为要调用的二级函数名称。x1,x2,...,xn为二级函数的自变量。如果调用复数二级函数,所传送的自变量参数应为复数二级函数自变量个数的两倍,分别与复数自变量的实部和虚部相对应;函数返回时,仅返回复数实部的值。
若FcErr=1:该函数至少使用两个参数,或者参数不匹配;FcErr=2:应使用字符串传递二级函数名称;FcErr=3:函数类型参数m非法;FcErr=4:找不到该二级函数;FcErr=5:内存分配失败。
19.2 实数二级函数
19.2.1、反正切函数 atan2(x,y):
求x/y的正切值,所在象限由x和y的符号确定。
19.2.2、最大值函数 max(x1,x2,x3,... ...):
若FcErr=1:没有参数。
19.2.3、最小值函数 min(x1,x2,x3,... ...):
若FcErr=1:没有参数。
19.2.4、余数函数 fmod(x,y):
求x/y的余数。
19.2.5、取小数部分函数 modf(x):
该函数把x分解成整数和小数部分,并返回小数部分。
19.2.6、符号传送函数 sign(x,y):
该函数的符号取y的符号,数值取x的绝对值,若y=0无符号传送,返回x值。
19.2.7、正差函数 dim(x,y):
当x>y时得x-y,否则返回0。
19.2.8、变步长辛卜生一元积分 SimpIntegrate(a,b,eps,"F"):
a为积分下限,b为积分上限,eps为积分精度要求,F为被积函数。
例子:
a(x)=sin[x]+0.8;
SimpIntegrate(1,2,0.0001,"a");
若FcErr=1:应使用字符串传递表达式名称;FcErr=2:指定的表达式不存在;FcErr=3:指定的表达式不是一元函数;
19.2.9、求和函数 sum("F",y1min,y1max,y1dy,y2min,y2max,y2dy,... ...):
F为求和函数;y1min,y1max,y1dy为第一个自变量的初值、终值和参数增量[初值<终值,参数增量>0],依次类推。
例子:
F(x,y)=sin[x]+0.8-y;
sum("f",1,2,0.01,2,5,0.1);
FcErr=1:应使用字符串传递表达式名称;FcErr=2:指定的表达式不存在;FcErr=3:参数个数不匹配;FcErr=4:常量表达式,无法求和;FcErr=5:内存分配失败;FcErr=6:自变量参数非法。
19.2.10、求积函数 pro("F",y1min,y1max,y1dy,y2min,y2max,y2dy... ...):
用法请参见sum(),用于求积。
FcErr=1:应使用字符串传递表达式名称;FcErr=2:指定的表达式不存在;FcErr=3:参数个数不匹配;FcErr=4:常量表达式,无法求积;FcErr=5:内存分配失败;FcErr=6:自变量参数非法。
19.2.11、数据求和函数 DataSum("F",y11,y12,... ...,y21,y22,... ...):
F为求和函数;y11,y12,... ...为第一组自变量数据,依次类推。
例子:
F(x,y)=x*y;
DataSum["F",1,2,3,4,5,6,7,8,9,10]; //返回值为190;
说明:对于式子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]的值。
若FcErr=1:应使用字符串传递表达式名称;FcErr=2:指定的表达式不存在;FcErr=3:参数个数不匹配;FcErr=4:常量表达式,无法求和。
19.2.12、数据求积函数 DataPro("F",y11,y12,... ...,y21,y22,... ...):
用法请参见DataSum(),用于数据求积。
若FcErr=1:应使用字符串传递表达式名称;FcErr=2:指定的表达式不存在;FcErr=3:参数个数不匹配;FcErr=4:常量表达式,无法求积。
19.2.13、设置实数堆栈最大数目 SetRealStackMax(n):
在使用递归函数之前,需要先设置一定数目的堆栈。通常n的值不能取得太大,当n取得很大时,函数递归调用虽不会溢出FORCAL的堆栈,但会使系统堆栈溢出,这样会使程序运行中断。该函数返回实际设置的堆栈数目。
若FcErr=1:内存分配失败。
19.2.14、数组数据求和函数 DataArraySum("F",nn,"n1","n2",... ...):
该函数以数组中的数据为自变量,对某个表达式进行累计求和。F为求和函数,nn指出有nn组数据,"n1","n2",... ...为与自变量相对应的多个数组。
若FcErr=1:应使用字符串传递表达式名称;FcErr=2:指定的表达式不存在;FcErr=3:参数个数不匹配;FcErr=4:常量表达式,无法求和;FcErr=5:数据组数nn应大于0;FcErr=6:无法分配内存;FcErr=7:应使用字符串传递数组名称;FcErr=8:指定的数组不存在;FcErr=9:数组"n1","n2",... ...中的某个数组长度小于nn。
NewRealArray["a",10,2,2,2,2,2,2,2,2,2,2];
NewRealArray["b",10,3,3,3,3,3,3,3,3,3,3];
ff(a,b,c)=a+b+c;
DataArraySum["ff",10,"a","b","a"];
19.2.15、调用二级函数 CalFun(m,"aa",x1,x2,...,xn):
只能调用整数或复数二级函数,实数二级函数可直接调用,无需使用该函数。m=4时调用整数二级函数;m=6时调用复数二级函数。"aa"为要调用的二级函数名称。x1,x2,...,xn为二级函数的自变量。如果调用复数二级函数,所传送的自变量参数应为复数二级函数自变量个数的两倍,分别与复数自变量的实部和虚部相对应;函数返回时,仅返回复数实部的值。
若FcErr=1:该函数至少使用两个参数,或者参数不匹配;FcErr=2:应使用字符串传递二级函数名称;FcErr=3:函数类型参数m非法;FcErr=4:找不到该二级函数;FcErr=5:内存分配失败。
19.3 复数二级函数
19.3.1、设置复数堆栈最大数目 SetComplexStackMax(n):
在使用递归函数之前,需要先设置一定数目的堆栈。通常n的值不能取得太大,当n取得很大时,函数递归调用虽不会溢出FORCAL的堆栈,但会使系统堆栈溢出,这样会使程序运行中断。该函数返回实际设置的堆栈数目。
若FcErr=1:内存分配失败。
19.3.2、调用二级函数 CalFun(m,"aa",x1,x2,...,xn):
只能调用整数或实数二级函数,复数二级函数可直接调用,无需使用该函数。m=4时调用整数二级函数;m=5时调用实数二级函数。"aa"为要调用的二级函数名称。x1,x2,...,xn为二级函数的自变量,只将复数的实部传给该自变量。该函数返回时,实部为二级函数的值,虚部为0。
若FcErr=1:该函数至少使用两个参数,或者参数不匹配;FcErr=2:应使用字符串传递二级函数名称;FcErr=3:函数类型参数m非法;FcErr=4:找不到该二级函数;FcErr=5:内存分配失败。
FORCAL中有以下提高效率的方法。
1、将表达式中可以计算的部分放到括号中。
例如,需要将表达式:
F(x,y)=x-5-7+y
写成:F(x,y)=x-[5+7]+y或F(x,y)=x+[-5-7]+y。
2、尽量使用自增减运算符++和--。
例如要把 i=i+1 写成 i++ 形式。
3、until循环函数的速度比while循环函数要快。
4、尽量避免不同类型表达式之间的相互调用,因为类型转换需要时间。尽量少用CalFun(...)函数。
5、尽量避免使用全局变量。
1、表达式最大长度:2G;
2、自变量个数:不限;
3、动态变量、静态变量、模块变量、全局变量个数:不限;
4、最多可用的实数表达式:不限;
最多可用的复数表达式:不限;
最多可用的整数表达式:不限;
5、表达式中最多可用的字符串数:不限;
6、自定义外部函数个数:不限;
7、while循环、until循环最大循环次数:不限;
8、表达式递归调用最多层数:受系统堆栈和自定义堆栈大小的限制,自定义堆栈最大为2G;
9、最多可存储的用户自定义数据类型:约32K;
10、执行速度:一级函数速度约为FORTRAN(或C/C++)执行速度的50%左右;其他情况,速度稍有下降;
11、FORCAL.DLL文件大小:152K;
12、内存需求:视FORCAL运行情况而定。
版权所有© Forcal数学软件
2002-2008,保留所有权利
E-mail: forcal@sina.com
QQ:630715621
最近更新: 2008年05月01日