【问题标题】:Conversion of binary bitstream to and from ternary bitstream?二进制比特流与三进制比特流的转换?
【发布时间】:2012-08-14 11:45:43
【问题描述】:

我需要将任意长度的二进制转换为精确的三进制表示。理想情况下,给定一个位数组char buffer[n],该算法将能够产生一个三元组(位模拟),反之亦然。有这样的算法吗?

我知道将单个 int 转换为三元的方法:

int nth_trit(int num, int n)
{
    for(int i = 0; i < n; i++)
        num /= 3;

    return num % 3;
}

唉,即使是long long long int 的比特流也不够用。我认为使用大整数库就足够了,虽然我不确定,并且觉得应该有更好的方法来计算三元表示。

一个直观的例子:

// Conversion is simple(short stream)
Binary  - 0 1 0 0 1 0 0 1
Decimal -             7 3
Ternary -         2 2 0 1

// Conversion is hard(long stream)
Binary  - 1 0 1 0 0 0 0 1 ..........
Ternary - ? ? ?

短流很简单,因为它非常适合int,所以可以使用nth_trit 函数,但长流不能,因此除了使用大整数库之外,没有简单的解决方案发生在我身上。

【问题讨论】:

  • 一个 trit 实际上代表大约 1.58496 ~ log(3) 位的信息。如果我理解正确,您是说我可以采用,即每 3 位并将它们转换为 2 个三元组,因为三元组大约代表 1.5 位。不幸的是,3 位 (2^3) 并不完全由 2 个三元组 (3^2) 表示。我需要一个准确的表示。
  • 您的“位”数组是'0''1' 字符值的数组吗?或者它是一个8位数字的数组,将被逐位“分解”(即通过你的nth_trit函数)?同样...您希望生成的“trits 数组”看起来像什么?大概它是'0'..'2' 范围内的字符数组 范围0-2 上的数值数组?可能是这样的:['0', '2', '1']?
  • 例如,我上面的代码采用 int 并返回确切的第 n 个 trit。我可以用long long int 替换int,但理想情况下我想将一个流,而不是一个固定大小的数字,转换成一个三元表示,一个trits 数组(范围从0..2

标签: c++ algorithm ternary-representation


【解决方案1】:

可以证明每个三进制数字都依赖于所有二进制数字。所以你不能比读取整个位串然后进行转换更好。

【讨论】:

    【解决方案2】:

    如果位缓冲区很长,您的算法就不是很好,因为每个输出 trit 重复所有的除法,对于较小的 n 值也需要。因此,将此算法转换为“bignum”算法将不是您想要的。

    另一种方法:从左到右扫描位,每个新的都会更新之前的值:

    val = val * 2 + bit
    

    具有n trits t[i] 的三进制数具有值

    sum(i = 0 .. n-1) t[i] * 3^i
    

    因此,为新扫描位更新的val 的三元表示变为,

    [ 2 * sum(i = 0 .. n-1) t[i] * 3^i ] + bit
        = bit + sum(i = 0 .. n-1) 2 * t[i] * 3^i 
        = 2 * t[0] + b + sum(i = 1 .. n) 2 * t[i] * 3^i
    

    为了简化代码,让我们计算一个无符号字符数组中的三元组。完成后,您可以以任何您喜欢的方式重新包装它们。

    #include <stdio.h>
    
    // Compute the trit representation of the bits in the given
    // byte buffer.  The highest order byte is bytes[0].  The
    // lowest order trit in the output is trits[0].  This is 
    // not a very efficient algorithm, but it doesn't use any
    // division.  If the output buffer is too small, high order
    // trits are lost.
    void to_trits(unsigned char *bytes, int n_bytes, 
                  unsigned char *trits, int n_trits)
    {
      int i_trit, i_byte, mask;
    
      for (i_trit = 0; i_trit < n_trits; i_trit++)
        trits[i_trit] = 0;
    
      // Scan bits left to right.
      for (i_byte = 0; i_byte < n_bytes; i_byte++) {
    
        unsigned char byte = bytes[i_byte];
    
        for (mask = 0x80; mask; mask >>= 1) {
          // Compute the next bit.
          int bit = (byte & mask) != 0;
    
          // Update the trit representation
          trits[0] = trits[0] * 2 + bit;
          for (i_trit = 1; i_trit < n_trits; i_trit++) {
            trits[i_trit] *= 2;
            if (trits[i_trit - 1] > 2) {
              trits[i_trit - 1] -= 3;
              trits[i_trit]++;
            }
          }
        }
      }
    }
    
    // This test uses 64-bit quantities, but the trit 
    // converter will work for buffers of any size.
    int main(void)
    {
      int i;
    
      // Make a byte buffer for an easy to recognize value.
      #define N_BYTES 7
      unsigned char bytes [N_BYTES] = 
        { 0xab, 0xcd, 0xef, 0xff, 0xfe, 0xdc, 0xba };
    
      // Make a trit buffer.  A 64 bit quantity may need up to 42 trits.
      #define N_TRITS 42
      unsigned char trits [N_TRITS];
    
      to_trits(bytes, N_BYTES, trits, N_TRITS);
    
      unsigned long long val = 0;
      for (i = N_TRITS - 1; i >= 0; i--) {
        printf("%d", trits[i]);
        val = val * 3 + trits[i];
      }
      // Should prinet value in original byte buffer.
      printf("\n%llx\n", val);
    
      return 0;
    }
    

    【讨论】:

    • +1 用于解释和算法。正是我需要的。谢谢!
    【解决方案3】:

    在任何基数中乘/除以 2 都很简单,因此将任何基数转换为二进制数的最简单方法是重复乘/除以 2,跟踪进位/奇偶校验。

    #include <algorithm>
    #include <cstdint>
    #include <functional>
    #include <iostream>
    #include <iterator>
    #include <vector>
    
    // in: a vector representing a bitstring, with most-significant bit first.
    // out: a vector representing a tritstring, with least-significant trit first.
    static std::vector<uint8_t> b2t(const std::vector<bool>& in) {
      std::vector<uint8_t> out;
      out.reserve(in.size());  // larger than necessary; will trim later
      // for each digit (starting from the most significant bit)
      for (bool carry : in) {
        // add it to the tritstring (starting from the least significant trit)
        for (uint8_t& trit : out) {
          // double the tritstring, carrying overflow to higher places
          uint8_t new_trit = 2 * trit + carry;
          carry = new_trit / 3;
          trit = new_trit % 3;
        }
        if (carry) {
          // overflow past the end of the tritstring; add a most-significant trit
          out.push_back(1);
        }
      }
      out.reserve(out.size());
      return out;
    }
    
    // in: a vector representing a tritstring, with most-significant trit first.
    // out: a vector representing a bitstring, with least-significant bit first.
    static std::vector<bool> t2b(std::vector<uint8_t> in) {
      std::vector<bool> out;
      out.reserve(2 * in.size());  // larger than necessary; will trim later
      bool nonzero;
      do {
        nonzero = false;
        bool parity = false;
        for (uint8_t& trit : in) {
          // halve the tritstring, starting from the most significant trit
          uint8_t new_trit = trit + 3 * parity;
          parity = new_trit & 1;
          nonzero |= trit = new_trit / 2;
        }
        // the division ended even/odd; add a most-signiticant bit
        out.push_back(parity);
      } while (nonzero);
      out.reserve(out.size());
      return out;
    }
    
    int main() {
      bool odd = false;
      std::string s;
      while (std::cin >> s) {
        if ((odd = !odd)) {
          std::vector<bool> in(s.size());
          std::transform(s.begin(), s.end(), in.begin(),
              [](char c) {return c - '0';});
          std::vector<uint8_t> out(b2t(in));
          std::copy(out.rbegin(), out.rend(),
              std::ostream_iterator<int>(std::cout));
          std::cout << std::endl;
        } else {
          std::vector<uint8_t> in(s.size());
          std::transform(s.begin(), s.end(), in.begin(),
              [](char c) {return c - '0';});
          std::vector<bool> out(t2b(in));
          std::copy(out.rbegin(), out.rend(),
              std::ostream_iterator<int>(std::cout));
          std::cout << std::endl;
        }
      }
      return 0;
    }
    
    $ ./a.out 1011 102 102 1011 10001100001101010011010010111000011011101000111101011101000110100101101101111110110011010010111100010110100010101011010100101100001101001000000111011110101001000100011010111011000111101110111001111110110011101011101101001001110010111111100011000110011000111110110111011110110110001111011011011000100101010010111010000110101011010100011010110110000010110111000111000110101000000110000001111110101110010000011000110001010000001001100011000000100100100001100101111000101001001010101101101000011100110001111011110001 的 12010110110220200020211012001000211110222212120220002002120120111221021120100122221020011120010202110111112112110201211201120222000011010100122122121211112101111121002110102112000111200002121211002022100220211220220111010210200222021221020122012102101010100001122200011110210221120122022011202201002002001221211001221112001 12010110110220200020211012001000211110222212120220002002120120111221021120100122221020011120010202110111112112110201211201120222000011010100122122121211112101111121002110102112000111200002121211002022100220211220220111010210200222021221020122012102101010100001122200011110210221120122022011202201002002001221211001221112001 的 10001100001101010011010010111000011011101000111101011101000110100101101101111110110011010010111100010110100010101011010100101100001101001000000111011110101001000100011010111011000111101110111001111110110011101011101101001001110010111111100011000110011000111110110111011110110110001111011011011000100101010010111010000110101011010100011010110110000010110111000111000110101000000110000001111110101110010000011000110001010000001001100011000000100100100001100101111000101001001010101101101000011100110001111011110001 ^D

    (10112 = 8+2+1 = 11 = 9 + 2 = 1023)
    (10001100001101010011010010111000011011101000111101011101000110100101101101111110110011010010111100010110100010101011010100101100001101001000000111011110101001000100011010111011000111101110111001111110110011101011101101001001110010111111100011000110011000111110110111011110110110001111011011011000100101010010111010000110101011010100011010110110000010110111000111000110101000000110000001111110101110010000011000110001010000001001100011000000100100100001100101111000101001001010101101101000011100110001111011110001 2 子> = 7343280200542654154029818354420920722408633707396360612751407162736942742985658428558632312175242897575484682660836397639769592568209070221085927986634481 = 120101101102202000202110120010002111102222121202200020021201201112210211201001222210200111200102021101111121121102012112011202220000110101001221221212111121011111210021101021120001112000021212110020221002202112202201110102102002220212210201220121021010101000011222000111102102211201220220112022010020020012212110012 211120019)

    【讨论】:

      【解决方案4】:

      平衡的三元/三元更好。 {-1, 0, 1} 以这种方式输出。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-11-22
        • 2014-06-07
        • 2013-03-06
        • 1970-01-01
        • 2011-09-14
        • 2011-03-24
        • 2020-05-04
        相关资源
        最近更新 更多