使用 emacs lisp 时,如果值超过 most-negative-number

When using emacs lisp, if the value exceed most-negative-number

所以,如果我将两个值相乘: emacs -batch -eval '(打印 (* 1252463 -4400000000000))' 它将超过 most-negative-fixnum 帧,并且会 return 数学上错误的答案。之间的教学水平会有什么差异 -O2 标志、-O2 -fsanitize=undefined 标志和 -O2 -fwrapv 标志?

在 emacs 中?可能什么都没有。编译后的函数大概是这样的:

int multiply(int x, int y) {
    return x * y;
}

如果我们编译它并查看程序集 (gcc -S multiply.c && cat multiply.s),我们得到

multiply:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %eax
    imull   -8(%rbp), %eax
    popq    %rbp
    ret

看到imull指令了吗?它正在做一个规则的乘法。如果我们尝试 gcc -O2 -S multiply.c 怎么办?

multiply:
    movl    %edi, %eax
    imull   %esi, %eax
    ret

嗯,这当然删除了一些代码,但它仍在执行 imull,常规乘法。

让我们试着让它不要使用 imull:

int multiply(int x) {
    return x * 2;
}

gcc -O2 -S multiply.c,我们得到

multiply:
    leal    (%rdi,%rdi), %eax
    ret

它没有计算较慢的 x * 2,而是计算 x + x,因为加法比乘法快。

我们可以让 -fwrapv 生成不同的代码吗?是:

int multiply(int x) {
    return x * 2 < 0;
}

gcc -O2 -S multiply.c,我们得到

multiply:
    movl    %edi, %eax
    shrl    , %eax
    ret

所以简化为x >> 31,与x < 0是一回事。在数学中,如果 x * 2 < 0x < 0。但在处理器的现实中,如果 x * 2 溢出,它可能会变成负数,例如 2,000,000,000 * 2 = -294967296.

如果你用 gcc -O2 -fwrapv -S temp.c 强制 gcc 考虑到这一点,我们得到

multiply:
    leal    (%rdi,%rdi), %eax
    shrl    , %eax
    ret

于是将x * 2 < 0优化为x + x < 0-fwrapv 不是默认值可能看起来很奇怪,但 C 是在乘法以这种可预测的方式溢出的标准之前创建的。