如何在 Rust 中获得高效的浮点最大值

问题描述 投票:0回答:1

我正在测试如何获得浮点数组的最大值:

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++ 相同的代码?

performance rust x86
1个回答
0
投票

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
© www.soinside.com 2019 - 2024. All rights reserved.