Двоичный файл к троичному преобразованию представления

Кто-либо знает (или может указать на некоторый источник для чтения о), метод или алгоритм для преобразования числа, представленного в двоичной системе счисления в троичную (мой особый случай), или универсальный алгоритм для таких преобразований?

Решение, которое я уже реализовал, состоит в том, чтобы преобразовать число в десятичное число сначала и затем преобразовать его в необходимую систему счисления. Это работает, но существует два шага. Интересно, могло ли это быть сделано за один шаг легко, не реализовывая троичную арифметику сначала? Есть ли некоторый прием, парни?

UPD: кажется, что мне не удалось описать ясно, какой способ преобразования я ищу. Я не прошу некоторый способ преобразовать основу 2 для базирования 3, я действительно знаю, как сделать это. Можно полагать, что у меня есть алгебраические структуры данных для троичных и двоичных чисел, в Haskell это похоже на это:

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

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

И существует два очевидных способа преобразовать тот в другого: сначала должен преобразовать его в Целое число сначала и получить результат (не интересный путь), второй должен реализовать собственное умножение и дополнение в основе 3 и вычислить результат, умножающий значения цифры к соответствующему питанию два (простой и тяжелый).

Таким образом, я задаюсь вопросом, существует ли другой метод, чем эти два.

8
задан Cœur 5 April 2018 в 11:48
поделиться

8 ответов

Вы можете использовать несколько умных сокращений для преобразования. Следующий код - это «неправильное» направление, это преобразование из троичного в двоичный, основанное на том факте, что 3 ^ 2 = 2 ^ 3 + 1 с использованием только двоичного сложения. В основном я конвертирую две троичные цифры в три двоичных. Переход от двоичного к троичному будет немного сложнее, так как потребуется тройное сложение (и, вероятно, вычитание) (над этим мы работаем). Я предполагаю, что в заголовке списка находится наименее значимая цифра (это единственный способ, который имеет смысл), поэтому вы должны читать числа «в обратном порядке».

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)

[Edit] Вот направление двоичного кода в троичное, как и ожидалось, немного длиннее:

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] Немного улучшенная версия subT, которая не требует addT

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)
3
ответ дан 5 December 2019 в 12:54
поделиться

Если вы делаете это на компьютере, все уже представлено в двоичном формате, поэтому просто многократное деление на 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

6
ответ дан 5 December 2019 в 12:54
поделиться

Я думаю, что всем не хватает чего-то важного. Во-первых, заранее вычислите таблицу, для каждого двоичного бита нам потребуется троичное представление. В MATLAB я построил его так, хотя каждый следующий шаг после этого будет выполняться вручную, вычисления настолько просты.

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

Теперь рассмотрим двоичное число 011000101 (которое оказывается десятичным числом 197, как мы узнаем позже). Извлеките троичное представление для каждого двоичного бита из таблицы. Выпишу соответствующие строки.

0000001 
0000011
0002101
0011202

Теперь просто суммируйте. Мы получаем это представление в непереносимой троичной системе.

0013315

Да, это не троичные числа, но они почти в корректном представлении с основанием 3. Теперь все, что вам нужно сделать, это сделать перенос. Начните с цифры единиц.

5 больше 2, поэтому отнимите количество, кратное 3, и увеличьте вторую цифру результата соответствующим образом.

0013322

Теперь вторая цифра равна 2, законной троичной цифре, поэтому переходите к третьей цифре. Сделайте и этот перенос,

0014022

Наконец, получив теперь полностью верное троичное число ...

0021022

Были ли мои вычисления правильными? Я позволю MATLAB вынести окончательное решение за нас:

base2dec('011000101',2)
ans =
   197

base2dec('0021022',3)
ans =
   197

Я указал, насколько тривиальной была эта операция, что я мог выполнить преобразование полностью вручную, переходя по существу напрямую от двоичного кода к троичному, по крайней мере, когда я получил это начальная таблица записана и сохранена?

3
ответ дан 5 December 2019 в 12:54
поделиться

Если это домашнее задание, псевдокод для записи x в базе b в обратном порядке:

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

Я уверен, что вы можете понять, как напишите результат вперед, а не назад. Обратите внимание, что / должно быть целочисленным делением в стиле C (результат - целое число, усеченное до нуля).

Обратите внимание, что это не зависит вообще от базы, на которой выполняется арифметика. Арифметика определяется на целых числах, а не на представлении целых чисел в определенной базе.


Изменить: Основываясь на вашем обновленном вопросе, я бы преобразовал цифровое представление в целое число (с помощью или и сдвигов) и использовал алгоритм, описанный выше, с целочисленной арифметикой.

Конечно, вы могли бы сделать это так, как вы описываете, но это похоже на ужасно много работы.

0
ответ дан 5 December 2019 в 12:54
поделиться

Боюсь, я не знаю достаточно языка Haskell, чтобы выразить это в коде, но мне интересно, может ли использование правила Хорнера для оценки многочленов дать метод.

Например, ax^2 + bx + c может быть оценено как c+x*(b+x*a).

Чтобы преобразовать, скажем, троичное число a*9+b*3+c в двоичное, нужно начать с двоичного представления a, затем умножить его на 3 (т.е. сдвинуть и сложить), затем сложить двоичное представление b, умножить результат на 3 и добавить c.

Мне кажется, это можно сделать с помощью карты (чтобы получить двоичное представление троичных цифр) и сложения (a,b -> a+3*b)

1
ответ дан 5 December 2019 в 12:54
поделиться

Нет, вы не можете преобразовать число base2 в число base3, не загружая его в целое число. Причина в том, что 2 и 3 являются простыми - у них нет общих множителей.

Если бы вы работали с основаниями 2 и 4, или даже с основаниями 6 и 9, то набор целых чисел до наименьшего общего кратного этих двух оснований был бы представлен двумя изоморфными наборами. Например, 13 (основание4) = 0111 (основание2), поэтому преобразование 1313 (основание4) = 01110111 (основание2) - это операция поиска и замены.

По крайней мере, решение, которое вы имеете, работает и является относительно простым. Если вам нужно повысить производительность, преобразуйте все представление base2 в целое число перед началом преобразования base3; это означает меньше операций с модулями. Альтернативой может быть обработка каждого символа в числе base2 по одному, в этом случае вы будете делить на все степени 3 для каждой цифры в представлении base2.

0
ответ дан 5 December 2019 в 12:54
поделиться

Я думаю, что могут быть разные "взгляды" на проблему, хотя я не уверен, что какие-то из них быстрее или лучше. Например, цифра n по основанию 3 младшего разряда равна n по модулю 3. Допустим, у вас уже есть двоичное представление числа n. Затем рассмотрим, как степени двойки работают по модулю 3. 2 ^ 0 = 1 по модулю 3, 2 ^ 1 = 2 по модулю 3, 2 ^ 2 = 1 по модулю 3, 2 ^ 3 = 2 по модулю 3, ... Другими словами , степени чередуются между 1 по модулю 3 и 2 по модулю 3. Теперь у вас есть простой способ получить 3-ю цифру младшего разряда, сканируя двоичное представление n и обычно добавляя только 1 или 2 в каждой битовой позиции. где встречается 1.

0
ответ дан 5 December 2019 в 12:54
поделиться

Я не думаю, что есть сверхэффективный способ.

«Решение, которое я уже реализовал преобразовать число в десятичное first. "

Я предполагаю, что вы сначала конвертируете в какой-то встроенный целочисленный тип. Я не думаю, что встроенное целое число имеет какое-либо отношение к основанию 10. (Хотя, когда вы его распечатываете, он будет будет преобразованием по основанию 10.

Возможно, вы ожидаете, что будет какой-то алгоритм, который просматривает ввод по одной цифре за раз и выдает результат.

Но, скажем, вы хотите преобразовать 3486784400 (основание 10) по основанию 3. Вам нужно будет проверить каждую цифру перед выводом, потому что

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

.. также

"вычисляют результат умножения цифры значения в соответствующую степень двойки "

явное вычисление степени не требуется, см. преобразование из базы 60 в основание 10

0
ответ дан 5 December 2019 в 12:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: