三元载体的快速内积

时间:2013-11-01 18:02:47

标签: c++ c vector product

考虑两个向量, A B ,大​​小 n ,7< = n < = 23. A B 仅包含-1s,0和1。

我需要一个快速算法来计算 A B 的内在产品。

到目前为止,我已经考虑过使用以下编码将符号和值存储在单独的uint32_t中:

  • 标志0,值0→0
  • 签署0,值1→1
  • 签署1,值1→-1。

我想到的C ++实现如下所示:

struct ternary_vector {
    uint32_t sign, value;
};

int inner_product(const ternary_vector & a, const ternary_vector & b) {
    uint32_t psign = a.sign ^ b.sign;
    uint32_t pvalue = a.value & b.value;
    psign &= pvalue;
    pvalue ^= psign;
    return __builtin_popcount(pvalue) - __builtin_popcount(psign);
}

这种方法运作得相当好,但我不确定是否可以做得更好。对此事的任何评论都非常感谢。

4 个答案:

答案 0 :(得分:3)

我喜欢2 uint32_t,但我认为你的实际计算有点浪费

只是几点:

  • 我不确定引用(通过a获取bconst &) - 与将它们放在堆栈上相比,这增加了一个间接级别。当代码很小(可能是几个时钟)时,这很重要。尝试通过值传递,看看你得到了什么

  • 遗憾的是,
  • __builtin_popcount非常低效。我自己用过它,但发现即使是我写的一个非常基本的实现也比这快得多。但是 - 这取决于平台。

基本上,如果平台具有硬件popcount实现,__builtin_popcount使用它。如果不是 - 它使用非常低效的替代品。

答案 1 :(得分:0)

这里的一个严重问题是对psignpvalue变量重复使用正负向量。通过以这种方式混淆代码,你既不是你的编译器也不是你自己的任何好处。

答案 2 :(得分:0)

您是否可以在std::bitset<2>中对三元状态进行编码,并根据and定义产品?例如,如果您的三元类型是:

 1 = P = (1, 1)
 0 = Z = (0, 0)
-1 = M = (1, 0) or (0, 1)

我相信你可以将他们的产品定义为:

1 *  1 =  1 => P * P = P => (1, 1) & (1, 1) = (1, 1) = P
1 *  0 =  0 => P * Z = Z => (1, 1) & (0, 0) = (0, 0) = Z
1 * -1 = -1 => P * M = M => (1, 1) & (1, 0) = (1, 0) = M

然后内部产品可以通过获取元素的位数来开始......我正在研究如何将它们组合在一起。

编辑:

我的愚蠢建议没有考虑(-1)(-1) = 1,这是我提出的表述无法处理的。感谢@ user92382提出这个问题。

答案 3 :(得分:0)

根据您的体系结构,您可能希望优化临时位向量 - 例如如果你的代码要编译成FPGA,或者布局到ASIC,那么一系列逻辑运算在速度/能量/面积方面比存储和读/写两个大缓冲区更好。

在这种情况下,你可以这样做:

int inner_product(const ternary_vector & a, const ternary_vector & b) {
   return __builtin_popcount( a.value & b.value & ~(a.sign ^ b.sign))
      -   __builtin_popcount( a.value & b.value &  (a.sign ^ b.sign));  
}

这将很好地布局 - (a.value&amp; b.value&amp; ...)可以启用/禁用XOR门,其输出分成两个带符号的累加器,第一个路径在累积之前未被记录