[英]Rotate left part of hex number in C++
我有以下問題:我在 C++ 中有一個十六進制數(數據類型:std::uint64_t),十六進制數包含從 1 到給定 n 的所有數字。 現在的問題是旋轉十六進制數的前 k 位,例如:
hex = 0x436512, k = 3 --> 0x634512
我已經嘗試將十六進制數分成兩部分,例如
std::uint64_t left = hex >> ((n - k) * 4);
std::uint64_t right = ((1UL << ((n - k) * 4)) - 1) & hex;
然后left
旋轉並將left
right
在一起。 是否有可能就地執行此操作並且僅使用位操作和/或數學運算符?
作為基線,您可以使用它,它基本上轉換為數字並返回。
#include <cstdio>
#include <cstdint>
#include <array>
uint64_t rotate( uint64_t value, int k ) {
// decompose
std::array<uint8_t,16> digits;
int numdigits = 0;
while ( value > 0 ) {
digits[numdigits] = value % 16;
value = value / 16;
numdigits += 1;
}
if ( k>numdigits ) return 0;
// revert digits
int p1 = numdigits - 1;
int p2 = numdigits - k;
for ( ; p1>p2; p1--,p2++ ) {
uint8_t tmp = digits[p1];
digits[p1] = digits[p2];
digits[p2] = tmp;
}
// reconstruct
for ( int j=0; j<numdigits; ++j ) {
value = (value*16) + digits[numdigits-1-j];
}
return value;
}
int main() {
uint64_t value = 0x123ffffff;
for ( int j=0; j<8; ++j ) {
value = value >> 4;
printf( "%lx %lx\n", value, rotate(value,3) );
}
}
Godbolt: https://godbolt.org/z/77qWEo9vE
它產生:
Program stdout
123fffff 321fffff
123ffff 321ffff
123fff 321fff
123ff 321ff
123f 321f
123 321
12 0
1 0
你其實不需要分解整個數字,你可以嚴格只分解左邊的數字。
#include <cstdio>
#include <cstdint>
#include <array>
uint64_t rotate( uint64_t value, int k ) {
// sanity check
if ( value == 0 ) return 0;
// fast find number of digits
int numdigits = (63-__builtin_clzl(value))/4 + 1;
if ( k>numdigits ) return 0;
// Decompose left and right
int rightbits = 4*(numdigits-k);
uint64_t left = value >> rightbits;
uint64_t right = rightbits==0 ? 0 : value & (uint64_t(-1)>>(64-rightbits));
// decompose left
uint64_t rot = 0;
for ( int j=0; j<k; ++j ) {
uint64_t digit = left % 16;
left = left / 16;
rot = (rot*16) + digit;
}
// rejoin
return right | (rot<<rightbits);
}
int main() {
uint64_t value = 0x123ffffff;
for ( int j=0; j<8; ++j ) {
value = value >> 4;
printf( "%lx %lx\n", value, rotate(value,3) );
}
}
產生相同的 output。
神箭: https://godbolt.org/z/P3z6W8b3M
在谷歌基准測試下運行:
#include <benchmark/benchmark.h>
#include <vector>
#include <iostream>
uint64_t rotate1(uint64_t value, int k);
uint64_t rotate2(uint64_t value, int k);
struct RotateTrivial {
uint64_t operator()(uint64_t value, int k) {
return rotate1(value, k);
}
};
struct RotateLeftOnly {
uint64_t operator()(uint64_t value, int k) {
return rotate2(value, k);
}
};
template <typename Fn>
static void Benchmark(benchmark::State& state) {
Fn fn;
for (auto _ : state) {
uint64_t value = uint64_t(-1);
for (int j = 0; j < 16; ++j) {
for (int k = 1; k < j; ++k) {
uint64_t result = fn(value, k);
benchmark::DoNotOptimize(result);
}
value = value >> 4;
}
}
}
BENCHMARK(Benchmark<RotateTrivial>);
BENCHMARK(Benchmark<RotateLeftOnly>);
BENCHMARK_MAIN();
在 AMD Threadripper 3960x 3.5GHz 上生成
--------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------
Benchmark<RotateTrivial> 619 ns 619 ns 1158174
Benchmark<RotateLeftOnly> 320 ns 320 ns 2222098
每次迭代有 105 次調用,因此普通版本約為 6.3 ns/調用或 20 個周期,優化版本約為 3.1ns/調用或 10 個周期。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.