- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在做 CSAPP 的 datalab,isGreater 函数。
这是描述
isGreater - if x > y then return 1, else return 0
Example: isGreater(4,5) = 0, isGreater(5,4) = 1
Legal ops: ! ~ & ^ | + << >>
Max ops: 24
Rating: 3
int isGreater(int x, int y)
{
int yComplement = ~y + 1;
int minusResult = x + yComplement; // 0xffffffff
int SF = (minusResult >> 31) & 0x1; // 1
int ZF = !minusResult; // 0
int xSign = (x >> 31) & 0x1; // 0
int ySign = (yComplement >> 31) & 0x1; // 1
int OF = !(xSign ^ ySign) & (xSign ^ SF); // 0
return !(OF ^ SF) & !ZF;
}
最佳答案
您在加法 x + yComplement
中检测到溢出, 而不是在整体减法 -INT_MIN
本身在 2 的补码中溢出; INT_MIN == -INT_MIN
.这是 the 2's complement anomaly 1.
您应该对任何负数(除 INT_MIN
外)减去 INT_MIN
进行快速正溢出检测.由此产生的加法将有符号溢出。例如-10 + INT_MIN
溢出。
http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt有一个用于加法和减法的输入/输出符号表。溢出的情况是输入符号相反但结果符号匹配 y
.
SUBTRACTION SIGN BITS (for num1 - num2 = sum)
num1sign num2sign sumsign
---------------------------
0 0 0
0 0 1
0 1 0
*OVER* 0 1 1 (subtracting a negative is the same as adding a positive)
*OVER* 1 0 0 (subtracting a positive is the same as adding a negative)
1 0 1
1 1 0
1 1 1
您可以直接将其与原始
x
一起使用和
y
,并且只使用
yComplement
作为获取
minusResult
的一部分.调整您的逻辑以匹配此真值表。
int ySign = (~y) >> 31;
并保留其余代码不变 . (使用 tmp 来保存
~y
所以你只做一次操作,对于这个和
yComplement
)。一个的补码逆 (
~
) 不会受到 2 的补码异常的影响。
unsigned
为了避免这个问题。
int
不能代表
INT_MIN
的绝对值.
unsigned int
,你不需要
& 1
移位后,因为逻辑移位不进行符号扩展。 (作为奖励,它可以避免
+
:
http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html 中的 C 签名溢出未定义行为)。
uint32_t
或
sizeof(unsigned) * CHAR_BIT
而不是 31)您将拥有安全且可移植的 2 补码比较实现。 (负数的有符号移位语义是在 C 中实现定义的。)我认为您将 C 用作一种用于位操作的伪代码,并且对实际编写可移植实现不感兴趣,这很好。您的处理方式适用于普通 CPU 上的普通编译器。
& 0x80000000
将高位保留在原位(但是您必须左移您的
!
结果)。
It's just the lab's restriction, you can't use unsigned or any constant larger than 0xff(255)
&1
.可以处理您只关心低位的数字,但其余的都是垃圾。
& !ZF
,即
&0
或 &1
. Thus, any high garbage in
OF` 被抹去。
>> 31
直到对两个数字进行异或运算之后。
// untested, 13 operations
int isGreater_optimized(int x, int y)
{
int not_y = ~y;
int minus_y = not_y + 1;
int sum = x + minus_y;
int x_vs_y = x ^ y; // high bit = 1 if they were opposite signs: OF is possible
int x_vs_sum = x ^ sum; // high bit = 1 if they were opposite signs: OF is possible
int OF = (x_vs_y & x_vs_sum) >> 31; // high bits hold garbage
int SF = sum >> 31;
int non_zero = !!sum; // 0 or 1
return (~(OF ^ SF)) & non_zero; // high garbage is nuked by `& 1`
}
注意使用
~
而不是
!
反转具有高垃圾的值。
x ^ sum
是
&
的输入,然后我们与 sum 异或。
// replace 31 with sizeof(int) * CHAR_BIT if you want. #include <limit.h>
// or use int32_t
int isGreater_optimized2(int x, int y)
{
int not_y = ~y;
int minus_y = not_y + 1;
int sum = x + minus_y;
int SF = sum; // value in the high bit, rest are garbage
int x_vs_y = x ^ y; // high bit = 1 if they were opposite signs: OF is possible
int x_vs_sum = x ^ sum; // high bit = 1 if they were opposite signs: OF is possible
int OF = x_vs_y & x_vs_sum; // low bits hold garbage
int less = (OF ^ SF);
int ZF = !sum; // 0 or 1
int le = (less >> 31) & ZF; // clears high garbage
return !le; // jg == jnle
}
我想知道是否有任何编译器可能会看穿这本手册并将其优化为
cmp edi, esi
/
setg al
,但没有这样的运气:/我想这不是他们寻找的模式,因为本可以编写为
x > y
的代码倾向于这样写:P
关于c - 模拟 jg 指令(datalab 的 isGreater),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51168010/
我想了解 cmp 和 je/jg 在汇编中是如何工作的。我在谷歌上看到了几个例子,但我还是有点困惑。下面我展示了我试图转换为 C 语言的汇编代码的一部分以及相应的 C 代码。它是以正确的方式实现的还是
所以每个在线资源都告诉我这样的事情: cmp %eax, %ebx jg 如果 eax 大于 ebx, 将跳转到 。但我有另一段代码似乎与此相矛盾: cmp $0x2, %eax jg 当 ea
我无法理解汇编语言的 ja 和 jg 之间的区别。我有一段代码: cmp dh, dl j-- hit 我询问哪个条件跳转命中(替换 j-- 命中)将采用 DX = 0680 的十六进制值。 这会
我不明白 CMP 之后的 JG/JNLE/JL/JNGE 指令。 例如,如果我有: CMP al,dl jg label1 当al=101时; dl =200。 我们问jg什么?是在 al>dl 上吗
我在做 CSAPP 的 datalab,isGreater 函数。 这是描述 isGreater - if x > y then return 1, else return 0 Example
我尝试解决如下所示的问题; 仅使用 and、jg 或 jle,如何实现以下代码? if %eax > 4 jmp do else jmp l1 当然不改
我在将 JScrollPane 添加到具有面板的框架时遇到问题,并且我想将面板布局保持为空。 如果我使用任何布局,则 JScrollPane 会出现,但当我使用布局为 null 时不会出现 这是我的代
一、前言 在前期完成 uni-app 实现 Android 原生APP-云打包集成极光推送(JG-JPUSH)操作后,接下来需要 uni-app 实现 IOS 原生APP-云打包集成极光推送(JG-J
一、前言 因项目需求,需要uni-app 原生APP-云打包集成极光推送,现将集成过程梳理得出此文。 二、资源 首先,我们需要用到的一些插件以及极光平台官网链接: 极光推送官方SDK 极光JCore官
一、前言 因项目需求,需要uni-app 原生APP-本地打包集成极光推送,现将集成过程梳理得出此文。 二、集成 2.1 uni-app 项目集成至 Android Studio 2.1.1 拷贝Hb
我是一名优秀的程序员,十分优秀!