如何用一个非零值初始化数组
How to initialize array with one non-zero value
我正在创建一个数字类型,它使用数组来存储数字。为了实现特征 One
,我发现自己编写了这样的代码:
fn one() -> Self {
let mut ret_array = [0; N];
ret_array[0] = 1;
Self(ret_array)
}
有没有其他方法可以用一个个非零元素初始化数组?
我不这么认为,不。
但是 Rust 编译器理解您想要实现的目标并且 optimizes it accordingly:
pub fn one<const N: usize>() -> [i32; N] {
let mut ret_array = [0; N];
ret_array[0] = 1;
ret_array
}
pub fn one_with_length_5() -> [i32; 5] {
one()
}
example::one_with_length_5:
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi + 4], xmm0
mov dword ptr [rdi], 1
ret
xorps xmm0, xmm0
将 16 字节(或 4 整数)SSE 寄存器 xmm0
设置为 [0,0,0,0]。
movups xmmword ptr [rdi + 4], xmm0
将 xmm0
寄存器的所有 4 个整数复制到位置 [rdi + 4]
,即 ret_array
的元素 1、2、3 和 4。
mov dword ptr [rdi], 1
将值 1
移动到 ret_array
的第一个元素。
ret_array
是在[=25=的位置],[rdi + 4]
是在[=27=的位置的元素],[rdi + 8]
是在[=29的位置的元素=],等等
如您所见,它仅将其他四个值初始化为 0,然后将第一个值设置为 1。第一个值不会被写入两次。
小提示
如果您将 N
设置为例如8
,它确实实际上写了两次值:
example::one_with_length_8:
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi + 16], xmm0
movups xmmword ptr [rdi + 4], xmm0
mov dword ptr [rdi], 1
ret
有趣的是,它实际上并没有写两次值[0]
,而是写了值[4]
。它一次写入 [1,2,3,4]
,然后写入 [4,5,6,7]
,然后写入 [0]
。
但那是因为这是最快的方法。它在 SSE 寄存器中存储 4 个零整数,然后 zero-initializes 向量一次存储 4 个整数。在没有 4-int SSE 命令帮助的情况下,两次写入 int 比初始化其他值更快。
如果您完全手动初始化它,甚至会发生这种情况:
pub fn one_with_length_8() -> [i32; 8] {
[1,0,0,0,0,0,0,0]
}
example::one_with_length_8:
mov rax, rdi
mov dword ptr [rdi], 1
xorps xmm0, xmm0
movups xmmword ptr [rdi + 4], xmm0
movups xmmword ptr [rdi + 16], xmm0
ret
你可以看到顺序不同,但指令是相同的。
我正在创建一个数字类型,它使用数组来存储数字。为了实现特征 One
,我发现自己编写了这样的代码:
fn one() -> Self {
let mut ret_array = [0; N];
ret_array[0] = 1;
Self(ret_array)
}
有没有其他方法可以用一个个非零元素初始化数组?
我不这么认为,不。
但是 Rust 编译器理解您想要实现的目标并且 optimizes it accordingly:
pub fn one<const N: usize>() -> [i32; N] {
let mut ret_array = [0; N];
ret_array[0] = 1;
ret_array
}
pub fn one_with_length_5() -> [i32; 5] {
one()
}
example::one_with_length_5:
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi + 4], xmm0
mov dword ptr [rdi], 1
ret
xorps xmm0, xmm0
将 16 字节(或 4 整数)SSE 寄存器xmm0
设置为 [0,0,0,0]。movups xmmword ptr [rdi + 4], xmm0
将xmm0
寄存器的所有 4 个整数复制到位置[rdi + 4]
,即ret_array
的元素 1、2、3 和 4。mov dword ptr [rdi], 1
将值1
移动到ret_array
的第一个元素。ret_array
是在[=25=的位置],[rdi + 4]
是在[=27=的位置的元素],[rdi + 8]
是在[=29的位置的元素=],等等
如您所见,它仅将其他四个值初始化为 0,然后将第一个值设置为 1。第一个值不会被写入两次。
小提示
如果您将 N
设置为例如8
,它确实实际上写了两次值:
example::one_with_length_8:
mov rax, rdi
xorps xmm0, xmm0
movups xmmword ptr [rdi + 16], xmm0
movups xmmword ptr [rdi + 4], xmm0
mov dword ptr [rdi], 1
ret
有趣的是,它实际上并没有写两次值[0]
,而是写了值[4]
。它一次写入 [1,2,3,4]
,然后写入 [4,5,6,7]
,然后写入 [0]
。
但那是因为这是最快的方法。它在 SSE 寄存器中存储 4 个零整数,然后 zero-initializes 向量一次存储 4 个整数。在没有 4-int SSE 命令帮助的情况下,两次写入 int 比初始化其他值更快。
如果您完全手动初始化它,甚至会发生这种情况:
pub fn one_with_length_8() -> [i32; 8] {
[1,0,0,0,0,0,0,0]
}
example::one_with_length_8:
mov rax, rdi
mov dword ptr [rdi], 1
xorps xmm0, xmm0
movups xmmword ptr [rdi + 4], xmm0
movups xmmword ptr [rdi + 16], xmm0
ret
你可以看到顺序不同,但指令是相同的。