为什么我们使用mask来削减字节?

克莱门特·奈尔玛

所以我想这很愚蠢,但我自己找不到答案。

几天前,我不得不创建一个函数,该函数返回无符号整数的强字节。在网上进行了一些研究之后,我想到了这一点:

fn strong_byte(num: u32) -> u8 {
  ((num >> 24) & 0xFF) as u8
}

但是再次搜索了一会后,我也发现了这个:

fn strong_byte(num: u32) -> u8 {
  (num << 24 >> 24) as u8
}

所以我想知道哪种形式表现更好?我试图找到显示左移与位掩码性能的基准,但没有发现任何东西。

我知道第一种语法是迄今为止使用最广泛的语法,但我不明白为什么第二种语法没有使用...

红发女郎

积分也应归功于他人,请参阅问题下方的注释。

术语

什么是强字节您应该使用最低有效字节(LSB)或最高有效字节(MSB)。

您的职能

我添加_1_2后缀的名称,只是为了区分它们。

fn strong_byte_1(num: u32) -> u8 {
  ((num >> 24) & 0xFF) as u8
}
fn strong_byte_2(num: u32) -> u8 {
  (num << 24 >> 24) as u8
}

这两个功能做不同的事情。猜猜输出...

fn main() {
    println!("{}", strong_byte_1(255));
    println!("{}", strong_byte_2(255));
}

...是。_1返回0_2返回255_1返回MSB和_2回报LSB。如果要比较它们,必须修复它们。

strong_byte_1实现包含不必要的位掩码。((num >> 24) & 0xFF) as u8等于(num >> 24) as u8此处查看Shepmaster的答案>>操作包含脚注:

有符号整数类型的算术右移,无符号整数类型的逻辑右移。

u32是无符号的->逻辑右移(请参阅Logical shift),这意味着:

0b11111111000000000000000000000000 >> 1 == 0b01111111100000000000000000000000
0b01111111100000000000000000000000 >> 1 == 0b00111111110000000000000000000000
0b00111111110000000000000000000000 >> 1 == 0b00011111111000000000000000000000
...
0b00000000000000000000000111111110 >> 1 == 0b00000000000000000000000011111111

最低位

让我们重写它们,以便两者都返回LSB。

fn lsb_1(num: u32) -> u8 {
  (num & 0xFF) as u8
}
fn lsb_2(num: u32) -> u8 {
  (num << 24 >> 24) as u8
}

更有表现力吗?

锈1.36&opt-level = 0

example::lsb_1:
        and     edi, 255
        mov     al, dil
        ret

example::lsb_2:
        push    rax
        shl     edi, 24
        mov     dword ptr [rsp + 4], edi
        mov     eax, dword ptr [rsp + 4]
        shr     eax, 24
        mov     dword ptr [rsp], eax
        mov     eax, dword ptr [rsp]
        mov     cl, al
        mov     al, cl
        pop     rcx
        ret

生锈1.36.0&opt-level = 1

example::lsb_1:
        mov     eax, edi
        ret

example::lsb_2:
        mov     eax, edi
        ret

MSB

fn msb(num: u32) -> u8 {
  (num >> 24) as u8
}

生锈1.36.0&opt-level = 0

example::msb:
        sub     rsp, 4
        shr     edi, 24
        mov     dword ptr [rsp], edi
        mov     eax, dword ptr [rsp]
        mov     cl, al
        mov     al, cl
        add     rsp, 4
        ret

生锈1.36.0&opt-level = 1

example::msb:
        mov     eax, edi
        shr     eax, 24
        ret

结论

更有表现力吗?查看编译器输出(程序集),查阅目标体系结构文档等。您正在使用什么编译器?哪个版本?您的目标架构是什么?换句话说-您的问题太广泛了。

提到的Compiler Explorer是一个不错的工具,可用于检查编译器的输出是什么。

一般来说,您应该完成程序,使其正常运行,然后进行优化。您的程序将做很多其他事情,并且将包含更多的瓶颈。度量,优化,回滚,优化,度量,提交...……但要使用最终产品,而不仅仅是简单的例程。您可以花费很少的时间进行过早的优化(因此没有用)。然后您会发现您优化了一个例程,但是您的程序正在等待其他事件(网络,...),在其他地方有问题,...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么我们使用损失来更新我们的模型,但使用指标来选择我们需要的模型?

为什么我们使用 alpine 镜像来创建我们的自定义镜像

为什么我们使用@staticmethod?

为什么我们使用抽象

我们为什么使用@Autowire

为什么我们使用TaskStackBuilder?

为什么我们使用“NULL”?

为什么我们使用setLayoutParams?

为什么我们使用()=> []而不是[]?

为什么我们使用扩展?

为什么我们使用字节寻址而不是字寻址?

为什么我们使用entrySet()方法并使用返回的集来迭代地图?

为什么我们需要在应用加载时使用 BeginInvokeOnMainThread 来显示 DisplayAlert

为什么我们使用非静态属性来锁定非静态字段?

为什么我们仍然使用HTTP而不是WebSocket来构建Web应用程序?

为什么我们使用 `i` 作为变量来控制 Javascript 循环?

为什么我们使用方括号而不是定义括号的方式来调用vec宏?

为什么我们不能使用push方法来迭代javascript数组?

为什么我们使用“/”来标记 MySQL 查询的结束?

为什么我们使用 val 而不是 var 来记住 Jetpack Compose 中的可变状态?

为什么我们需要使用线程来运行Kafka使用者?我们需要多少个线程?

为什么我们使用序列化程序而不是完全干净来验证模型,或者我们应该互换使用它们?

为什么我们使用函数calc和stack来做栅格计算?这比直接使用我们的欲望函数更好吗?

为什么我们使用SASS,甚至我们也在使用SCSS?

在OCaml中,我们为什么有'+。','-。' 但是我们仅使用“ <”而不是“ <。”?

为什么我们需要安装 http 模块来运行我们的 node js 应用程序?

为什么我们需要使用标记接口?

为什么我们使用WebDriver而不是Selenium IDE?

为什么我们使用 try,除了在 Python 中