AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 77515753
Accepted
fadedbee
fadedbee
Asked: 2023-11-20 20:03:34 +0800 CST2023-11-20 20:03:34 +0800 CST 2023-11-20 20:03:34 +0800 CST

如何将两个 uint32_t 值交错为一个 uint64_t?

  • 772

如果我有两个 32 位值 X 和 Y,如何有效地将它们的位按照 xyxyxyxy 的顺序交错为一个 64 位值 Z...(Z 是 Z 顺序曲线上的一个位置。)

我可以迭代 X 和 Y 中的每个位,同时设置 Z 中的位。这看起来效率很低。

是否有一种捷径可以将两个值中的位交错为一个大值,而这需要不到一百条 CPU 指令?

c
  • 3 3 个回答
  • 121 Views

3 个回答

  • Voted
  1. Best Answer
    nielsen
    2023-11-20T20:50:06+08:002023-11-20T20:50:06+08:00

    此 C++ 答案也适用于 C:https ://stackoverflow.com/a/39490836/11993121

    答案概括了原理,但没有写出完整的解决方案。一个工作实现如下:

    #include <stdint.h>
    
    uint64_t interleave(uint32_t x0, uint32_t y0)
    {
        static const uint64_t B[] = {0x0000FFFF0000FFFF, 0x00FF00FF00FF00FF, 0x0F0F0F0F0F0F0F0F, 0x3333333333333333, 0x5555555555555555};
        static const unsigned S[] = {16, 8, 4, 2, 1};
    
        uint64_t x = x0;
        uint64_t y = y0;
    
        for(unsigned i = 0; i < sizeof(B)/sizeof(B[0]); i++)
        {
            x = (x | (x << S[i])) & B[i];
            y = (y | (y << S[i])) & B[i];
        }
        return x | (y << 1);
    }
    

    测试示例:

    #include <stdio.h>
    
    void printBinary64(uint64_t x)
    {
        uint64_t bit = ((uint64_t)1 << 63);
        for(unsigned i = 0; i < 64; i++)
        {
            printf("%c", (x&bit) ? '1' : '0');
            bit = bit >> 1;
        }
    }
    
    void printBinary32(uint32_t x)
    {
        uint32_t bit = ((uint32_t)1 << 31);
        for(unsigned i = 0; i < 32; i++)
        {
            printf("%c ", (x&bit) ? '1' : '0');
            bit = bit >> 1;
        }
    }
    
    int main(void)
    {
        uint32_t x = 0x01234567;
        uint32_t y = 0xFEDCBA98;
        printf(" ");
        printBinary32(x);
        printf("\n");
        printBinary32(y);
        printf("\n");
        printBinary64(interleave(x,y));
        printf("\n");
    }
    
    • 2
  2. Simon Goater
    2023-11-21T00:02:25+08:002023-11-21T00:02:25+08:00

    无论如何,这是一个手动矢量化版本,它使用 SSE 内在函数同时对 x 和 y 进行位运算。然而,gcc 编译器对我来说太聪明了,它以某种方式更有效地优化了尼尔森的标量函数。

    不管怎样,这可行,但可能只对那些可能想要调整它以使用更宽的向量宽度来同时交错一对以上 uint32_ts 的人有用。

    uint64_t interleavesse2(uint32_t x0, uint32_t y0) {
      // Works but is almost 50% slower!! than scalar version when compiled with gcc -O3 -msse2
      // Materially faster than when scalar version compiled with gcc -O2 -msse2
      __m128i mask = _mm_setr_epi32(0xffff, 0xffff, 0xffff, 0xffff);
      __m128i z = _mm_setr_epi32(x0, 0, y0, 0);
      z = _mm_and_si128(_mm_or_si128(z, _mm_slli_epi64(z, 16)), mask);
      mask = _mm_setr_epi32(0xff00ff, 0xff00ff, 0xff00ff, 0xff00ff);
      z = _mm_and_si128(_mm_or_si128(z, _mm_slli_epi64(z, 8)), mask);
      mask = _mm_setr_epi32(0xf0f0f0f, 0xf0f0f0f, 0xf0f0f0f, 0xf0f0f0f);
      z = _mm_and_si128(_mm_or_si128(z, _mm_slli_epi64(z, 4)), mask);
      mask = _mm_setr_epi32(0x33333333, 0x33333333, 0x33333333, 0x33333333);
      z = _mm_and_si128(_mm_or_si128(z, _mm_slli_epi64(z, 2)), mask);
      mask = _mm_setr_epi32(0x55555555, 0x55555555, 0x55555555, 0x55555555);
      z = _mm_and_si128(_mm_or_si128(z, _mm_slli_epi64(z, 1)), mask);
      uint64_t res[2];
      memcpy(res, &z, 16);
      return res[0] | (res[1] << 1);
    }
    
    • 0
  3. bazza
    2023-11-21T03:10:17+08:002023-11-21T03:10:17+08:00

    你是否必须经常这样做,比如你有很多 X 与很多 Y 交错吗?如果没有,下面的内容仅供参考。

    如果是,则存在“正交”方法。假设您有 128 个 X 与 128 个 Y 交错。从 32 128 位向量开始,将 X[0] 的位放在 32 个向量的第 0 位中。将 X[1] 的位放入向量的第 1 位,依此类推。对另一组 32 128 位向量中的 Y 值执行相同的操作。这有效地将值中的位转置为一组向量中的位列。然后,交错它们只是在从两组向量重新构建 64 位值时交替索引 X 向量和 Y 向量的情况。

    诚然,仅对于交织而言,将整数转置为向量数组中的位列可能效率低下。但是,如果稍后要完成更多位操作,则可以减少大量工作来重新索引数组中的向量。一些 SIMD 单元(如 Altivec)具有可以帮助进行转置的向量指令。

    按位逻辑运算(例如 AND)仍然可以完成(一次 1 位,但一次 128 个不同的值),但没有速度优势。然而,在已经转置的表示中也没有缺点。如果处理是一系列位操作和按位操作,则位操作实际上是“自由的”,这就是可以节省时间的地方。

    • 0

相关问题

  • 比 * 更快的乘法

  • 在 C 中的 scanf() 格式说明符中使用宏获取字符串长度

  • 如何将#define的数据类型设置为long double?

  • 不兼容的常量指针

  • OpenGL 中的非渐变颜色变化

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    使用 <font color="#xxx"> 突出显示 html 中的代码

    • 2 个回答
  • Marko Smith

    为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类?

    • 1 个回答
  • Marko Smith

    您可以使用花括号初始化列表作为(默认)模板参数吗?

    • 2 个回答
  • Marko Smith

    为什么列表推导式在内部创建一个函数?

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 个回答
  • Marko Smith

    为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)?

    • 4 个回答
  • Marko Smith

    为什么库中不调用全局变量的构造函数?

    • 1 个回答
  • Marko Smith

    std::common_reference_with 在元组上的行为不一致。哪个是对的?

    • 1 个回答
  • Marko Smith

    C++17 中 std::byte 只能按位运算?

    • 1 个回答
  • Martin Hope
    fbrereto 为什么在传递 {} 时重载解析更喜欢 std::nullptr_t 而不是类? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 您可以使用花括号初始化列表作为(默认)模板参数吗? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi 为什么列表推导式在内部创建一个函数? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A fmt 格式 %H:%M:%S 不带小数 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python C++20 的 std::views::filter 未正确过滤视图 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute 为什么 'char -> int' 是提升,而 'char -> Short' 是转换(但不是提升)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa 为什么库中不调用全局变量的构造函数? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis std::common_reference_with 在元组上的行为不一致。哪个是对的? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev 为什么编译器在这里错过矢量化? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan C++17 中 std::byte 只能按位运算? 2023-08-17 17:13:58 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve