通用的數學表示式編譯計算動態庫FORCAL.DLL (轉)

worldblog發表於2007-12-12
通用的數學表示式編譯計算動態庫FORCAL.DLL (轉)[@more@]

通用的數學編譯計算動態庫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,請從作者網站或者華軍軟體園/等">等站點。

正文:

--------------------------------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",""}; 和aa2a為兩個函式名;
  int n[]={1,0}; 表示有2個自變數,0表示有1個自變數;
  double (*fun[])(int ,double *)={asd,aa2a}; 和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、等高階語言中使用,用法參見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):如果x2.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。
  #"...":不為該字串開闢儲存空間,該字串應為一個已經編譯過的複數表示式中的第一個字串“...”,如果找到這個表示式,則取該表示式的序號,否則返回一個出錯資訊,出錯碼為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.? ! 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下載:
  作者主頁: 或  
  E-: 或 或

山東省工業學校工藝教研室(255070) 王 祿

2002.2-.10


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991861/,如需轉載,請註明出處,否則將追究法律責任。

相關文章