二进制位流与三进制位流之间的转换
Conversion of binary bitstream to and from ternary bitstream?
我需要将任意长度的二进制转换为精确的三进制表示。理想情况下,给定比特阵列char buffer[n]
,该算法将能够产生trit(比特模拟)阵列,反之亦然。有这样的算法吗?
我知道如何将单个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都重复n
的较小值所需的所有除法。因此,将此算法转换为"bignum"算法将不是您想要的。
另一种方法:从左到右扫描比特,每个新的比特更新以前的值:
val = val * 2 + bit
n
与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
为了简化代码,让我们在一个无符号字符数组中计算trits。它们完成后,你可以随心所欲地重新包装。
#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%llxn", val);
return 0;
}
乘/除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.out101110210210111000110001101010011010010111000111010001111010111010001101001011011101111110110011010010111100010110100010101011001011000110100100000111011110101001000110101110111011111011100111111101111011011101110110100100111001011111111001011101110111011110110111111101110111011101010111011101101110111011101111111011011101111011011011101110101011110110111010101110101011011011101110111010011101110110110110111011101001101110110111011011011111110111011011111101110111011111111111011101110010000011000110001101000000100110001100000100100100001100101111000101010110110100001110001111110111100011201011011022020002021101200100021111022212022000200212012011122102112010012222102001112001020211011111211020121120112022200001101010012212121111210111112100211010211200011120000212121100202210022021122022011101021020022202122102012102101010100001122200011110211120220112022010020020012212110012211120011201011011022020002021101200100021111022212022000200212012011122102112010012222102001112001020211011111211020121120112022200001101010012212121111210111112100211010211200011120000212121100202210022021122022011101021020022202122102012102101010100001122200011110211120220112022010020020012212110012211120011000110001101010011010010111000111010001111010111010001101001011011011111101100110100101111000101101000101010110010110001101001000001110111101010010001101011101110111110111001111110111011110101110110100100111001011111111001011101110111011110110111011101101111011011101101110111011101110101011101111010110111011101101101110110111011011011011101110101011011101110100111011101110100110110110111010101101101111110110110111111101110110111111101101110111111011101110111000001101100011010000001001110000010010010000110010111100010110101011010000111000111111011110001^D
(10112=8+2+1=11=9+2=1023)
(10001100011010100110100101110001110100011110101110100011010010110110111111011001101001011110001011010001010101101010010110001101001000001110111101010010001101011101110111110111001111110111011110101110110100100111001011111111001011110010111011101110111101101110111011111110111011101101110111011101110101011101111010111010101110101011110110111010101110101010101110111011110010111010101101110101011101110101000001101111111011101101110010000011000110001010000010011100000100100100001100101111000101010010110110100001110011110111100012=734328020054265414029818354420920722408633707396360612751407162736942742985658428558632312175242897575484682660836397639769592568209070221085927986634481=1201011011022020002021101200100021111022212022000200212012011122102112010012222102001112001020211011111211020121120112022200001101010012212121111210111112100211010211200011120000212121100202210022021122022011101021020022202122102012102101010100001122200011110221120220112022010020020012212110012211120019)
平衡三元/三元更好。{-1,0,1}以这种方式进行输出。
- 在 Rcpp 中的字符串类型之间转换时出错
- r-在Rcpp和C++之间转换矢量(使用Rcpp::as或Rcpp:::wrap)是否会创建一个新的矢量并复制元素
- 在不同类型之间转换常量指针
- 在 3D 骨架系统 DirectX 之间转换
- C++ 如何将用户控件添加到窗体,以便我可以在面板之间转换
- 在 std::u8string 和 std::string 之间转换
- 如何在Unicode/UCS CodePoint和UTF16替代对之间转换
- 在DXGI格式之间转换RGBA数据
- 在两个不动点表达之间转换
- 在函数指针类型之间转换
- 代码的错误答案是在Java Camel案件和C 下划线标识符之间转换的错误答案
- 如何在C 中的不同类之间转换
- 一个关于C++中double和int之间转换的奇怪结果
- 模板类在模板类型之间转换,但也专门化
- 是否有Visual c++编译器在线,以及如何在c++和vs简单代码之间转换
- c/在Unix时间和"Gregorian time"之间转换
- 无法使用iconv在编码之间转换
- 在std::string和std::wstring之间转换的多平台方式
- 我真的应该每次在基元类型之间转换时都使用static_cast吗
- 使用Boost::units在两个量之间转换的最简单方法