gpt4 book ai didi

c# - 否定浮点变量的不同方法会生成不同的程序集

转载 作者:行者123 更新时间:2023-12-04 07:51:44 25 4
gpt4 key购买 nike

我有以下代码:

public static float F(float n) 
{
return -n;
}
生成以下 组装 :
Program.F(Single)
L0000: push eax
L0001: vzeroupper
L0004: vmovss xmm1, [esp+8]
L000a: vmovss xmm0, [Program.F(Single)] ; remember this line
L0012: vxorps xmm0, xmm0, xmm1 ; remember this line
L0016: vmovss [esp], xmm0
L001b: fld st, dword ptr [esp]
L001e: pop ecx
L001f: ret 4
另一方面,我有以下片段:
public static float G(float n) 
{
return n * -1;
}
它产生:
Program.G(Single)
L0000: push eax
L0001: vzeroupper
L0004: vmovss xmm0, [esp+8]
L000a: vmulss xmm0, xmm0, [Program.G(Single)] ; remember this line
L0012: vmovss [esp], xmm0
L0017: fld st, dword ptr [esp]
L001a: pop ecx
L001b: ret 4
问题
  • 正如您可能注意到的那样,输出略有不同。为什么我们有 2 个不同的程序集?代码不是执行完全相同的任务吗?
  • 有这么大块的组装的原因吗?如果是,为什么?
  • 我怎样才能获得更有效的版本。

  • 笔记
    注意 s 是最后一个问题。
    我想基本上获得“C”之类的程序集。例如。:
    float 
    f(float n) {
    return -n;
    }

    float
    g(float n) {
    return n * -1;
    }
    它产生:
    f:
    xorps xmm0, XMMWORD PTR .LC0[rip]
    ret
    g:
    xorps xmm0, XMMWORD PTR .LC0[rip]
    ret
    .LC0:
    .long -2147483648
    .long 0
    .long 0
    .long 0
  • 我尝试了以下操作,但效果不佳:

  • public static unsafe float F(float n) 
    {
    uint i = *(uint*)&n;

    i ^= 0x80000000;

    n = *(float*)&i;

    return n;
    }
    我得到了以下我认为效率更低的方法:
    Program.F(Single)
    L0000: sub esp, 8
    L0003: vzeroupper
    L0006: mov eax, [esp+0xc]
    L000a: mov [esp], eax
    L000d: mov eax, [esp]
    L0010: xor eax, 0x80000000
    L0015: mov [esp], eax
    L0018: vmovss xmm0, [esp]
    L001d: vmovss [esp+0xc], xmm0
    L0023: vmovss xmm0, [esp+0xc]
    L0029: vmovss [esp+4], xmm0
    L002f: fld st, dword ptr [esp+4]
    L0033: add esp, 8
    L0036: ret 4
  • 我犯了一个愚蠢的错误(见评论)。忘记切换 x64模式:

  • 现在我们有了一个“高效”的汇编代码:
    public static float F(float n) 
    {
    return -n;
    }

    public static float G(float n)
    {
    return n * -1;
    }
    C.F(Single)
    L0000: vzeroupper
    L0003: vmovss xmm1, [C.F(Single)]
    L000b: vxorps xmm0, xmm0, xmm1
    L000f: ret

    C.G(Single)
    L0000: vzeroupper
    L0003: vmulss xmm0, xmm0, [C.G(Single)]
    L000b: ret
    但我认为第一和第二个问题是有效的:

    Why do we have different ASM outputs here?

    最佳答案

    输出是不同的,原因很简单,编译器不像人类那样“思考”,而是遵循标准。

    public static float F(float n) 
    {
    return -n;
    }
    这意味着,要求编译器 否定 n并返回否定值。
    这正是编译器所做的
    vxorps xmm0, xmm0, xmm1    <--- change sign bit
    public static float G(float n) 
    {
    return n * -1;
    }
    这意味着做 乘法 ,这正是编译器所做的
    vmulss xmm0, xmm0, [C.G(Single)] <--- multiply
    在你的世界 (-n) == (n * -1)但是编译器对此有不同的看法。并且这两个表达式不一样。所以 (-n) != (n * -1)和汇编输出是不同的。
    更糟糕的是,对于浮点/ double 值 (a * b * c) != (c * b * a) ...

    好吧,至少不是默认情况下,您可以使用特殊的编译器标志使其相等,对不起,不记得它们到底是什么。

    关于c# - 否定浮点变量的不同方法会生成不同的程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66929770/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com