CやJavaで書かれた数値計算アルゴリズムをBASICに移植するのは,たいていの場合,さほど困難ではありません。
そのためには,JavaやCで書かれたプログラムの読み方を知っておくことが必要です。以下にその要点を示します。
C | Java | Full BASIC | 意味または補足 |
---|---|---|---|
double x,y; | double x,y; | DECLARE NUMERIC x,y | 倍精度実数型の変数宣言 |
int a,b; | int a,b; | DECLARE NUMERIC a,b | 整数型の変数宣言 |
static int a; | static int a; | SHARE NUMERIC a | 静的変数。Full BASICではモジュール本体に書く |
extern int a; | public static int a; | PUBLIC NUMERIC a | 静的変数。Full BASICではモジュール本体に書く |
#define N 1000 | final int N=1000; | LET N=1000 | 定数宣言。Full BASICでは変数で代用 |
printf("%g",a); | System.out.print(a); | PRINT a; | Cの%で始まる文字列は書式指定 |
printf("%g\n",a); | System.out.println(a); | PRINT a | Cの書式文字の\nは改行を意味する |
printf("a=%g\n",a); | System.out.println("a="+a); | PRINT "a=";a | Javaで文字列と数値の和は文字列連結を意味する |
scanf("%lf",&x); | String d1=in.readline(); x=Double.parseDouble(d1); | INPUT x | 倍精度実数型変数xへの入力 |
scanf("%d",&a); | String d2=in.readline(); a=Integer.parseInt(d2); | INPUT a | 整数型変数aへの入力 |
0xfff8 | 0xfff8 | BVAL("fff8",16) | 0x....は16進の定数 |
a=12; | a=12; | LET a = 12 | C,Javaでは,=は代入を意味する |
int a=12; | int a=12; | DECLARE NUMERIC a LET a = 12 | C,Javaでは,変数宣言と代入文を一度に書くことができる |
a+=12; | a+=12; | LET a = a + 12 | +=の他に,-=,*=,/=などがある |
a++; | a++; | LET a = a + 1 | 変数に1を加算 |
a=b++; | a=b++; | LET a = b LET b = b + 1 | aにbの値を代入後,bに1を加算 |
a=++b; | a=++b; | LET b = b + 1 LET a = b | bに1を加算後,aに代入 |
a=b=c=12; | a=b=c=12; | LET a,b,c=12 | CやJavaの代入文は代入された結果を値として持つ |
a / b | a / b | a/b または IP(a/b) | a,bが整数型のとき,a / b は整数除算の商 |
a % b | a % b | REMAINDER(a,b) | a,bが整数型のとき,a % b は整数除算の余り |
a & 1 | a & 1 | MOD(a,2) | a & 1 は整数aの最下位ビットを意味する |
a & b | a & b | BITAND(a,b) (注1) | & はビット演算のAND (補足4参照) |
a | b | a | b | BITOR(a,b) (注1) | | はビット演算のOR (補足4参照) |
a ^ b | a ^ b | BITXOR(a,b) (注1) | ^ はビット演算のXOR (補足4参照) |
~a | ~a | -1-a | ~ はビット反転 |
a << n | a << n | a*(2^n) | aをnビット左シフトした数 |
a >> n | a >> n | IP(a/(2^n)) | aをnビット右シフトした数 |
floor(x) | Math.floor(x) | INT(x) | |
fmod(x,y) | Math.fmod(x,y) | REMAINDER(x,y) | xをyで割った余り。結果はxと同符号。 |
sqrt(x) | Math.sqrt(x) | SQR(x) | |
atan(x) | Math.atan(x) | ATN(x) | |
atan2(y,x) | Math.atan2(y,x) | ANGLE(x,y) | atan2とANGLEとでは引数の順番が逆 |
fabs(x) | Math.abs(x) | ABS(x) | |
pow(x,y) | Math.pow(x,y) | x^y | |
double a[15]; | double[] a=new double[15]; | DIM a(0 TO 14) | C,Javaの配列添字は0で始まる |
a[n] | a[n] | a(n) | 配列aのn番目の要素 |
int b[5][4]; | int[][] b=new int[5][4]; | DIM b(0 TO 4, 0 TO 3) | 2次元配列(整数型) |
a[m][n] | a[m][n] | a(m,n) | 2次元配列の要素 |
a==b | a==b | a = b | 相等 |
a!=b | a!=b | a <> b | 非等 |
!p | !p | NOT p | 否定 |
p && q | p && q | p AND q | pかつq。pが偽ならqを評価しない |
p || q | p || q | p OR q | pまたはq。pが真ならqを評価しない |
if(条件){…}else{…} | if(条件){…}else{…} | IF 条件 THEN … ELSE … END IF | |
a=(条件)?式1:式2; | a=(条件)?式1:式2; | IF 条件 THEN LET a=式1 ELSE LET a=式2 | |
for(i=0;i<n;i++){…} | for(i=0;i<n;i++){…} | LET i=0 DO WHILE i<n … LET i=i+1 LOOP | ループの実行でnの値が変化しなければ, FOR i=0 TO n-1 … NEXT i でもよい |
for(;;){…} | for(;;){…} | DO … LOOP | |
while(条件){…} | while(条件){…} | DO WHILE 条件 … LOOP | |
while(i--){…} | while(i-->0){…} | DO WHILE i>0 LET i=i-1 … LOOP | Cでは非ゼロが真を意味する |
while(--i){…} | while(--i>0){…} | DO LET i=i-1 IF i=0 THEN EXIT DO … LOOP | |
while(1){…} | while(true){…} | DO … LOOP | |
do {…} while(条件); | do {…} while(条件); | DO … LOOP WHILE 条件 | |
break; | break; | EXIT DO または EXIT FOR | breakは最も内側のループからの脱出 |
while(…){ … if(条件)continue; … } | while(…){ … if(条件)continue; … } | DO WHILE … … IF NOT 条件 THEN … END IF LOOP | continueは,NEXT文,LOOP文へのGOTOに相当する。 左の形にならないときはGOTO文を使う。 |
switch (式){ case 1: … break; case 2: … break; default: … } | switch (式){ case 1: … break; case 2: … break; default: … } | SELECT CASE 式 CASE 1 … CASE 2 … CASE ELSE … END SELECT | 2個目以降のcaseラベルおよびdefault:の直前が break;であればSELECT CASEに書き換えられる。 そうでないときはcaseラベルを越えて先に進む。 その場合は個別に書き換え方を工夫する。 |
switch (式){ case 1: … break; case 2: … } | switch (式){ case 1: … break; case 2: … } | SELECT CASE 式 CASE 1 … CASE 2 … CASE ELSE END SELECT | Full BASICでは,一致するCASE項目がない場合, CASE ELSEを省けないことに注意 |
double abc(double x) { … return(式) … return(式) } | static double abc(double x) { … return(式) … return(式) } | EXTERNAL FUNCTION abc(x) … LET abc=式 EXIT FUNCTION … LET abc=式 END FUNCTION | return();は関数値を与え,関数から抜ける |
void xyz(int a) { … } | static void xyz(int a) { … } | EXTERNAL FUNCTION xyz(a) … END FUNCTION | 値を持たない関数も関数定義に書き換えて, 呼出し側はダミーの変数への関数値代入にする。 引数の値が関数内で変更されない場合は, 副プログラムに書き換えてもよい。 |
void xyz(int a[]) { … } | static void xyz(int[] a) { … } | EXTERNAL SUB xyz(a()) … END SUB | C,Javaで配列引数は,実質,参照渡しになるので, BASICでは副プログラムにする。 |
double f(double x[]) { … } |
static double f(double[] x) { … } |
EXTERNAL FUNCTION f(x()) … END FUNCTION | 値を持つ関数の場合は,関数内で 配列値を変えていなければ関数定義にする。 |
注1. JIS規格外の十進BASIC独自拡張 (Ver. 7.5.4以降)
補足1
CやJavaは識別名の大文字と小文字の違いが意味を持つ。そのため,大文字と小文字の違いを無視すると同じになってしまう識別名が存在する場合は,識別名の変更が必要になる。
補足2
CやJavaでは浮動小数点演算の桁あふれは例外状態を引き起こさない(停止しない)。そのため,Full BASICに移植した場合は,適切な例外状態処理を追加しなければ正常に動作しないことがある。
補足3
Cでは,比較演算,論理演算の結果が真であると1,偽であると0の値を持つ。
逆に,条件として数値式を書くと,非ゼロは真,0は偽と解釈される。
例
a=(x>1)+(x>2);
は,Full BASICで
LET a=0 IF x>1 THEN LET a=a+1 IF x>2 THEN LET a=a+1
と同等。
C,Javaの&&,||は,Full BASICのAND,ORと同様に短絡評価を行う。それに対して,&,|を完全評価の論理演算の意味で用いることができる。だから,どちらの意味に解釈しても結果に差がでないような場合,たとえば,if ( 0<=x & x<1 ) あるいは if ( 0<=x && x<1 ) は,どちらも,IF 0<=x AND x<1 THEN に翻訳してしまってかまわない。
if (--a || --b) のような条件は書き換えに注意が必要。この場合,aの値が0でないときはbの値を変えてはいけない。もしif (--a | --b) だったら,条件のテストを行う前に,a,bどちらも1ずつ減じておけばよい。
補足4
ビット演算の&,|,^ をFull BASICで実現するのは面倒。たとえば,次のような外部関数定義を用意する。
EXTERNAL FUNCTION bitwiseAND(a,b) DECLARE NUMERIC aa, bb DECLARE NUMERIC i,c LET c=0 FOR i=0 TO 31 LET aa=MOD(a,2) LET a=(a-aa)/2 LET bb=MOD(b,2) LET b=(b-bb)/2 LET c=c+MIN(aa,bb)*2^i NEXT i IF c>=2^31 THEN LET c=c-2^32 LET bitwiseAND=c END FUNCTION
MIN(aa,bb)の部分は,|のときはMAX(aa,bb)に,^のときはMOD(aa+bb,2)に変える。
ただし,a & 7 はMOD(a,8),a & 0xfff8 は INT(a/8)*8 など,算術演算で代用できる場合も多い。
補足5
Cでstatic変数が関数の内側で宣言されている場合,その変数宣言は関数定義または副プログラムの外に移す。
例
C | Full BASIC |
---|---|
double abc(double a) { static int s; …… } |
MODULE m PUBLIC FUNCTION abc SHARE NUMERIC s LET s=0 EXTERNAL FUNCTION abc(a) …… END FUNCTION END MODULE |
補足6
Full BASICはポインタを扱うことができない。
Cでは変数を参照渡しにする目的でポインタを使う場合があるが,その場合は,副プログラムの変数引数を使えばよい。
例
C | Full BASIC | |
---|---|---|
double a,b; swap(&a,&b); | CALL SWAP(a,b) | &aは変数aのアドレス |
void swap(double *x, double *y) { double t=*x; *x=*y; *y=t; } | EXTERNAL SUB SWAP(x,y) LET t=x LET x=y LET x=y END SUB | double *x は,double型へのポインタxの宣言 *xはxが参照するdouble型の変数 |
値を持つ関数がポインタ型の引数も持つ場合は厄介。ただし,値を受け取るだけならそのまま関数でよい。
値を返すために使っている場合は,静的な変数で代用できるなら,モジュールのSHARE変数にして引数から外す。
動的に確保しなければならない変数だったら,値を返すための引数を追加して副プログラムに変える。
Cでは関数へのポインタを扱うこともできるが,そのようなプログラムをFull BASICに移植するのは難しい(汎用の関数にはできない)。
補足7
Full BASICには手続きの再帰呼び出し以外には動的に変数を確保する手段がない。動的に変数を確保する必要がある場合は,配列で代用する。
また,Full BASICにはCの構造体に対応する概念がない。構造体がでてきたら,細かく分けて書き換える。