2016-09-25 29 views
1

我一直在使用Vector进行实验来使用HW来平行整数运算。有什么办法来启用向量操作溢出检查?我可以使用Vector来执行算术运算吗<T>

一个示例是将两列(等长阵列)的整数相加在一起。这里c=a+b意味着c[0] = a[0] + b[0]c[1] = a[1] + b[1]

我想我可以做这样的事情:

overflow[i] = b[i] >= 0 ? c[i] < a[i] : c[i] >= a[i]; 

但这(分支)可能会比净的自动溢出检查较慢,并且可能否定的性能优势使用Vector<T>

我们还希望优化我们最常用的操作:乘法,减法,以较小程度的整数除法。

编辑:我想到了这一点,并想出了这个,这是未经检查的载体添加速度的2.5倍。看起来像很多额外的开销。

public Vector<int> Calc(Vector<int> a, Vector<int> b) 
    { 
     var result = a + b; 
     var overflowFlag = Vector.GreaterThan(b, Vector<int>.Zero) * Vector.LessThan(result,a) 
      + Vector.LessThan(b,Vector<int>.Zero) * Vector.GreaterThan(result, a); 

     // It makes no sense to add the flags to the result, but haven't decided what to do with them yet, 
     // and don't want the compiler to optimise the overflow calculation away 
     return result + overflowFlag; 
    } 

时序:(4K迭代添加一对100K阵列)

  • 普通添加:618ms
  • 普通经过添加:1092ms
  • 向量添加:208ms
  • 矢量已加入:536ms
+0

不是,但你可以自己检查它当然。在更多的背景下,我可以提供更有针对性的建议。 – harold

+0

@哈罗德 - 我添加了一点进一步的背景。有没有一种确定溢出是否发生的有效方法? – Rob

+0

你不需要分支(实际上你不能),你可以使用ConditionalSelect。乘法是棘手的,没有扩大和扩大是讨厌的,我会考虑它。稍后我会回来更正确地回答 – harold

回答

1

使用一些借用黑客的喜悦(第2章的溢出检测),这里有一些溢出谓词(未测试):

签名另外:

var sum = a + b; 
var ovf = (sum^a) & (sum^b); 

结果是标志,而不是完整的面具。也许这就够了,也许不是,在这种情况下,我通常会推荐一个右移,但Vector<T>没有右移(缺少太多东西)。尽管你可以比较零。

无符号加法:为了完整?

var sum = a + b; 
var ovf = Vector.LessThan(sum, a); 

乘法:

据我可以告诉有只是没有合理的办法做到这一点。即使在本地SSE,这也有点烦人,但pmuldq和一些洗牌并不算太坏。
在C#SIMD中,这似乎毫无希望。没有高位(除了16位整数,本地SSE也没有,也很烦人),没有扩大乘法(无论如何也无法缩小结果),也没有合理的方法来事先扩大。即使你可以扩大(他们可以请把它加到API中,认真),multiplying 64bit integers with SSE is annoying,所以使用标量算术来做这件事并不是一个坏的选择,这就使得这个观点失败了。

所以我会建议不要在SIMD中这样做,至少不要在C#中。

这并不意味着您使用内置的溢出检测。如果溢出是一个致命的错误,那么这是适当的,如果它是普通的和预期的,并且你只是想要一个布尔型标志的溢出状态,那么它是灾难性的缓慢。在这种情况下,你可以使用:

签名乘法:

long ext_prod = (long)a * b; 
int prod = (int)ext_prod; 
bool ovf = (prod >> 31) != (int)(ext_prod >> 32); 

无符号乘法:

ulong ext_prod = (ulong)a * b; 
uint prod = (uint)ext_prod; 
bool ovf = (ext_prod >> 32) != 0; 

在SIMD它会基本的工作以同样的方式,即测试高半是否是填充了符号的副本(根据定义,在无符号的情况下为零),但是扩大使得它在本地SIMD中变得令人讨厌,并且在C#SIMD中变得毫无希望。

+0

使用'ext_prod == prod'检查溢出会不会更快?至少它似乎是我的快速基准。 – Rob

+0

@Rob好,如果这是结果,那么是的,显然:) – harold