[英]Any hope to convert a std::bitset<128> to a single 128-bit integer in the near future?
I am using std::bitset to represent short DNA sequences (haplotypes).我使用 std::bitset 来表示短 DNA 序列(单倍型)。 For my purposes, I need to be able to convert each such sequence into a single integer.出于我的目的,我需要能够将每个这样的序列转换为一个整数。 At the moment, it seems like this requirement bounds my sequences to be of length <=64 because of the way std::bitset::to_ullong works?目前,由于 std::bitset::to_ullong 的工作方式,这个要求似乎限制了我的序列长度 <=64?
Since there are ways to represent 128-bit integers in C++ ( Is there a 128 bit integer in C++? ), I am wondering how long it will take before std::bitset supports direct conversion to 128-bit integers as well?由于有多种方法可以在 C++ 中表示 128 位整数(C++ 中是否有 128 位整数? ),我想知道在 std::bitset 支持直接转换为 128 位整数之前需要多长时间?
Of course I would be more than happy to learn that I am wrong and one can already do that...当然,我会很高兴得知我错了,并且已经可以做到这一点......
Thanks!谢谢!
You could always provide your own:您始终可以提供自己的:
#include <climits>
#include <cstdint>
#include <limits>
#include <bitset>
static_assert(sizeof(unsigned long long) == 8 && CHAR_BIT == 8);
struct my_uint128_t {
std::uint64_t lo;
std::uint64_t hi;
};
template<std::size_t N>
my_uint128_t to_uint128_t(const std::bitset<N>& v) {
constexpr std::bitset<N> mask(std::numeric_limits<std::uint64_t>::max());
std::uint64_t lo = (v & mask).to_ullong();
std::uint64_t hi = ((v >> 64) & mask).to_ullong();
return {lo, hi};
}
However, this makes a few technically unsafe assumptions, such as unsigned long long
being 64 bits.但是,这会产生一些技术上不安全的假设,例如unsigned long long
是 64 位。 The static_assert
helps, but a better solution is to actually account for the possible discrepancies: static_assert
帮助,但更好的解决方案是实际考虑可能的差异:
#include <climits>
#include <limits>
#include <bitset>
#include <array>
template<std::size_t BITS>
struct my_uint_t {
static constexpr std::size_t num_parts =
(BITS / CHAR_BIT + (BITS % CHAR_BIT > 0)) / sizeof(unsigned long long);
std::array<unsigned long long, num_parts> parts;
template<std::size_t N, std::size_t I>
void populate_from_bitset(const std::bitset<N>& v) {
constexpr std::size_t offset = I * CHAR_BIT * sizeof(unsigned long long);
constexpr std::bitset<N> mask(std::numeric_limits<unsigned long long>::max());
parts[I] = ((v >> offset) & mask).to_ullong();
if constexpr(I + 1 < num_parts) {
populate_from_bitset<N, I + 1>(v);
}
}
};
template<std::size_t N>
my_uint_t<128> to_uint128_t(const std::bitset<N>& v) {
my_uint_t<128> result;
result.populate_from_bitset<N, 0>(v);
return result;
}
auto tmp_a = &to_uint128_t<16>;
auto tmp_b = &to_uint128_t<65>;
auto tmp_c = &to_uint128_t<128>;
Both gcc and clang optimize this down to adequately clean assembly on X86-64: gcc 和 clang 都对此进行了优化,以充分清洁 X86-64 上的程序集:
my_uint128_t to_uint128_t<16ul>(std::bitset<16ul> const&):
movzx edx, WORD PTR [rdi]
xor eax, eax
ret
my_uint128_t to_uint128_t<65ul>(std::bitset<65ul> const&):
mov rdx, QWORD PTR [rdi]
mov rax, QWORD PTR [rdi+8]
ret
my_uint128_t to_uint128_t<128ul>(std::bitset<128ul> const&):
mov rdx, QWORD PTR [rdi]
mov rax, QWORD PTR [rdi+8]
ret
Notes:笔记:
my_uint128_t
is a bit of a placeholder type here. my_uint128_t
在这里有点占位符类型。 There's still some endianness handling required to use this correctly as a portable 128 bit integer.仍然需要一些字节序处理才能将其正确用作可移植的 128 位整数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.