是否有人知道(或者可能指向某些来源阅读)将二进制数字系统中表示的数字转换为三元数字(我的特定情况)的方法或算法,或者用于此类转换的通用算法?
我已经实现的解决方案是先将数字转换为十进制,然后将其转换为所需的数字系统。这有效,但有两个步骤。我想知道如果不首先实施三元算法,是否可以一步完成?伙计们有什么诀窍吗?
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的幂(直截了当和重)。
所以我想知道是否有另外一种方法而不是这两种方法。
答案 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。