二进制到三进制表示转换

时间:2010-08-03 20:13:37

标签: algorithm math numbers theory ternary-representation

是否有人知道(或者可能指向某些来源阅读)将二进制数字系统中表示的数字转换为三元数字(我的特定情况)的方法或算法,或者用于此类转换的通用算法?

我已经实现的解决方案是先将数字转换为十进制,然后将其转换为所需的数字系统。这有效,但有两个步骤。我想知道如果不首先实施三元算法,是否可以一步完成?伙计们有什么诀窍吗?

UPD:我似乎无法清楚地描述我正在寻找哪种转换方式。我不是要求一些方式将base-2转换为base-3,我知道如何做到这一点。您可能会认为我有三元数和二进制数的代数数据结构,在Haskell中看起来像这样:

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

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

有两种显而易见的方法可以将一个转换为另一个:首先将其转换为Integer并获得结果(不是有趣的方式),其次是在base-3中实现自己的乘法和加法并计算结果乘法数字值各自为2的幂(直截了当和重)。

所以我想知道是否有另外一种方法而不是这两种方法。

9 个答案:

答案 0 :(得分:5)

如果你是用计算机做的,那么事物已经是二进制的,所以只需要重复除以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中

答案 1 :(得分:3)

您可以使用一些聪明的缩写进行转换。以下代码是“错误”方向,它是基于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)

[编辑]这是二进制到三元的方向,正如预期的那样冗长:

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)

答案 2 :(得分:3)

我认为每个人都缺少重要的东西。首先,提前计算一个表,对于每个二进制位,我们需要三元表示。在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 :(得分:1)

我担心我不知道Haskell能够在代码中表达这个,但我想知道使用Horner的规则来评估多项式可能会产生一种方法。

例如, x ^ 2 + b x + c可以被评估为c + x *(b + x * a)。

转换,比方说, 三进制数a * 9 + b * 3 + c为二进制,一个以a的二进制表示开始,然后将其乘以3(即移位和加法),然后加上b的二进制表示,将结果乘以3,添加c。

在我看来,这应该可以用地图(以获得三元数字的二进制表示)和折叠(a,b - > a + 3 * b)

答案 4 :(得分:0)

如果这是家庭作业,伪代码会在基座x中向后写b

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

我相信你可以弄清楚如何将结果转发而不是倒退。请注意,/需要是C样式的整数除法(结果是一个整数,截断为零)。

请注意,这并不依赖于执行算术的基础上的 。算术是在整数上定义的,而不是特定基数中整数的表示。


编辑:根据您更新的问题,我会将数字表示形式整理成一个整数(通过ors和shift),并使用上述算法进行整数运算。

当然,你可以按照你的描述去做,但这似乎是一项非常多的工作。

答案 5 :(得分:0)

我不认为这是一种超级有效的方式。

  

“我已经实施的解决方案   是将数字转换为十进制   第一“。

我假设您实际上是先转换为某种内置整数类型。我不认为内置整数与基数10有任何关系。(但是,当你打印它时,会有一个基数为10的转换。)

也许你会期望有一些算法一次查看输入一位数并产生输出。

但是,假设您想将3486784400(基数为10)转换为基数3.您需要在生成输出之前检查每个数字,因为

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

..还

  

“计算结果乘以数字   两个值的相应值“

无需明确计算权力,请参阅convert from base 60 to base 10

答案 6 :(得分:0)

我认为问题可能会有一些不同的“观点”,但我不确定它们中的任何一个是更快还是更好。例如,n的低阶基数3只是n mod 3.假设你已经有n的二进制表示。然后考虑2的幂如何解决mod 3. 2 ^ 0 = 1 mod 3,2 ^ 1 = 2 mod 3,2 ^ 2 = 1 mod 3,2 ^ 3 = 2 mod 3,...换句话说,功率在1 mod 3和2 mod 3之间交替。你现在有一种简单的方法可以通过扫描n的二进制表示来获得低阶基数3位,并且通常在每个位位置只添加1或2发生1的地方。

答案 7 :(得分:0)

不,您不能将base2号码转换为base3号码而不将其加载为整数。原因是2和3是互质的 - 它们没有共同的因素。

如果您使用的是base2和base4,甚至是base6和base9,那么直到两个基数的最低公倍数的整数集将由两个同构集表示。例如13(base4)= 0111(base2),所以转换1313(base4)= 01110111(base2) - 这是一个查找和替换操作。

至少你所使用的解决方案相对简单。如果需要提高性能,请在开始base3转换之前将整个base2表示转换为整数;它意味着更少的模数运算。替代方案是逐个处理base2中的每个字符,在这种情况下,你将除以base2表示中每个数字的所有3的幂。

答案 8 :(得分:0)

如果使用二进制编码的三进制(每个三位一体一对位),则可以使用并行算术进行转换。参见this tutorial