You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于unsigned long long的64组二进制数高效批量求和及性能问询

问题解决方案

一、核心实现思路:位并行加法

你的编码逻辑是:vector<unsigned long long>中第i个元素的第j位,对应第j个64位数的第i位。要批量完成64对数字的求和,直接用位运算模拟加法的进位逻辑是最优方案,完全不需要二叉树结构——二叉树分治适合单一大数的拆分求和,而这里是64个独立数字的并行运算,位运算能充分利用CPU64位寄存器的并行处理能力。

具体步骤模拟加法的本质(无进位和+进位传递):

  1. 计算每一位的无进位和:sum_no_carry = a[i] ^ b[i](异或操作对应单比特无进位相加)
  2. 计算初始进位:carry = (a[i] & b[i]) << 1(与操作找出同时为1的位,左移一位即为进位)
  3. 迭代处理进位传递:直到进位为0,每次更新无进位和与进位:
    while (carry != 0) {
        unsigned long long temp = sum_no_carry ^ carry;
        carry = (sum_no_carry & carry) << 1;
        sum_no_carry = temp;
    }
    
  4. 将最终的sum_no_carry存入结果向量c的对应位置。

整个过程仅需遍历vector的64个元素,每个元素的进位循环次数极少(最多64次,实际平均远低于此),完全贴合CPU硬件特性。

二、是否需要二叉树结构?

不需要。二叉树分治会引入额外的分支判断和内存访问开销,反而降低并行运算的效率。位运算的批量处理已经是最适配当前场景的方案。

三、性能对比与验证

1. 两种方案的实现代码

方案A:位并行批量加法

#include <vector>
using namespace std;

void batch_add(const vector<unsigned long long>& a, const vector<unsigned long long>& b, vector<unsigned long long>& c) {
    c.resize(64);
    for (int i = 0; i < 64; ++i) {
        unsigned long long sum = a[i] ^ b[i];
        unsigned long long carry = (a[i] & b[i]) << 1;
        while (carry != 0) {
            unsigned long long temp = sum ^ carry;
            carry = (sum & carry) << 1;
            sum = temp;
        }
        c[i] = sum;
    }
}

方案B:64次普通unsigned long long加法

void normal_add(const vector<unsigned long long>& a, const vector<unsigned long long>& b, vector<unsigned long long>& c) {
    vector<unsigned long long> nums_a(64, 0), nums_b(64, 0);
    // 解码a到普通数字数组
    for (int i = 0; i < 64; ++i) {
        for (int j = 0; j < 64; ++j) {
            if (a[i] & (1ULL << j)) {
                nums_a[j] |= (1ULL << i);
            }
        }
    }
    // 解码b到普通数字数组
    for (int i = 0; i < 64; ++i) {
        for (int j = 0; j < 64; ++j) {
            if (b[i] & (1ULL << j)) {
                nums_b[j] |= (1ULL << i);
            }
        }
    }
    // 逐个相加
    vector<unsigned long long> nums_c(64);
    for (int j = 0; j < 64; ++j) {
        nums_c[j] = nums_a[j] + nums_b[j];
    }
    // 编码回目标格式
    c.resize(64, 0);
    for (int i = 0; i < 64; ++i) {
        for (int j = 0; j < 64; ++j) {
            if (nums_c[j] & (1ULL << i)) {
                c[i] |= (1ULL << j);
            }
        }
    }
}

2. 性能测量方法

  • 多次迭代取平均:单次运算时间极短,需重复执行几十万/几百万次,计算平均耗时避免误差。
  • 高精度计时工具:
    使用C++11标准的std::chrono模块:
    #include <chrono>
    
    template<typename Func>
    double measure_avg_time(Func func, int iterations) {
        // 预热缓存
        func();
        auto start = chrono::high_resolution_clock::now();
        for (int i = 0; i < iterations; ++i) {
            func();
        }
        auto end = chrono::high_resolution_clock::now();
        chrono::duration<double> total = end - start;
        return total.count() / iterations; // 返回单次执行的平均时间(秒)
    }
    
    也可使用平台专用工具:Linux下用clock_gettime(CLOCK_MONOTONIC),Windows下用QueryPerformanceCounter,精度更高。
  • 开启编译器优化:测试时必须添加-O3(GCC/Clang)或/O2(MSVC)编译选项,否则结果无实际参考价值。

四、性能差异预期

位并行方案的速度会显著快于普通加法方案:

  1. 避免了解码/编码的双重O(6464)循环操作,位并行仅需O(64k)操作(k为进位循环次数,通常远小于64)。
  2. 位运算均为CPU单周期指令,能一次性并行处理64个位,充分利用寄存器带宽;而普通加法需要多次内存读写和循环分支,开销更大。

内容的提问来源于stack exchange,提问作者user2138251

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 11:47:28