10 以外の基数で浮動小数点を計算するにはどうすればよいですか?
-
06-09-2019 - |
質問
ウィキペディアの記事を踏まえると、 基数点, 、10.1 に相当する 2 進数、または 17.17 に相当する 16 進数はどのように計算すればよいでしょうか?前者の場合、10 分の 1 に相当する 2 進法は何でしょうか?後者の場合、17/100 の 16 進数表現?
私はこれら 2 つの例に対する解決策よりもアルゴリズムを探しています。
解決
10 進数 10.1 を 2 進数に変換するには、整数部分と小数部分を分離し、それぞれを個別に変換します。
整数部分を変換するには、整数を 2 で除算し、剰余を逆の順序で書き込みます。
10/2 = 5 余り 0
5/2 = 2 余り 1
2/2 = 1 余り 0
1/2 = 0 余り 1
答え:1010
小数部を変換するには、2 の乗算を繰り返し、各ステップで整数部を減算します。整数部分は生成順に 2 進数を表します。
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
...(サイクルは永遠に繰り返される)
つまり、10進数の0.1は2進数の0.000110011001100...
(より詳細な説明については、私の記事のルーチン dec2bin_i() および dec2bin_f() を参照してください。 http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ .)
16 進数の場合は、除数/乗数を 2 ではなく 16 にする点を除き、同じ手順を使用します。9 を超える剰余と整数部分は、16 進数に直接変換する必要があります。10 は A になり、11 は B になり、..., 15はFになります。
他のヒント
基底Bにおける着信番号(ディジットの有限数で表すことができる数)N <サブ> 1 サブ> <サブ> 1 サブ>、非終了数で終わることができます異なる基底Bにおける 2 。逆に、一つの基地Bにおいて非終了数<サブ> 1 サブ>基底Bにおける着信番号であることが判明するかもしれ 2
進数に変換するとき0.17 <サブ> 10 であるように、数0.1 <サブ> 10 サブ>バイナリに変換されたとき、非終端番号です。しかし、10塩基に変換ベース3に着信番号0.1 <サブ> 3 サブ>非終端、番号0を繰り返す(3)<サブ> 10 サブ>(その数3反復を意味であります)。同様に、16進数にバイナリ0.17 <サブ> 10 サブ> 0.1 <サブ> 10 サブ>変換、一方が数値0.0(0011)を繰り返す、非終端で終わる 2 0.2(B851E)<サブ> 16 サブ>
別の基部からそのような数を変換する際に、このため、自分自身ではなく、完全に正確な表現を有するの数を近似する必要があります。
このアルゴリズムは非常に簡単ですが、実際には、あなたはそれをスピードアップするためにルックアップテーブルとログとの両方の調整の多くを行うことができます。 しかし、基本的なアルゴリズムのために、あなたはこのような何かを試すことがあります:
shift=0;
while v>=base, v=v/base, shift=shift+1;
Next digit:
if v<1.0 && shift==0, output the decimal point
else
D=floor(v)
output D
v=v-D
v=v*base
shift = shift-1
if (v==0) exit;
goto Next Digit
また、循環小数長くN桁の後に印刷を停止するには、そこにテストを置いてもよい。
10分の1 'バイナリ等価' が代わりに1/10 ^ 1のすなわち半分が、それは1/2 ^ 1です。
各桁は、2のべき乗を表します。小数点の後ろの数字が同じである、それは彼らが2の累乗の上に1を表していることだけです。
8 4 2 1 . 1/2 1/4 1/8 1/16
10.1だから、あなたは明らかに10の部分を作るために「8」と「2」が必要です。 1/2(0.5)が多すぎると、1/4(0.25)が1/8(0.125)が多すぎると、多すぎます。私たちは、0.0375で私たちを残している、1/16(0.0625)が必要です。 1/32は0.03125であるので、我々はあまりにもそれを取ることができます。これまでのところ、私たちは持っています:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32
1 0 1 0 0 0 0 1 1
0.00625のエラーで。 1/64(0.015625)と1/128(0.0078125)がともにあまり、1/256(0.00390625)に動作します:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256
1 0 1 0 0 0 0 1 1 0 0 1
0.00234375のエラーでます。
0.1は(1/3が正確に小数で表すことができないだけのような)バイナリで正確に表現できません。あなたの基数を置く場所にもよりますが、最終的には、おそらくラウンド、停止、およびエラーを受け入れなければならない。
、ここにあります。
Function dec2base_f(ByVal ddecimal As Double, ByVal nBase As Long, ByVal dscale As Long) As String
Const BASES = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 'up to base 36
Dim digitCount As Long
Dim wholeNumber As Double
Dim digit As String * 1
digitCount = 0
dscale = max(dscale, Len(CStr(ddecimal)) - Len("0."))
Dim baseary_f As String
baseary_f = "0."
Do While ddecimal > 0 And digitCount < dscale
ddecimal = ddecimal * nBase
digit = Mid$(BASES, Fix(ddecimal) + 1)
baseary_f = baseary_f & digit '"1"
ddecimal = ddecimal - Fix(ddecimal)
digitCount = digitCount + 1
Loop
dec2base_f = baseary_f
End Function
Function base2dec_f(ByVal baseary_f As String, nBase As Double) As Double
Const BASES As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim decimal_f As Double
Dim i As Long
Dim c As Long
For i = Len(baseary_f) To Len("0.") + 1 Step -1
c = InStr(BASES, Mid$(baseary_f, i, 1)) - 1
decimal_f = decimal_f + c
decimal_f = decimal_f / nBase
Next
base2dec_f = decimal_f
End Function
Debug.Print base2dec_f(dec2base_f(0.09, 2, 200), 2) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 8, 200), 8) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 16, 200), 16) --> 0.09