進法の変換 |
現在私たちが,普通に使う数記法は位取り十進法と言われているものですが,それ以外の進法が使われることもあります。例えば,16進法はコンピュータでよく使われています。
ここでは, 進法の変換を行うプログラムを挙げます。2進法や16進法についての説明はホームページでの”2・8・16進法の計算”をご覧下さい。
n進法の1桁をどのような記号で表すかは一般的には厳密な決まりはありません。そこでここでは次のように表されているとします。
nが10以下の場合,1桁の数字は普通の数字を使うことにします。nが11以上の場合,10はAで表し,,11はB で表すとして,以下同様にアルファベットを1桁の数に割り当てます。(これは16進法で使われている方法の自然な拡張です。)
この場合,使える最大はZでこれは,この方法では 35を表しますから,以下扱う進法の最大は36進法です。
n進法表示 |
そこで,n≦36として,n進法で表された数aを10進法で表すことを考えます。小数も扱うことにします。このとき,aは
a=amnm+・・・+a1n+a0+b1n-1+b2n-2+・・・+bsn-s
但し ,am≠0でaiとbjは0からn-1までの正整数
と表されています。この数を
am・・・a1a0.b1b2・・・ bs
と表して,aのn進法表示と言います。このように表された数を,10進法での表し方に変換するのが,ここでの目的です。
Basic で扱う数の表し方は10進法ですから,それ以外の進法で表された数は,Basic での数としては扱えません。そこで,文字列として考えます。ですから,
am・・・a1a0.b1b2・・・ bs
を文字列
"am・・・a1a0.b1b2・・・ bs"
として扱うわけです。以下n進法での数はこのように表されているとします。この文字列を InStr$ と表すとすると,各桁(小数点も含む)は,
Mid$(InStr$,i,1)
で表すことができます。
n進法から10進法への変換 |
まず,整数を考えましょう。n進法で表された整数aの10進法へ変換を考えます。aを表す文字列 InStr$ を
"am・・・a1a0.b1b2・・・ bs"
とします。これを10進法で表すにはInStr$ の各桁を表す数をそれぞれ10進法で表し,niを乗じてれらを加えれば良いだけです。niはnのi乗ですから n^i で計算できます。しかし,これを計算して,aiに乗じないで,1桁ずらすごとに,nを乗じて最終的にn^iたを掛けたことにするほうが効率的です。 つまり,
amnm+・・・+a1n+a0= (・・・((amn+am-1)n+am-2)n+・・・)n+a0
と計算します。(・・・ ・・・)を In とし,aiを Digit として繰り返しの形に書くと,
In = In*n + Digit
と書けます。簡単な式です。
aiは10以上の場合,アルファベットで表されていますから,少しだけ注意が必要です。は上の規則から, aiを表す文字をDch$とすると,aiの表す10進数としての数Digitは次のようにして求められます。
If Asc(Dch$)>=Asc("A") then Digit = Asc(Dch$) - Asc("A") + 10 Else Digit = Asc(Dch$) - Asc("0") End If
これに注意すると,n進法で表された,数 InStr$ を10進法の数として返す関数 n2d は次のようになります。
Function n2d(InStr$,n):' n進から 10 進へ(正整数のみ) In=0 For i=1 to Len(InStr$) If Asc(Dch$)>=Asc("A") then Digit = Asc(Dch$) - Asc("A") + 10 Else Digit = Asc(Dch$) - Asc("0") End If In = In*n + Digit Next i n2d=In End Function
次に,小数も扱えるようにしましょう。小数点があった以後はbjn-jを加えて行きます。小数点の右側と左側の処理が異なりますから,それを示すフラグ(フラグは何かを判定する標識といった意味です。)を使います。それを PFlag としましょう。PFlga=0 のとき,左側, PFlag=1のとき,右側とします。初期値は PFlag=0 として,小数点が来たら, PFlag=1 とします。小数点何位にあるかをしめす変数を Ctr とします。
このことを考慮して,上のプログラムを書き換えると,次が得られます。
Function n2d(InStr$,n):' n進から 10 進へ In=0 PFlag = 0 For i=1 to Len(InStr$) DCh$ = UCase$(Mid$(InStr$,i,1)) If DCh$="." then PFlag = 1 : Ctr = 1 If Asc(Dch$)>=Asc("A") then Digit = Asc(Dch$) - Asc("A") + 10 Else Digit = Asc(Dch$) - Asc("0") End If Select Case PFlag Case 0 : In = In*n + Digit Case 1 : In = In + Digit/n^(Ctr) Ctr = Ctr + 1 End Select Next i n2d=In End Function
ここで,
DCh$ = UCase$(Mid$(InStr$,i,1))
は,入力文字列が小文字でも正しく計算できるように,常に大文字で考えるようにしたものです。
この関数は,
Print n2d("abc",16)
のように使うことが出来ます。これは ABC で表される16進数を10進数で表した結果を表示します。
10進法からn進法への変換 |
次に逆の処理を考えましょう。まず整数です。整数aをn進法で書くには,
a=amnm+・・・+a1n+a0
のを求めればよいわけですが,
a=(amnm-1+・・・+a1)n+a0
とすると,
a0=a mod n
(amnm-1+・・・+a1)=a ¥ n
で求められます。この処理を下の桁から繰り返せば,aをn進法で表すことが出来ます。
従って,整数a をn進法で表すプログラムは
While a >= n OutD = InInt mod n OutStr$=nDigit$(OutD)+OutStr$ a = a \ n Wend
となります。ここで,nDigitは1桁の数を1桁記号の文字に変換する関数で,
Function nDigit$(In) :' 1桁の数を返す 例:10-->"A" If In>9 then nDigit$ = Chr$(In-10+Asc("A")) Else nDigit$ = Chr$(In+Asc("0")) End if End Function
で与えられます。
次に小数をn進法で表しましょう。
a=b1n-1+b2n-2+・・・+bsn-s
であるとき,b1は簡単に分かります。即ち,b1=(anの整数部分)で与えられます。従ってこれを繰り返せば,b1,b2,b3, ・・・が計算できます。
ここで小数のn進法で注意することが1つだけあります。上の操作はいくらでも繰り返すことが出来ます。そして,多くの場合,0でないbiが無限に出てきます。ですから,何桁で終わるかを指定する必要がありあます。
そこで,例えば,小数以下DSize だけ表すとして,プログラムにすると,
OutStr$="0." For i=1 to DSize a = a*m OutD = Int(a) OutStr$ = OutStr$ + nDigit$(OutD) a = a - OutD Next i
となります。以上を纏めると
Function D2n$(In, n) :' 10 進 In を から n進へ OutStr$="" InInt = Int(In) InDec = In - InInt While InInt >= n OutD = InInt mod n OutStr$=nDigit$(OutD)+OutStr$ InInt = InInt \ n Wend OutD = InInt mod n OutStr$=nDigit$(OutD)+OutStr$ If InDec > 0 then OutStr$ = OutStr$ + "." For i=1 to DSize InDec = InDec*n OutD = Int(InDec) OutStr$ = OutStr$ + nDigit$(OutD) InDec = InDec - OutD Next i End if D2n$ = OutStr$ End Function
となります。この関数は,
Print D2n$(123, 12)
のように使うことが出来ます。これは 123を12進数で表した結果を表示します。
まとめ |
以上のプログラムを纏めたものが Bin.tbt です。