OpenForcal的用户界面

目  录

1 什么是OpenForcal
2 主要技术指标
3 Forcal表达式
4 OpenForcal源程序
5 表达式的名称及用表达式作为函数的参数
6 OpenForcal中的函数
7 常量与变量
8 再谈Forcal中的函数
9 用mov( )函数给自变量赋值及过程
10 Forcal中的逻辑函数
11 Forcal中的流程控制函数
12 Forcal中的字符数据处理
13 Forcal中的数组
14 效率及其他
15 例子


1 什么是OpenForcal  [目录]

    Forcal是Formula Calculator的缩写,是一个数学表达式编译计算系统。它以动态库的形式存在,可以为多种程序提供支持。动态库(扩展名为DLL)是Windows使用的一种在程序运行时进行加载使用的执行程序。
    OpenForcal也是一个动态库,由Forcal提供支持。但它对Forcal的使用进行了封装,隐藏了一些较难实现的细节,仍然保留有用的接口,使用OpenForcal编写程序比直接使用Forcal更容易,而且效率更高,代码的可重用性更好。
    OpenForcal提供了一个统一的具有C++注释风格的源程序界面,使用户可以通过简单的编程方便地实现他们所需的功能。OpenForcal设计的目的是:用一种最简单的函数调用来执行各种复杂的数学计算,即:函数名(自变量1,自变量2,... ...)。
    OpenForcal本身提供的函数功能非常有限,但很容易对OpenForcal进行功能扩展。OpenForcal可以加载多个扩展动态库,通过这些扩展动态库,可以为OpenForcal添加编译预处理及各种数值计算函数,因而是一个开放式的数值计算系统。
    OpenForcal也提供了简单的编程功能,但并不提倡这样做,把常用的程序放到OpenForcal的扩展动态库中,由OpenForcal调用会更好。
    在下面的内容中我们将介绍OpenForcal的功能及用法,所有由OpenForcal支持的实用程序都将具有这些最基本的性能。


2 主要技术指标  [目录]

    OpenForcal主要技术指标如下:


    (1)表达式最大长度:32K;
    (2)自变量个数:不限;
    (3)变量个数:不限;
    (4)最多可用的实数表达式:30000个;
        最多可用的复数表达式:30000个;
        最多可用的整数表达式:30000个;
    (5)表达式中最多可用的字符串数:不限;
    (6)所有表达式中最多可用的字符串总数:100000个;
    (7)自定义外部函数个数:32K;
    (8)for循环、dowhile循环最大循环次数:2G;
    (9)表达式嵌套调用最多层数:32K;
    (10)执行速度:若表达式中仅含有一级函数,速度约为FORTRAN(或C/C++)执行速度的50%左右;其他情况,速度稍有下降;
    (11)源程序最大长度:10000000个字符;
    (12)加载扩展动态库个数:不限;
    (13)加载动态库说明文件个数:不限;
    (14)OpenForcal.dll文件大小:68K;Forcal.dll文件大小:136K;
    (15)内存需求:视OpenForcal运行情况而定。


3 Forcal表达式  [目录]

    由于OpenForcal由Forcal提供支持,因此我们首先需要了解Forcal表达式。
    FORCAL表达式用一些文本字符表示,可以用任何一种文本编辑器进行编辑。而数学公式有各种各样复杂的形式,因此需要把各种复杂的数学公式转换成文本字符形式,如果您还不知道如何进行转换,请参考任何一门高级语言程序设计的书籍。

3.1 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 为函数名,可为任意字符,或者缺省;自变量放在小括号( )内,有多个自变量时,自变量间以逗号分隔,自变量由英文小写字母a...z、下划线_和数字0...9组成,但第一个字符不能为数字,自变量个数可以为零;等号后为函数式,不可缺省。
    格式2和格式3是等效的,均表示无参函数。
    格式4:数学表达式的可优化表示形式。aa、bb为后置变量[在表达式后面定义,后置变量必须赋一个值],其命名方式与自变量相同且不能与任何一个自变量同名。该格式的计算顺序为从右向左,即:先计算bb,然后计算aa,最后计算F(x,y)并把该值作为整个表达式的值。
    格式5表示可以将表达式放在一对括号( )、[ ]或{ }内。
    函数式中的运算符有加号'+'、减号'-'、乘号'*'、除号'/'和乘方'^'五种。注意数字与自变量相乘时,乘号不可省略;在进行乘方运算时,底数应为非负数。函数式中可以用三对括号( )、[ ]和{ }。

3.2 FORCAL表达式的特殊形式

    FORCAL表达式的特殊形式提供了与高级语言中的函数或过程相类似的功能。
      格式6:f(x,y:a,b)=one
             {a=2,
              b=3+a,
              return[x+y+a+b]
             }
    在(x,y:a,b)中,冒号前的x,y为表达式的自变量参数,冒号后的a,b为在该表达式中定义的变量,由于这些变量在表达式的开头定义,故称为前置变量,同时把在表达式结尾定义的变量[见格式4]称为后置变量。自变量、前置变量和后置变量统称为变量,变量在表达式中可以重新赋值。
    变量赋值的格式如下:
      (a=2+3)
    即要把赋值表达式放在一对括号内,同时该赋值表达式返回赋值后的变量的值。如果赋值表达式作为一个函数的参数,可以不加括号,例如格式6中的例子。
    除了用赋值表达式可以给变量赋值,用数值传送函数mov[x]也可以给变量赋值,并且,对于下列表达式,mov函数比赋值表达式的执行速度更快:
      [x=x+f(...)]
      mov[f(...)+x]
    另外,例子中的one[...]是一个多变量函数,该函数总是返回0值;return[x]函数返回表达式的值为x。

    以下例子能帮助您进一步了解FORCAL表达式的格式:

      (1)、(:x,y)=[x=2]+[y=x+3]
      无参表达式,但该表达式使用了两个前置变量x和y,该表达式的值为7。
      (2)、(x,y:)=[x=2]+[y=x+3]
      该表达式有两个自变量参数x和y,但该表达式的值总是7。
      (3)、(:)=2+3
      无参表达式,该表达式与2+3等效。
      (4)、f(x,y:a,b)=one
          {a=2,
           b=3+a,
           return[x+y+a+b+c+d]
          },c=8,d=9
      该表达式有两个自变量参数x和y,同时使用了两个前置变量a和b,使用了两个后置变量c和d。

    最后指出,(1)在FORCAL表达式中英文字母不区分大小写(字符串"..."中的字符除外),(2)FORCAL表达式中的空格字符将被忽略(字符串"..."中的空格字符除外)。例如,变量ab2、a B2和Ab2是一样的。

3.3 FORCAL表达式的类型

    FORCAL表达式有实数表达式、复数表达式和整数表达式三种。表达式中的函数均分为一级函数和二级函数,其中一级函数较为常用,为单变量函数,运算速度较快,而二级函数功能较为丰富,非常容易扩充。
    FORCAL表达式中的一级函数见下表:

函数类型 实数表达式 整数表达式 复数表达式 说明
正弦函数 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)  
重置自变量函数 mov(x) mov(x) mov(x) 功能复杂!
共轭函数     con(x)  
实部虚部交换函数     xy(x)  
实部为0函数     x0(x)  
虚部为0函数     y0(x)  

    说明:若整数表达式中有实数,在编译时将全部转化为整数,同时在进行乘方运算以及一级函数运算时,将把整数转化为双精度实数后进行运算,最后再把运算结果转化为整数。
    复数举例:2+3i。
    复数表达式举例:F(x,y,... ...)=2+3i-sin[x-i]*ln[y]- ... ... 。
    在复数表达式中不能使用 i 作为自变量,因为 i 已经用来表示虚数。
    FORCAL中的二级函数包括数据类型函数、逻辑函数、流程控制函数和一些常用数学函数等,极大地扩展了FORCAL的数值计算功能,我们将在后面的说明中分类介绍它们。


4 OpenForcal源程序  [目录]

4.1 OpenForcal源程序的格式


    在OpenForcal源文件中,可以有多个FORCAL表达式,表达式之间用分号“;”隔开。
    由于FORCAL数学表达式有三种,即整数表达式、实数表达式和复数表达式。为便于区分,OpenForcal将以i:开头的表达式作为整数表达式,以c:开头的表达式作为复数表达式,其余为实数表达式。
    同时,在源文件中可以进行注释,注释方法与C++语言相似,即:每行两个//后的内容为注释内容;在一行内或者多行之间
/*...*/之间的内容为注释内容。注释不是源程序的有效部分,但可以使程序更易读。

    举例如下:

    //这是一个例子!红色部分为注释,不会被执行;
    i:2.2+3.3; //以i:开头是整数表达式; 
    c:sin(2.2+3.3i); //以c:开头是复数表达式;
    2.2+3.3; //这是实数表达式。
    2+3;/* 从这里开始,连续几行注释:
    333+222;
    . . . . . . ;
    555-222;
    */
sin(2.5);
    exp(2);


    可以用加载OpenForcal的任何一个程序验证以上代码。

4.2 OpenForcal程序的执行

    由于表达式有些带有参数,有些不带参数,OpenForcal在进行处理时,对于有参数的表达式只进行编译,不进行计算。
    OpenForcal只顺序执行不带参数的表达式。
    但是,如果表达式以冒号“ : ”开头,则无论是有参表达式还是无参表达式,都是只编译,不执行,格式如下:

    i:: 2+3; //整数无参表达式,只编译,不执行;
    i:: "f1" ()=2+3; //整数无参表达式,只编译,不执行;
    c:: 2+3i; //复数无参表达式,只编译,不执行;
    c:: "f2" ()=2+3i; //复数无参表达式,只编译,不执行;
    : 2+3; //实数无参表达式,只编译,不执行;
    : "f3" ()=2+3; //实数无参表达式,只编译,不执行。

    无参表达式f1、f2和f3可以在其他可执行的表达式中被调用。


5 表达式的名称及用表达式作为函数的参数  [目录]

    给表达式起一个名字是为了在另一个地方能够使用它,OpenForcal用下面的方式给表达式定义一个名称:

      "f1"(x)=x+1;

    在FORCAL表达式中两个"..."之间的内容表示为字符串。每个表达式中第一个字符串可以作为该表达式的名称。因此,上面这个表达式的名称即为 f1 ,它在FORCAL内部表示了该种类型表达式的一个序号。
    FORCAL中的有些函数需要用表达式的序号作参数,这时,我们可以用#"..."引用一个已经定义的表达式。 例如:

      "f1"(x)=x+1; //只编译,不执行;
      calfor(#"f1",2); //编译执行。

    表达式 f1 是有参表达式,只编译,不执行。函数calfor[]执行了表达式 f1,并传递给它一个参数2。
    需要注意的是,#"..."只能引用与所在表达式相同类型的表达式,如果要引用不同类型的表达式,需要使用如下形式:
    #"#...": 引用任意类型的表达式,“...”为表达式名称;
    #"i#...": 引用整数类型的表达式,“...”为表达式名称; 
    #"r#...": 引用实数类型的表达式,“...”为表达式名称;
    #"c#...": 引用复数类型的表达式,“...”为表达式名称。


6 OpenForcal中的函数  [目录]

    OpenForcal中只提供了几个必要的函数,大量的函数需要通过扩展动态库提供。

6.1 实数函数

    (1)版本信息函数:ver[];

    (2)实数表达式运行错误检测函数:err[];

    检测到错误时,该函数返回 1 (逻辑真),否则返回 -1 (逻辑假)。

    (3)停止函数:stop[];

    该函数并不立即停止执行程序,只是在执行完本表达式后停止程序的执行。
    若要立即停止程序的执行,需要在stop[]函数后紧跟一个从表达式立即返回的函数return[]。
    例如:
      //假定存在一个输出字符串的函数str["... ..."];
      one{stop[],str["停止程序!"]}; //输出了字符串之后,停止程序执行;
      one{stop[],return[0],str["本字符串不会输出!"]}; //立即停止程序执行;

    (4)取表达式地址函数:GetAddress[$"F",#"F"];

    该函数获取表达式"F"的地址,第一个参数$"F"为表达式的类型,第二个参数#"F"为表达式的序号。
    该函数可能返回如下运行错误:

      1、没有找到该表达式的地址;

    例如:

      "F"(x,y,z)=x+y-z;
      GetAddress[$"F",#"F"];

    (5)运行错误检测函数:FindErrQuit[];

      发现任何运行错误,将停止执行程序!必须重新编译,才能重新运行程序。

    (6)窗口显示控制函数:SetTalk[bool];

      缺省情况下,OpenForcal每计算完一个表达式,就输出该表达式的值。SetTalk[]函数用于设置是否输出表达式的值。当bool为真时,输出表达式的值;当bool为假时,不输出表达式的值,直到再一次遇到SetTalk[真]。注意当bool为假时,并不关闭其他函数的输出。

6.2 复数函数

    (1)复数表达式运行错误检测函数:err[];

    请参考实数函数中的说明。

    (2)停止函数:stop[];

    请参考实数函数中的说明。

    (3)取表达式地址函数:GetAddress[$"F",#"F"];

    请参考实数函数中的说明。

6.3 整数函数

    (1)整数表达式运行错误检测函数:err[];

    请参考实数函数中的说明。

    (2)停止函数:stop[];

    请参考实数函数中的说明。

    (3)取表达式地址函数:GetAddress[$"F",#"F"];

    请参考实数函数中的说明。


7 常量与变量  [目录]

7.1 常量

    常量是指那些不需要程序计算的固定值。有数值常量和符号常量两种。如100就是一个数值常量。在OpenForcal中可以用符号表示一个常量,符号常量名由英文字母a...z、下划线_和数字0...9组成,但第一个字符不能为数字。目前只能使用实型符号常量,实型符号常量用const: 定义,例如:

    const: pi=3.14, _e_=2.718, eps=1e-10; //定义了三个常量;
    const: pi2=2*pi, pi_e=pi-_e_; //在常量定义中可以使用常数表达式;
    pi; pi2; eps; //输出常量的值;

    在常量定义时,等号前为常量的符号名,等号后为任意合法的不包含字符串的常数表达式,在常数表达式中可以使用以前定义的常量,但不能使用同一常量定义语句中的常量。
    除了可以使用自定义的常量以外,还可以使用自动常量。所谓自动常量就是由OpenForcal自动给符号名分配一个常数值。实型自动常量用autoconst: 定义,例如:

    autoconst: a0,a1,a2,a3,a4,a5; //定义了6个自动常量;
    autoconst: b0,b1,b2,b3,b4,b5; //定义了6个自动常量;
    a0;a1;a2;a3;a4;a5; //输出自动常量的值;
    b0;b1;b2;b3;b4;b5; //输出自动常量的值;

    OpenForcal给用autoconst: 定义的常量按其先后顺序自动分配一个从0开始的自然数。把自动常量的符号名放在一个autoconst: 语句中和放在若干autoconst: 语句中是完全一样的。
    如果用autoconst:: 定义自动常量,则每次OpenForcal都会给该语句中的符号名分配一个从0开始的自然数,称局部自动常量。例如:

    autoconst::d1,d2,d3; //定义了3个局部自动常量;
    autoconst::f1,f2,f3; //定义了3个局部自动常量;
    d1;d2;d3; //输出局部自动常量的值;
    f1;f2;f3; //输出局部自动常量的值;

    另外,也可以在动态库说明文件中进行常量定义,请参考“如何对OpenForcal进行功能扩展”中“如何编写动态库函数说明文件”。
    最后指出,如果符号常量名与表达式的自变量重名,则该符号常量被忽略。

7.2 变量

    变量是指在程序运行时,其值可以改变的量。Forcal中的变量有两种,一种是在表达式中定义的变量,这些变量通常用符号表示,只能在本表达式中使用,称为局部变量;另一种是用NewDoubleS(m)、NewDoubleArrayS(m)等函数申请的数组元素,这些数组元素可在任何一个表达式中(通过相应的函数)访问和改变其值,称为全局变量。
    通常,数组元素只能通过序号来访问,非常不方便。但可以利用符号化的自动常量来表示这些序号,因而,数组元素也可以像局部变量一样通过符号来访问。例如:

    autoconst: a0,a1,a2,a3,a4,a5; //定义了6个自动常量;
    autoconst: b0,b1,b2,b3,b4,b5; //定义了6个自动常量;
    autoconst: EndAutoConst; //标志最后一个自动常量;
    NewDoubleS[EndAutoConst]; //申请EndAutoConst个全局变量;
    setd[a1,100]; setd[b1,100]; //给两个全局变量赋值;
    getd[a1]+getd[b1]; //计算两个变量的和;


8 再谈 Forcal 中的函数  [目录]

    前面谈到,FORCAL中的一级函数只有一个自变量,但是二级函数可以有多个自变量甚至没有,不过即使没有自变量,在使用它们时,函数名后面的括号也不能省略。
    使用一个函数,最重要的是要搞清楚它的自变量和返回值的意义。
    例:变步长辛卜生一元积分函数 simpintegrate(a,b,eps,n,x2,x3,... ...):其中a为积分下限,b为积分上限,eps为积分精度要求;n指出要使用一个表达式的序号作参数,该参数即被积函数表达式的名称,前已提及,如果已经定义了被积函数的表达式的名称,可用#"..."获得这个序号;x2,x3,... ...表示可以向被积函数传递多个参数。下面即该函数的实际应用:

    "f"(x)=x+1;
    "g"(x,y)=x+y+1;
    SimpIntegrate(0,5,0.00001,#"f");
    SimpIntegrate(0,5,0.00001,#"g",0);

    总之,函数的自变量可以是一个数,也可以是一个字符串、表达式名称(序号)、数组或者表示其他的意义,具体要查看该函数的相关说明。
    一般地,如果您错误地使用了函数的自变量,将会导致一个程序运行时的错误说明。


9 用mov( )函数给自变量赋值及过程  [目录]

    一级函数 mov(x)是一个特殊的函数。它将x值传送至最近使用的一个变量,因此对该变量进行了重新赋值。注意该函数实际上有两个参数,源参数为x,但目的参数即“最近使用的一个变量”却是隐含的。“最近使用的一个变量”即按照表达式的计算顺序,在mov函数执行之前最后使用的变量。详见下面的例子:
    例1:

    "f1"(x)=x+mov[5]+x;
    calfor[#"f1",2]; // 当x为2时表达式的值为12而不是9。
    para[#"f1",0]; //查看表达式 f1 的自变量值为多少。

    例2:

    "f2"(x)=x+mov[x+5]+x;
    calfor[#"f2",2]; // 当x为2时表达式的值为16。
    para[#"f2",0]; //查看表达式 f2 的自变量值为多少。

    例3:

    "f3"(a,b,c)=one(a,mov[5],b,mov[8],mov[a+b+(c-c)],mov[a+b]);
    calfor[#"f3",777,888,999]; //不论向表达式 f3 传递何值;
    para[#"f3",0]; para[#"f3",1]; para[#"f3",2]; //计算结束时a为5,b为13,c为13。

    可以用para(n,m)函数获取自变量参数,详见FORCAL动态库中para[]函数的介绍。
    可以看出,有时候,表达式的值可能并不重要,重要的可能是自变量的返回值,或者是执行该表达式时执行的一系列处理动作, 这些动作用以完成预定的任务,我们把具有这种功能的表达式称为一个过程。
    FORCAL表达式的特殊形式即是一种过程,关于这种形式,请参考前面的说明。
    如果不需要表达式的值以及不需要向表达式传递参数,可以用过程调用函数 call(n)[或 call(#"...")]来执行一个过程。例如,例3可以该为:

    "f3"(a,b,c)=one(a,mov[5],b,mov[8],mov[a+b+(c-c)],mov[a+b]);
    call[#"f3"];
//用call[]执行一个过程;
    para[#"f3",0]; para[#"f3",1]; para[#"f3",2]; //计算结束时a为5,b为13,c为13。


10 Forcal中的逻辑函数  [目录]

    FORCAL用大于0的数表示逻辑真,小于等于0的数表示逻辑假(复数表达式中的逻辑函数作判断时,仅取复数的实部)。逻辑函数有下面一些:

    (1)、gt(x,y):如果x>y返回1,否则返回-1。
    (2)、ge(x,y):如果x>=y返回1,否则返回-1。
    (3)、lt(x,y):如果x<y返回1,否则返回-1。
    (4)、le(x,y):如果x<=y返回1,否则返回-1。
    (5)、eq(x,y):如果x==y返回1,否则返回-1。
    (6)、ne(x,y):如果x!=y返回1,否则返回-1。
    (7)、and(x,y):如果x>0同时y>0返回1,否则返回-1。
    (8)、or(x,y):如果x<0同时y<0返回-1,否则返回1。
    (9)、not(x):如果x>0返回-1,否则返回1。
    (10)、xor(x,y):如果x和y符号相同返回-1,否则返回1。

    逻辑函数用在FORCAL表达式中需要逻辑判断的地方,例如 for[...]、dowhile[...]、if[...]等函数中用到了逻辑函数。
    实际上,根据逻辑函数的定义,大于0的数表示逻辑真,小于等于0的数表示逻辑假,则任何一个计算式都可以表示逻辑值。例如 100-x ,当x小于100时表示逻辑真,x大于等于100时表示逻辑假。


11 Forcal 中的流程控制函数  [目录]

    在OpenForcal中对于表达式是顺序执行的。但是在表达式的内部,某些函数可以改变计算的顺序,称为流程控制函数。
    在以下说明中,fcerr为动态库函数运行错误代码,int(m)表示取实数m的整数部分,或者表示取复数m的实部的整数部分。
    FORCAL可设置同时使用多个表达式,假如设置了n个表达式,则表达式的序号分别为0、1、2、...、 i、 ...、n-1,第i个表达式简称为表达式i。通常,我们并不直接使用这些序号,而是通过Forcal提供的操作符#"..."来获取,但在这里为了说明的方便,我们将使用表达式i这种说法。

11.1 立即返回函数 return(x)

    结束计算并立即返回表达式的值为x。

11.2 判断函数 if(x,y1,y2,... ...,yn)

    当逻辑值x为真时,依次执行表达式y1,y2,... ...,yn,否则,不执行表达式y1,y2,... ...,yn。
    该函数至少要有2个自变量参数,其中第一个参数为逻辑表达式。
    该函数总是返回0值。

11.3 自定义分段函数

    which{逻辑值1,表达式1,
          逻辑值2,表达式2,
          ... ...,
          逻辑值n,表达式n,
          缺省表达式
         };

    FORCAL从前往后检测逻辑值,当检测到逻辑真时,计算与此逻辑真对应的表达式并返回该表达式的值,如果没有检测到逻辑真,则计算缺省表达式的值作为返回值,若此时没有缺省表达式,则产生一个运行错误。
    若fcerr=1:没有参数或找不到返回值。
    例如下式定义了一个分段函数:

    (x)=which{gt(x,0),2*x-1,
              x*x-1
             };

    如果舍弃该函数的返回值,则该函数可以作为一个选择计算函数使用。

11.4 for循环函数

    for{x,
        y1,y2,
        ...,
        break(),
        ...,
        continue(),
        ...,
        z
       };

    自变量x为逻辑表达式,y1,y2,...,break(),...,continue(), ...为执行语句,z为增量语句。当x的值为真时,依次执行这些表达式,直到x的值为假时退出循环。当执行到break()函数时,跳出for循环,执行for循环后面的函数;当执行到continue()函数时,返回到for循环的开始语句x处继续执行。
    该函数至少要有2个自变量参数,其中第一个参数为逻辑表达式。
    该函数总是返回0值。
    若fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用,或者嵌套太深;fcerr=1:循环次数超出限制。
    该函数中continue()的使用会导致fcerr=1:循环次数超出限制。

11.5 dowhile循环函数

    dowhile{x1,x2,
            ...,
            break(),
            ...,
            continue(),
            ...,
            y
           };

    dowhile为先执行后判断的循环函数。即先执行多个表达式x1,x2,...,break(),...,continue(),...,然后计算逻辑表达式y的值,直到y的值为假时退出循环。当执行到break()函数时,跳出dowhile循环,执行dowhile循环后面的函数;当执行到continue()函数时,返回到dowhile循环的开始语句x1处继续执行。
    该函数至少要有2个自变量参数,其中最后一个参数为逻辑表达式。
    该函数总是返回0值。
    若fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用,或者嵌套太深;fcerr=1:循环次数超出限制。
    该函数中continue()的使用会导致fcerr=1:循环次数超出限制。

11.6 合并表达式函数one(x1,x2,... ...,xn)

    该函数可将多个无参表达式合并为一个表达式,以减少表达式个数,节约内存,并可提高执行速度。
    该函数总是返回0值。

11.7 执行过程函数 call(n)

    int(n)指出该表达式的序号,如果该表达式有参数,则按缺省值进行计算。
    执行过程通常是指不需要传递一个表达式的参数而执行这个表达式,但一般该表达式的自变量返回值有意义,可以用para(n,m)获取该表达式的自变量参数值。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译。
    该函数总是返回0值。

11.8 获取表达式的自变量参数的值 para(n,m)

    int(n)指出该表达式的序号,int(m)指出自变量参数的序号。
    若fcerr=-1:未对可接受表达式的二级函数进行设置,fcerr=1:指定的表达式不存在,fcerr=2:表达式未进行编译,fcerr=3:指定的自变量参数不存在。

11.9 实数表达式中的表达式相互调用函数

11.9.1 计算指定序号的表达式的值 calfor(n,x1,x2,... ...)

    int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.9.2 计算指定序号的复数表达式的值 calcfor(n,x1,y1,x2,y2,... ...)

    int(n)指出该表达式的序号,x1,y1,x2,y2,... ...为该表达式的参数,其中xi为复数的实部,yi为复数的虚部。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.9.3 计算指定序号的整数表达式的值 califor(n,x1,x2,... ...)

    int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.10 整数表达式中的表达式相互调用函数

11.10.1 计算指定序号的表达式的值 calfor(n,x1,x2,... ...)

    n指出该表达式的序号,x1,x2,... ...为该表达式的参数。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.10.2、计算指定序号的复数表达式的值 calcfor(n,x1,y1,x2,y2,... ...)

    n指出该表达式的序号,x1,y1,x2,y2,... ...为该表达式的参数,其中xi为复数的实部,yi为复数的虚部。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.10.3 计算指定序号的实数表达式的值 calrfor(n,x1,x2,... ...)

    n指出该表达式的序号,x1,x2,... ...为该表达式的参数。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.11复数表达式中的表达式相互调用函数

11.11.1 计算指定序号的表达式的值 calfor(n,x1,x2,... ...)

    int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.11.2 计算指定序号的实数表达式的值 calrfor(n,x1,x2,... ...)

    int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数,所有参数均取复数的实部。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。

11.11.3 计算指定序号的整数表达式的值 califor(n,x1,x2,... ...)

    int(n)指出该表达式的序号,x1,x2,... ...为该表达式的参数,所有参数均取复数的实部的整数值。
    若fcerr=-1:未对可接受表达式的二级函数进行设置;fcerr=-2:直接或间接递归调用次数超出限制,可能是无穷递归调用;fcerr=1:指定的表达式不存在;fcerr=2:表达式未进行编译;fcerr=3:参数个数不匹配。


12 Forcal中的字符数据处理  [目录]

    前已述及,在两个双引号 "..." 之间的内容为字符串。FORCAL在编译表达式时,将表达式中的字符串用一个整数代替,这个整数即该字符串的地址,使用字符串的二级函数可以根据这个地址存取这些字符串。
    在编译时,对于以下几种字符串形式,FORCAL将作如下处理:
    "...":为该字符串开辟存储空间,并在表达式中用一个整数即该空间的地址代替该字符串;
若一个表达式中的首字符串为"char",则表明该表达式中的字符串为公用字符串,公用字符串可被@"..."描述符访问到;
    &"...":不为该字符串开辟存储空间,仅仅取同一个表达式中相同字符串的地址,如果在同一个表达式中没有相同的字符串,则返回一个出错信息,出错码为24;
    @"...":不为该字符串开辟存储空间,仅仅取公用区字符串(表达式中的首字符串为"char")中相同字符串的地址,如果公用区字符串中没有相同的字符串,则返回一个出错信息,出错码为24;
    $"...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的表达式中的第一个字符串,如果找到这个表达式,则取该表达式的类型(1为整型、2为实型、3为复型),否则返回一个出错信息,出错码为22。
    #"...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的相同类型的表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
    #"#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的表达式(可为任何类型)中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
    #"i#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的整数表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
    #"r#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的实数表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
    #"c#...":不为该字符串开辟存储空间,该字符串应为一个已经编译过的复数表达式中的第一个字符串“...”,如果找到这个表达式,则取该表达式的序号,否则返回一个出错信息,出错码为23。
    在前面我们用到#"...",它使FORCAL编译器在表达式中插入一个表达式的序号,即该表达式的名称。


13 Forcal中的数组  [目录]

    FORCAL中用一些函数管理和使用数组,这些数组是全局的,可被任何一个表达式访问到。关于这些函数请参考“Forcal使用说明”中的“全局变量及数组函数”。


14 效率及其他  [目录]

14.1 如何提高效率

    以下情况,可以提高FORCAL程序编译和执行的效率。
    (1)、将表达式中可以计算的部分用括号括起来;
    (2)、采用FORCAL表达式格式4表示的数学表达式的可优化形式;
    (3)、用表达式组合函数one[...]将多个表达式组合在一个表达式内;
    (4)、尽量用乘法运算代替乘方运算,例如要将 x^2 写成 x*x ;
    (5)、程序中多次用到的表达式和函数值要一次算好,用中间变量寄存,以避免不必要的重复计算;
    (6)、精心处理循环,特别是不受循环变量影响的计算,要放到循环体外;
    (7)、dowhile[]的速度比for[]的速度要快,必要时将for循环转换为dowhile循环;
    (8)、给变量增加一个值用mov函数比用赋值表达式更快;
    (9)、多用注释,提高程序的可读性。

14.2 FORCAL中的代码优化

    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的第二种代码优化可以保证表达式中的任何相同部分只进行一次计算,从而最大限度地提高了计算速度。

14.3 怎样用mov函数给自变量赋值

    (1)、将一个数3.5赋给自变量x:
      one[x, mov(3.5)] 或者 mov[3.5+(x-x)]
    (2)、将一个自变量的值x赋给另一个自变量y:
      mov[x+(y-y)]
    (3)、自变量x的值加1:
      mov[1+x]
    (4)、自变量x的值加一个计算式:
      mov[f(x,y,… …)+x]


15 例子  [目录]

例子1:简单的数值计算:

2+sin[2+3*sqrt(3)]*exp[5]; //实数表达式;
c:sin[2+3i]-ln[i]; //复数表达式;

例子2:变步长辛卜生一元积分:

"f"(x)=sin[x]+0.8; //定义一元函数;
simpintegrate(1,2,0.0001,#"f");

例子3:二元函数图象[须加载动态库扩展OpenFcGl.dll]

NewDoubleS[1];setd[0,0];//设置一个变量;
"DrawBegin";
glClear[];
glLoadIdentity[];
glTranslated[0,0,-20];
glRotated[getdadd(0,1),1,1,1];//使图象连续旋转;
glColor3d[0,1,0];
"f"(x,y)=(x^2-2*x)*exp(-x^2-y^2-x*y);
plot3d[#"f",-3,3,-3,3];
FindErrQuit[];//检查运行错误;
"DrawEnd";
DrawScene{GetAddress[$"DrawBegin",#"DrawBegin"],
          GetAddress[$"DrawEnd",#"DrawEnd"]
         };

例子4:有一组测定数据:0.105、0.115、0.115、0.116、0.116、0.128,求其平均值和标准偏差:

NewDoubleArrayS[1]; //申请一个数组;
NewDoubleArray[0,6,0.105,0.115,0.115,0.116,0.116,0.128]; //给数组赋初值;
"f"(x)=x; //定义计算平均值用到的函数;
DataArraySum(#"f",0,6,0)/6; //计算平均值;
"g"(x)=[x-DataArraySum(#"f",0,6,0)/6]^2; //定义计算标准偏差用到的函数;
sqrt{DataArraySum(#"g",0,6,0)/5}; //计算标准偏差;

例子5:实验测得x与y的关系如下表:

序号 1 2 3 4 5 6 7 8 9 10
X 22 34 39 43 46 54 58 64 67 72
Y 11 13 16 16 17 15 20 19 24 23

求其回归方程y=a*x+b及相关系数r?

NewDoubleArrayS[2]; //申请二个数组;
NewDoubleArray[0,10,22, 34,39,43,46,54,58,64,67,72]; //给数组0赋初值;
NewDoubleArray[1,10,11,13,16,16,17,15,20,19,24,23]; //给数组1赋初值;
"x"(x)=x; //定义函数1;
"xx"(x)=x^2; //定义函数2;
"xy"(x,y)=x*y; //定义函数3;

//以下表达式求系数a;
"a"()=[DataArraySum(#"xy",0,10,0,1)-DataArraySum(#"x",0,10,0)*DataArraySum(#"x",0,10,1)/10]/[DataArraySum(#"xx",0,10,0)-DataArraySum(#"x",0,10,0)^2/10];
//以下表达式求系数b;
DataArraySum(#"x",0,10,1)/10-calfor[#"a"]*DataArraySum(#"x",0,10,0)/10;
//以下表达式求相关系数r;
[DataArraySum(#"xy",0,10,0,1)-DataArraySum(#"x",0,10,0)*DataArraySum(#"x",0,10,1)/10]/sqrt{[DataArraySum(#"xx",0,10,0)-DataArraySum(#"x",0,10,0)^2/10]*[DataArraySum(#"xx",0,10,1)-DataArraySum(#"x",0,10,1)^2/10]};