System.Numerics.Vector.ConditionalSelect用途、用法及示例讲解咨询
详解System.Numerics.Vector.ConditionalSelect
我来把System.Numerics.Vector.ConditionalSelect给你讲透——官方文档确实有点抽象,我用几个实用例子帮你理解它的用途、场景和用法。
核心用途
简单来说,这是.NET SIMD(单指令多数据)编程里的批量条件选择工具:它会同时遍历两个输入向量的每个元素位置,根据第三个条件向量对应位置的布尔值,决定取第一个向量还是第二个向量的元素,最终生成一个新的向量。本质是把循环里的if-else逻辑并行化,用硬件加速提升批量数据处理的性能。
适用场景 & 使用时机
适合的场景
- 批量数据清洗/修正:比如把数组中所有负数替换为0、把超出范围的像素值截断到合法区间
- 向量化数值计算:根据不同条件选择不同的计算分支结果(比如大于阈值的数乘2,小于阈值的数除以2)
- 图像/信号处理:批量处理像素、采样点的条件替换或筛选
什么时候用它?
- 当你需要对大量数据执行相同的条件选择逻辑时(数据量要远大于
Vector<T>.Count,SIMD的并行优势才会明显) - 当普通循环里的
if-else成为性能瓶颈,想通过硬件并行加速时 - 已经在使用
System.Numerics.Vector进行向量化编程,需要整合条件判断逻辑时
具体用法 & 示例
先说明:Vector<T>.Count的值由当前CPU支持的SIMD宽度决定,比如x64架构下,Vector<float>.Count通常是8,Vector<int>.Count通常是4——代码要适配这个动态值,同时处理剩余的非SIMD批次数据。
示例1:批量替换负数为0
这是最典型的场景,把数组中所有小于0的数替换成0,保留非负数:
using System; using System.Numerics; class NegativeToZeroExample { static void Main() { // 模拟一组包含正负值的测试数据 float[] input = { -1.2f, 3.4f, -5.6f, 7.8f, -9.0f, 2.3f, -4.5f, 6.7f }; float[] output = new float[input.Length]; // 定义替换用的0向量 Vector<float> zeroVector = Vector<float>.Zero; int vectorSize = Vector<float>.Count; // 按SIMD批次处理数据 int i = 0; for (; i <= input.Length - vectorSize; i += vectorSize) { // 从输入数组加载一个向量 Vector<float> inputVector = new Vector<float>(input, i); // 生成条件向量:每个位置标记原元素是否 >= 0 Vector<float> condition = Vector.GreaterThanOrEqual(inputVector, zeroVector); // 执行条件选择:条件为true时取原元素,否则取0 Vector<float> result = Vector.ConditionalSelect(condition, inputVector, zeroVector); // 将结果写回输出数组 result.CopyTo(output, i); } // 处理剩余的不足一个向量长度的数据 for (; i < input.Length; i++) { output[i] = input[i] >= 0 ? input[i] : 0; } // 打印结果 Console.WriteLine("原始数据:"); Console.WriteLine(string.Join(", ", input)); Console.WriteLine("\n处理后数据(负数替换为0):"); Console.WriteLine(string.Join(", ", output)); } }
代码解释:
- 用
Vector.GreaterThanOrEqual生成条件向量:每个位置的元素对应布尔值(true对应全1的位模式,false对应全0) ConditionalSelect会并行检查每个位置的条件:true取第一个向量的元素,false取第二个向量的元素- 最后把结果向量拷贝回数组,剩余数据用普通循环兜底
示例2:多条件分支的批量处理
如果需要多个条件判断(比如大于10的乘2,小于0的除以2,中间值保持不变),可以多次调用ConditionalSelect叠加逻辑:
using System; using System.Numerics; class MultiConditionExample { static void Main() { float[] input = { 15.2f, -3.4f, 7.6f, 12.8f, -5.0f, 9.3f, -1.5f, 20.7f }; float[] output = new float[input.Length]; Vector<float> tenVector = new Vector<float>(10f); Vector<float> zeroVector = Vector<float>.Zero; Vector<float> twoVector = new Vector<float>(2f); int vectorSize = Vector<float>.Count; int i = 0; for (; i <= input.Length - vectorSize; i += vectorSize) { Vector<float> inputVec = new Vector<float>(input, i); // 生成两个条件向量 Vector<float> greaterThanTen = Vector.GreaterThan(inputVec, tenVector); Vector<float> lessThanZero = Vector.LessThan(inputVec, zeroVector); // 第一步:处理大于10的元素,乘以2 Vector<float> tempResult = Vector.ConditionalSelect(greaterThanTen, Vector.Multiply(inputVec, twoVector), inputVec); // 第二步:处理小于0的元素,除以2 Vector<float> finalResult = Vector.ConditionalSelect(lessThanZero, Vector.Divide(inputVec, twoVector), tempResult); finalResult.CopyTo(output, i); } // 处理剩余元素 for (; i < input.Length; i++) { float val = input[i]; if (val > 10) output[i] = val * 2; else if (val < 0) output[i] = val / 2; else output[i] = val; } Console.WriteLine("原始数据:"); Console.WriteLine(string.Join(", ", input)); Console.WriteLine("\n处理后数据:"); Console.WriteLine(string.Join(", ", output)); } }
代码解释:
- 先通过
ConditionalSelect处理“大于10”的条件,生成中间结果 - 再用一次
ConditionalSelect处理“小于0”的条件,得到最终结果 - 这种叠加方式比循环里嵌套
if-else效率高得多,因为所有操作都是并行执行的
关键注意事项
- SIMD兼容性:不同CPU的SIMD宽度不同,
Vector<T>.Count会自动适配,所以必须处理剩余的非SIMD批次数据 - 条件向量的生成:条件向量只能由
Vector类的比较方法(GreaterThan、LessThan等)生成,这些方法返回的向量中,true对应全1的位模式,false对应全0 - 性能收益:只有数据量足够大时(比如上万级别的数组),SIMD的优势才会显现,小数据量用普通循环反而可能更快
内容的提问来源于stack exchange,提问作者MaYaN
相关产品推荐
相关产品推荐

