什么系列的内在函数会完成这个路径预测代码?

如何解决什么系列的内在函数会完成这个路径预测代码?

我有一个对数组进行操作的 Paeth 预测函数:

std::array<std::uint8_t,4> birunji::paeth_prediction
    (const std::array<std::uint8_t,4>& a,const std::array<std::uint8_t,4>& b,4>& c)
{
    std::array<std::int16_t,4> pa;
    std::array<std::int16_t,4> pb;
    std::array<std::int16_t,4> pc;

    std::array<std::uint8_t,4> results;

    for(std::size_t i = 0; i < 4; ++i)
    {
        pa[i] = b[i] - c[i];
        pb[i] = a[i] - c[i];
        pc[i] = pa[i] + pb[i];

        pa[i] = std::abs(pa[i]);
        pb[i] = std::abs(pb[i]);
        pc[i] = std::abs(pc[i]);

        if(pa[i] <= pb[i] && pa[i] <= pc[i])
            results[i] = a[i];
        else if(pb[i] <= pc[i])
            results[i] = b[i];
        else
            results[i] = c[i];
    }

    return results;
}

我正在尝试手动使用内部函数来矢量化代码(用于学习目的)。

__m128i birunji::paeth_prediction(const __m128i& a,const __m128i& b,const __m128i& c)
{
    __m128i pa = _mm_sub_epi16(b,c);
    __m128i pb = _mm_sub_epi16(a,c);
    __m128i pc = _mm_add_epi16(pa,pb);
    
    pa = _mm_abs_epi16(pa);
    pb = _mm_abs_epi16(pb);
    pc = _mm_abs_epi16(pc);

    __m128i pa_le_pb = _mm_cmpgt_epi16(pb,pa);
    __m128i pa_le_pc = _mm_cmpgt_epi16(pc,pa);
    __m128i pb_le_pc = _mm_cmpgt_epi16(pc,pb);

    return
    _mm_and_si128(_mm_and_si128(pa_le_pb,pa_le_pc),_mm_and_si128(_mm_and_si128(pb_le_pc,b),a));
}

我遇到的问题是条件语句。我如何成功矢量化这些?我不确定我上面的尝试是否正确。

解决方法

_mm_cmpgt_epi16 可用于比较。请注意,_mm_cmpgt_epi16(a,b) = !(a <= b)_mm_cmpgt_epi16(b,a) != (a <= b) 不同,因为它不是大于或等于比较,而是严格的大于比较。所以掩码是反转的,但这在这种情况下同样有用,不需要显式反转。

这个函数本身不应该返回一个条件,它应该根据条件从abc中选择。如果 SSE4.1 可用,则可以使用 _mm_blendv_epi8 来实现该选择。例如(未测试):

__m128i paeth_prediction(__m128i a,__m128i b,__m128i c)
{
    __m128i pa = _mm_sub_epi16(b,c);
    __m128i pb = _mm_sub_epi16(a,c);
    __m128i pc = _mm_add_epi16(pa,pb);
    
    pa = _mm_abs_epi16(pa);
    pb = _mm_abs_epi16(pb);
    pc = _mm_abs_epi16(pc);

    __m128i not_pa_le_pb = _mm_cmpgt_epi16(pa,pb);
    __m128i not_pa_le_pc = _mm_cmpgt_epi16(pa,pc);
    __m128i not_pb_le_pc = _mm_cmpgt_epi16(pb,pc);
    __m128i not_take_a = _mm_or_si128(not_pa_le_pb,not_pa_le_pc);
    __m128i t = _mm_blendv_epi8(b,c,not_pb_le_pc);
    return _mm_blendv_epi8(a,t,not_take_a);
}

最后两行实现如下逻辑:

如果PB不小于或等于PC,取C,否则取B。
如果 PA 不小于或等于 PB PA 不小于或等于 PC,则取上一步的结果,否则取 A。 >

如果没有 SSE4.1,可以使用 AND/ANDNOT/OR 实现混合。

我已经更改了函数的签名,因此它按值获取向量,通过常量引用获取它们是不必要的(向量很容易复制)并且可以从间接增加开销,尽管这种开销可能会被删除如果函数最终被编译器内联。

作为变体,_mm_min_epi16 可用于实现部分逻辑:

__m128i paeth_prediction(__m128i a,pb);
    
    pa = _mm_abs_epi16(pa);
    pb = _mm_abs_epi16(pb);
    pc = _mm_abs_epi16(pc);

    __m128i not_pb_le_pc = _mm_cmpgt_epi16(pb,pc);
    __m128i take_a = _mm_cmpeq_epi16(pa,_mm_min_epi16(pa,_mm_min_epi16(pb,pc)));
    __m128i t = _mm_blendv_epi8(b,not_pb_le_pc);
    return _mm_blendv_epi8(t,a,take_a);
}

因为条件 pa <= pb && pa <= pc 等价于 pa == min(pa,pb,pc)

生成的汇编代码看起来好一点,但我没有以任何方式对其进行测试,包括性能。

,

您可以通过完全避免转换为 int16_t 来简化计算。 首先,请注意 pa<=pcpb<=pc 当且仅当 a<=c<=bb<=c<=a 为真。如果 c 小于或等于两者,则返回 max(a,b);如果 c 大于或等于,则返回 min(a,b)

所以我们可以先使用ab操作对minmax进行“排序”,

A = min(a,b)
B = max(a,b)

剩下三种可能的情况:

A<=B<=c  --> A
c<=A<=B  --> B
A< c< B  --> c

这意味着在 C++ 代码中

std::array<std::uint8_t,4> birunji::paeth_prediction
    (const std::array<std::uint8_t,4>& a,const std::array<std::uint8_t,4>& b,4>& c)
{
    std::array<std::uint8_t,4> results;

    for(std::size_t i = 0; i < 4; ++i)
    {
        uint8_t A = std::min(a[i],b[i]);
        uint8_t B = std::max(a[i],b[i]);
        if     (B<=c[i]) results[i] = A;
        else if(c[i]<=A) results[i] = B;
        else             results[i] = c[i];
    }

    return results;
}

不幸的是,没有无符号 SIMD 比较(在 AVX-512 之前),但我们可以使用 (x<=y) == (max(x,y)==y)(或进行饱和减法并与零比较。

可能的(未经测试的)SIMD 实现(这也适用于任意多个元素——但您可以只加载最低 32 位中的四个元素并忽略结果的其余部分):

__m128i paeth_prediction(__m128i a,__m128i c)
{
    __m128i A = _mm_min_epu8(a,b);
    __m128i B = _mm_max_epu8(a,b);

    __m128i A_greater_equal_c = _mm_cmpeq_epi8(_mm_max_epu8(A,c),A);
    __m128i B_less_equal_c    = _mm_cmpeq_epi8(_mm_min_epu8(B,B);

    // if you don't have SSE 4.1,this can be done using bitwise and/or operations:
    __m128i t = _mm_blendv_epi8(b,A_greater_equal_c);
    return _mm_blendv_epi8(a,B_less_equal_c);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res