如果我有两个包含 u8
的数组,我可以将它们转换为更大的整数类型以减少我需要做的加法次数吗?例如,如果两个字节数组每个包含 4 个字节,我可以将它们每个都变成一个 u32
,进行加法,然后将它们转换回去吗?
例如:
let a = u32::from_ne_bytes([1, 2, 3, 4]);
let b = u32::from_ne_bytes([5, 6, 7, 8]);
let c = a + b;
let c_bytes = u32::to_ne_bytes(c);
assert_eq!(c_bytes, [6, 8, 10, 12]);
此示例产生正确的输出。
- 这是否总能产生正确的输出(假设没有溢出)?
- 这比单独添加要快吗?
- 它是否适用于其他整数类型?例如
u32
中的 2 个u16
添加了u32
中的另外 2 个u16
?
如果这存在并且很常见,它叫什么?
最佳答案
- Does this always result in the right output (assuming there is no overflow)?
是的。如果每个总和小于 256,这将根据需要添加字节。您在每种情况下都指定了“ne”,以实现 native 字节序。这将起作用,无论 native 字节序如何,因为操作是按字节进行的。
如果您编写代码来实际检查总和是否在范围内,那么您几乎肯定会撤消您获得的任何额外加速(如果有的话)。
- Is this faster than just doing the additions individually?
也许吧。唯一确定的方法就是测试。
- Does it hold true for other integer types? Such as 2
u16
s in au32
added with 2 otheru16
s in au32
?
可以,但是需要注意字节序。
If this exists and is common, what is it called?
这并不常见,因为它通常是不必要的。这种类型的优化使代码更难阅读,并引入相当大的复杂性和错误机会。 Rust 编译器和它们之间的 LLVM 能够找到您永远不会想到的极其复杂的优化,同时您的代码保持可读性和可维护性。
如果它有一个名字,那就是 SIMD,大多数现代处理器本身都支持它的一种形式(SSE、MMX、AVX)。您可以使用内置函数手动执行此操作,例如core::arch::x86_64::_mm_add_epi8
,但 LLVM 可能会自动执行。尝试手动执行此操作可能会干扰 LLVM 否则会进行的优化,同时使您的代码更容易出错。
无论如何我都不是汇编代码专家,但我看了一下 assembly generated对于以下两个函数:
#[no_mangle]
#[inline(never)]
pub fn f1(a1: u8, b1: u8, c1: u8, d1: u8, a2: u8, b2: u8, c2: u8, d2: u8) -> [u8; 4]{
let a = u32::from_le_bytes([a1, b1, c1, d1]);
let b = u32::from_le_bytes([a2, b2, c2, d2]);
u32::to_le_bytes(a + b)
}
#[no_mangle]
#[inline(never)]
pub fn f2(a1: u8, b1: u8, c1: u8, d1: u8, a2: u8, b2: u8, c2: u8, d2: u8) -> [u8; 4]{
[a1 + a2, b1 + b2, c1 + c2, d1 + d2]
}
f1
的程序集:
movzx r10d, byte ptr [rsp + 8]
shl ecx, 24
movzx eax, dl
shl eax, 16
movzx edx, sil
shl edx, 8
movzx esi, dil
or esi, edx
or esi, eax
or esi, ecx
mov ecx, dword ptr [rsp + 16]
shl ecx, 24
shl r10d, 16
movzx edx, r9b
shl edx, 8
movzx eax, r8b
or eax, edx
or eax, r10d
or eax, ecx
add eax, esi
ret
对于f2
:
add r8b, dil
add r9b, sil
add dl, byte ptr [rsp + 8]
add cl, byte ptr [rsp + 16]
movzx ecx, cl
shl ecx, 24
movzx edx, dl
shl edx, 16
movzx esi, r9b
shl esi, 8
movzx eax, r8b
or eax, esi
or eax, edx
or eax, ecx
ret
较少的指令不一定会使它更快,但这不是一个坏的准则。
在仔细测量和测试后,将这种优化视为最后的手段。
关于math - 通过将它们转换为更大的整数数据类型来一次添加整个字节数组是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58000264/