使用 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 < 0
则 x < 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 是在乘法以这种可预测的方式溢出的标准之前创建的。
所以,如果我将两个值相乘: 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 < 0
则 x < 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 是在乘法以这种可预测的方式溢出的标准之前创建的。