8

2進法で表された数値を3進法に変換する方法またはアルゴリズム(私の特定のケース)、またはそのような変換のための普遍的なアルゴリズムを知っている人はいますか?

私がすでに実装した解決策は、最初に数値を 10 進数に変換してから、必要な数値システムに変換することです。これは機能しますが、2 つの手順があります。最初に三項演算を実装しなくても、ワンステップで簡単に実行できるのだろうか? 何かトリックはありますか?

UPD:探している変換方法を明確に説明できなかったようです。基数 2 を基数 3 に変換する方法を求めているわけではありませんこれを行う方法は知っています。私は 3 進数と 2 進数の代数データ構造を持っていると思うかもしれませんが、Haskell では次のようになります。

data BDigit = B0 | B1
type BNumber = [BDigit]

data TDigit = T0 | T1 | T2
type TNumber = [TDigit]

1 つ目は、最初に整数に変換して結果を取得する方法です (興味深い方法ではありません)。それぞれ 2 のべき乗 (単純で重い)。

そこで、この2つ以外の方法はないかと考えています。

4

9 に答える 9

6

コンピューターでそれを行う場合、物事は既に 2 進数で行われているため、3 で割って剰余を取ることを繰り返すだけで、物事が得られるのと同じくらい簡単です。

手動で行う場合、2 進数の長除算は 10 進数の長除算と同じように機能します。3で割って余りを取るだけです。16から始めると

   ___101
11 |10000
     11
      100
       11
        1   

100000 / 11 = 101 + 1/11 so the least significnnt digit is 1

101/ 11 = 1 + 10/11  the next digit is 2

1  and the msd is 1

三進法で 121

于 2010-08-03T20:21:52.207 に答える
3

誰もが何か重要なものを見逃していると思います。まず、事前にテーブルを計算します。バイナリビットごとに、3値での表現が必要です。MATLABでは、このように構築しましたが、それ以降のすべてのステップは純粋に手作業で実行されますが、計算は非常に簡単です。

dec2base(2.^(0:10),3)
ans =
0000001
0000002
0000011
0000022
0000121
0001012
0002101
0011202
0100111
0200222
1101221

ここで、2進数011000101(後でわかるように、たまたま10進数197になります)について考えます。テーブルから各2進数ビットの3進数表現を抽出します。対応する行を書き出します。

0000001 
0000011
0002101
0011202

今ちょうど合計。運ばれていない三元で、この表現を取得します。

0013315

はい、これらは3進数ではありませんが、ほぼ有効な基数3の表現になっています。今あなたがする必要があるのはキャリーをすることです。単位の桁から始めます。

5は2より大きいので、3の倍数の数を減算し、必要に応じて結果の2桁目をインクリメントします。

0013322

2桁目は2になり、有効な3進数なので、3桁目に進みます。それも運びますか

0014022

最後に、現在完全に有効な3進数を生成します...

0021022

私の計算は正しかったですか?MATLABに最終的な判断を任せます。

base2dec('011000101',2)
ans =
   197

base2dec('0021022',3)
ans =
   197

この操作がいかに簡単であるかを指摘しましたか?少なくとも最初のテーブルを書き留めて保存すると、完全に手動で変換を実行でき、基本的に2進数から3進数に直接変換できますか?

于 2010-08-04T10:25:35.187 に答える
3

変換には、いくつかの巧妙な省略形を使用できます。次のコードは「間違った」方向です。これは、2 進加算のみを使用して 3^2 = 2^3 + 1 という事実に基づいて、3 進から 2 進に変換したものです。基本的には、3 桁の 2 桁を 2 進数の 3 桁に変換しています。2 進数から 3 進数への変換は、3 進数の加算 (およびおそらく減算) が必要になるため、少し複雑になります (それに取り組んでいます)。リストの先頭にある最下位桁を想定しているため (これが唯一の意味のある方法です)、数字を「逆方向」に読む必要があります。

addB :: BNumber → BNumber → BNumber
addB a [] = a
addB [] b = b
addB (B0:as) (B0:bs) = B0 : (addB as bs) 
addB (B0:as) (B1:bs) = B1 : (addB as bs)
addB (B1:as) (B0:bs) = B1 : (addB as bs)
addB (B1:as) (B1:bs) = B0 : (addB (addB as bs) [B1])

t2b :: TNumber → BNumber
t2b [] = []
t2b [T0] = [B0]
t2b [T1] = [B1]
t2b [T2] = [B0,B1]
t2b (T2:T2:ts) = let bs = t2b ts in addB bs (B0:B0:B0:(addB bs [B1]))
t2b (t0:t1:ts) = 
   let bs = t2b ts
       (b0,b1,b2) = conv t0 t1
   in addB bs (b0:b1:b2:bs) 
   where conv T0 T0 = (B0,B0,B0)
         conv T1 T0 = (B1,B0,B0)
         conv T2 T0 = (B0,B1,B0)
         conv T0 T1 = (B1,B1,B0)
         conv T1 T1 = (B0,B0,B1)
         conv T2 T1 = (B1,B0,B1)
         conv T0 T2 = (B0,B1,B1)
         conv T1 T2 = (B1,B1,B1)

[編集] これはバイナリからターナリへの方向です。予想通り、もう少し長くなります。

addT :: TNumber → TNumber → TNumber
addT a [] = a
addT [] b = b
addT (T0:as) (T0:bs) = T0 : (addT as bs) 
addT (T1:as) (T0:bs) = T1 : (addT as bs)
addT (T2:as) (T0:bs) = T2 : (addT as bs)
addT (T0:as) (T1:bs) = T1 : (addT as bs) 
addT (T1:as) (T1:bs) = T2 : (addT as bs)
addT (T2:as) (T1:bs) = T0 : (addT (addT as bs) [T1])
addT (T0:as) (T2:bs) = T2 : (addT as bs)
addT (T1:as) (T2:bs) = T0 : (addT (addT as bs) [T1])
addT (T2:as) (T2:bs) = T1 : (addT (addT as bs) [T1])

subT :: TNumber → TNumber → TNumber
subT a [] = a
subT [] b = error "negative numbers supported"
subT (T0:as) (T0:bs) = T0 : (subT as bs) 
subT (T1:as) (T0:bs) = T1 : (subT as bs)
subT (T2:as) (T0:bs) = T2 : (subT as bs)
subT (T0:as) (T1:bs) = T2 : (subT as (addT bs [T1])) 
subT (T1:as) (T1:bs) = T0 : (subT as bs)
subT (T2:as) (T1:bs) = T1 : (subT as bs)
subT (T0:as) (T2:bs) = T1 : (subT as (addT bs [T1]))
subT (T1:as) (T2:bs) = T2 : (subT as (addT bs [T1]))
subT (T2:as) (T2:bs) = T0 : (subT as bs)

b2t :: BNumber → TNumber
b2t [] = []
b2t [B0] = [T0]
b2t [B1] = [T1]
b2t [B0,B1] = [T2]
b2t [B1,B1] = [T0,T1]
b2t (b0:b1:b2:bs) = 
   let ts = b2t bs
       (t0,t1) = conv b0 b1 b2
   in subT (t0:t1:ts) ts
   where conv B0 B0 B0 = (T0,T0)
         conv B1 B0 B0 = (T1,T0)
         conv B0 B1 B0 = (T2,T0)
         conv B1 B1 B0 = (T0,T1)
         conv B0 B0 B1 = (T1,T1)
         conv B1 B0 B1 = (T2,T1)
         conv B0 B1 B1 = (T0,T2)
         conv B1 B1 B1 = (T1,T2)

[Edit2] addT を必要としない、subT のわずかに改良されたバージョン

subT :: TNumber →  TNumber →  TNumber
subT a [] = a
subT [] b = error "negative numbers supported"
subT (a:as) (b:bs) 
  | b ≡ T0 = a : (subT as bs)
  | a ≡ b =  T0 : (subT as bs)
  | a ≡ T2 ∧ b ≡ T1 =  T1 : (subT as bs)
  | otherwise = let td = if a ≡ T0 ∧ b ≡ T2 then T1 else T2 
                in td : (subT as $ addTDigit bs T1)  
    where addTDigit [] d = [d]
          addTDigit ts T0 =  ts
          addTDigit (T0:ts) d = d:ts 
          addTDigit (T1:ts) T1 = T2:ts
          addTDigit (t:ts) d = let td = if t ≡ T2 ∧ d ≡ T2 then T1 else T0
                               in td : (addTDigit ts T1)
于 2010-08-04T06:45:28.740 に答える
1

残念ながら、これをコードで表現できる十分な Haskell の知識はありませんが、多項式を評価するためにホーナーの規則を使用するとメソッドが得られるのではないかと思います。

たとえば、a x^2 + b x + c は c+x*(b+x*a) として評価できます。

たとえば、3 進数 a*9+b*3+c を 2 進数に変換するには、a の 2 進数表現から始めて、それを 3 倍し (つまり、シフトして加算)、次に b の 2 進数表現を加算し、乗算します。結果に 3 を加え、c を追加します。

これは、マップ(3進数のバイナリ表現を取得するため)とフォールド(a、b -> a + 3 * b)で実行できるようです

于 2010-08-04T09:46:15.193 に答える
0

これが宿題の場合x、ベースをb逆方向に書き込むための擬似コード:

while (x != 0) {
    q <-- x/b
    r <-- x - q*b
    print r
    x <-- q
}

結果を逆方向ではなく順方向に書き込む方法を理解できると確信しています。Cスタイルの整数除算である必要があることに注意してください/(結果は整数であり、ゼロに向かって切り捨てられます)。

これは、算術が実行されるベースにまったく依存しないことに注意してください。算術は、特定のベースの整数の表現ではなく、整数で定義されます。


編集:あなたの更新された質問に基づいて、私は数字表現を整数に叩きつけ(orsとshiftsを介して)、整数演算で上記のアルゴリズムを使用します。

確かにあなたが説明するようにそれを行うことができますが、それは非常に多くの作業のようです。

于 2010-08-03T20:45:31.307 に答える
0

問題については、いくつかの異なる「見方」があると思いますが、それらのいずれかがより高速または優れているかどうかはわかりません。たとえば、n の下位 3 進数は n mod 3 です。すでに n のバイナリ表現があるとします。次に、2 のべき乗が 3 を法としてどのように機能するかを考えてみましょう。 、べき乗は 1 mod 3 と 2 mod 3 の間で交互になります。これで、n のバイナリ表現をスキャンし、通常は各ビット位置で 1 または 2 のいずれかを加算するだけで、下位の 3 進数を取得する簡単な方法が得られます。 1 が発生する場所。

于 2010-08-04T01:51:39.340 に答える
0

超効率的な方法はないと思います。

「私がすでに実装した解決策は、最初に数値を 10 進数に変換することです。」

最初に組み込みの整数型に実際に変換していると思います。組み込みの整数が基数 10 とは何の関係もないと思います (ただし、印刷すると基数 10 の変換が行われます)。

おそらく、一度に 1 桁の入力を見て出力を生成するアルゴリズムがあると思うでしょう。

しかし、3486784400 (基数 10) を基数 3 に変換したいとします。出力を生成する前に、すべての桁を調べる必要があります。

3486784401 (base 10) = 100000000000000000000 (base 3)
3486784400 (base 10) =  22222222222222222222 (base 3)

..また

「数字の値をそれぞれ 2 の累乗に掛けた結果を計算する」

累乗を明示的に計算する必要はありません。基数 60 から基数 10 への変換を参照してください。

于 2010-08-03T21:14:51.177 に答える
0

いいえ、base2 の数値を整数に読み込まずに base3 の数値に変換することはできません。その理由は、2 と 3 が互いに素であるためです。これらには公約数がありません。

base2 と base4、または base6 と base9 を使用している場合、2 つの基数の最小公倍数までの整数のセットは、2 つの同型集合で表されます。たとえば、13 (base4) = 0111 (base2) を変換すると、1313 (base4) = 01110111 (base2) になります。これは、検索と置換の操作です。

少なくとも、あなたが持っている解決策は機能し、比較的単純です。パフォーマンスを向上させる必要がある場合は、base3 変換を開始する前に、base2 表現全体を整数に変換してください。これはモジュラス操作が少ないことを意味します。別の方法は、base2 数値の各文字を 1 つずつ処理することです。この場合、base2 表現の各桁を 3 のべき乗で除算します。

于 2010-08-04T09:59:09.820 に答える