我正在测试如何获得浮点数组的最大值:
pub fn max(n: [f64;8]) -> f64 {
IntoIterator::into_iter(n).reduce(|a,b| a.max(b)).unwrap()
}
这给了我(夜间生锈)
vmovsd xmm0, qword ptr [rdi + 56]
vmovsd xmm1, qword ptr [rdi + 48]
vmovsd xmm2, qword ptr [rdi + 40]
vmovsd xmm3, qword ptr [rdi + 32]
vmovsd xmm4, qword ptr [rdi + 24]
vmovsd xmm5, qword ptr [rdi + 16]
vmovsd xmm6, qword ptr [rdi]
vmovsd xmm7, qword ptr [rdi + 8]
vcmpunordsd xmm8, xmm6, xmm6
vmaxsd xmm6, xmm7, xmm6
vblendvpd xmm6, xmm6, xmm7, xmm8
vcmpunordsd xmm7, xmm6, xmm6
vmaxsd xmm6, xmm5, xmm6
vblendvpd xmm5, xmm6, xmm5, xmm7
vcmpunordsd xmm6, xmm5, xmm5
vmaxsd xmm5, xmm4, xmm5
vblendvpd xmm4, xmm5, xmm4, xmm6
vcmpunordsd xmm5, xmm4, xmm4
vmaxsd xmm4, xmm3, xmm4
vblendvpd xmm3, xmm4, xmm3, xmm5
vcmpunordsd xmm4, xmm3, xmm3
vmaxsd xmm3, xmm2, xmm3
vblendvpd xmm2, xmm3, xmm2, xmm4
vcmpunordsd xmm3, xmm2, xmm2
vmaxsd xmm2, xmm1, xmm2
vblendvpd xmm1, xmm2, xmm1, xmm3
vcmpunordsd xmm2, xmm1, xmm1
vmaxsd xmm1, xmm0, xmm1
vblendvpd xmm0, xmm1, xmm0, xmm2
ret
所以我花了很多时间处理 NaN。我很确定
vmaxsd
与 Rust 中的 f64::max
的作用相同,但我不确定我是否忽略了某些东西。
所以我转向 C++ 并得到了
double max(double *num) {
double sum = num[0];
for (int i = 1; i < 8; i++) {
sum = std::max(sum, num[i]);
}
return sum;
}
编译为(在 gcc 14.1 上)
vmovsd xmm2, QWORD PTR [rdi]
vmovsd xmm1, QWORD PTR [rdi+8]
vmaxsd xmm0, xmm1, xmm2
vmovsd xmm1, QWORD PTR [rdi+16]
vmovsd xmm2, QWORD PTR [rdi+24]
vmaxsd xmm1, xmm1, xmm0
vmaxsd xmm0, xmm2, xmm1
vmovsd xmm2, QWORD PTR [rdi+32]
vmaxsd xmm1, xmm2, xmm0
vmovsd xmm2, QWORD PTR [rdi+40]
vmaxsd xmm0, xmm2, xmm1
vmovsd xmm2, QWORD PTR [rdi+48]
vmaxsd xmm1, xmm2, xmm0
vmovsd xmm0, QWORD PTR [rdi+56]
vmaxsd xmm0, xmm0, xmm1
ret
(没有快速数学选项,只有 -O3)
这让我相信 Rust 的汇编不是最优的,或者 C++ max 和 Rust max 的语义不同。
有人可以解释一下这个问题吗? 我怎样才能用 Rust 发出与 C++ 相同的代码?
std::max
使用 <
进行比较,因此它确实具有不同的语义,在 Rust 中使用相同的产生等效的程序集:
pub fn max(n: [f64;8]) -> f64 {
n.into_iter().reduce(|a,b| if a < b { b } else { a }).unwrap()
}
example::max::h17b765fea01ee3b1:
movsd xmm0, qword ptr [rdi + 56]
movsd xmm1, qword ptr [rdi + 48]
movsd xmm2, qword ptr [rdi + 40]
movsd xmm3, qword ptr [rdi + 32]
movsd xmm4, qword ptr [rdi + 24]
movsd xmm5, qword ptr [rdi + 8]
maxsd xmm5, qword ptr [rdi]
movsd xmm6, qword ptr [rdi + 16]
maxsd xmm6, xmm5
maxsd xmm4, xmm6
maxsd xmm3, xmm4
maxsd xmm2, xmm3
maxsd xmm1, xmm2
maxsd xmm0, xmm1
ret