Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 绝对值,不带分支或移位,仅加/减和布尔值_Assembly_X86_Bit Manipulation_Absolute Value - Fatal编程技术网

Assembly 绝对值,不带分支或移位,仅加/减和布尔值

Assembly 绝对值,不带分支或移位,仅加/减和布尔值,assembly,x86,bit-manipulation,absolute-value,Assembly,X86,Bit Manipulation,Absolute Value,我们在学校遇到这个问题是为了那些想测试自己的学生。我在这方面花了相当长的时间,但还是搞不懂 AX寄存器中有16位数字,该数字是有符号的。得到它 绝对值,AX中的数字必须保持不变 (编辑:没有限定的寄存器数量,AX寄存器可以更改,但在函数结束时,它需要是原始编号),答案是 应该是BX。您只能使用以下说明: MOV、ADD、XOR、SUB、NOT和或NEG 像编译器那样使用SAR是很容易的,但是如果没有它,就不清楚如何获得任何以符号位为条件的行为。愚蠢的想法#1:查找表。这在16位实模式下无法工作。

我们在学校遇到这个问题是为了那些想测试自己的学生。我在这方面花了相当长的时间,但还是搞不懂

AX寄存器中有16位数字,该数字是有符号的。得到它 绝对值,AX中的数字必须保持不变 (编辑:没有限定的寄存器数量,AX寄存器可以更改,但在函数结束时,它需要是原始编号),答案是 应该是BX。您只能使用以下说明:
MOV、ADD、XOR、SUB、NOT和或NEG

像编译器那样使用SAR是很容易的,但是如果没有它,就不清楚如何获得任何以符号位为条件的行为。

愚蠢的想法#1:查找表。这在16位实模式下无法工作。即使一张桌子有一整段64kiB的内存也是不够的;我们需要两倍于此才能查找任何可能的16位值的2字节结果

我们可以通过32位寻址轻松实现这一点,如
xor ebx,ebx
/
mov bx,ax
/
mov bx,[table+ebx*2]
,如果您可以证明128kiB的表数据是合理的:P


完全按照规则,您可以使用
sub esp,1以32位或64位模式在堆栈上构建表。因此,多亏了Peter Cordes的回答,代码非常简单,问题在于SAR指令,但Peter创建得非常好

中的号码已加载到AX

; this is practicaly the SAR instruction, 
; the mask for the absolute value is 
; number >> (sizeof(short)) * CHAR_BIT -1)
; number >>        (2 * 8) - 1 = 15
; so normaly we would do SAR bx, 15 and done

mov bl, ah  ; BX = AX>>8
add bx, bx  ; BX <<= 1
neg bh      ; 0 or -1 
mov bl, bh  ; duplicate the full BX

mov cx, ax  ;
add cx, bx  ; the number + mask 
xor bx, cx  ; (number+mask) ^ mask 
;这是实际的SAR指令,
; 绝对值的掩码为
; 数字>>(sizeof(short))*字符位-1)
; 编号>>(2*8)-1=15
; 正常情况下,我们会做SAR bx,15,完成
mov bl,啊,;BX=AX>>8

添加bx,bx;BX最小值-2^16的绝对值不能用16位表示?@qwr:该问题的解决方案是输入是有符号的,结果是无符号的。因此,
0x8000
32768
)是输入
0x8000
-32768
)的正确绝对值结果。这在asm中很容易,在C中很麻烦,您可能需要编写类似于
(x<0)的东西?0U-x:(无符号)x以避免导致签名溢出。但这会在减法之前将
x
转换为无符号,因此它可能只适用于2的补码。IDK,C有时真的很难使用。我们的教授每学期都会发这个,他说在过去的10年里,他在那里只有7个人能做到,每个学期大约有800名新生。我用SAR做的很简单:
mov-ax,[esp+8]mov-bx,ax-SAR-bx,15-mov-cx,ax-add-cx,bx-xor-bx,cx
这篇文章被编辑成这样,我相信你可以使用两个以上registers@qwr:是的,我注意到了;这使得第二部分不是一个挑战。彼得·科德斯:对不起,我不确定,所以我不得不问教授,没有具体说明它是否启用。我对逐位运算不太熟悉,所以你的解释很有帮助,再次感谢。@AdamĎuriník:更新,很高兴听到没有我丢失的任何划痕空间的方法。7人超过10年听起来对一年级的学生来说是合适的,他们大多是asm的初学者!感谢您将其传递给我们。“通常”您将
cwd
签名将AX扩展为DX:AX,即设置DX=0或-1。无论如何,在问题的第一个版本中,我认为我们不允许使用任何其他寄存器,否则不修改AX的限制是微不足道的。
    neg  dh               ; 0 or -1 according to sign bit of AX
    mov  dl, dh           ; duplicate to the full DX = 0 or -1
    mov  bx, ax
    xor  bx, dx           ; ~x      or x
    sub  bx, dx           ; ~x + 1  or x
unsigned absval(int x) {
    return x<0 ? 0U - x : x;
}
    mov     eax, edi
    cdq                      ; sign-extend EAX into EDX:EAX
    xor     eax, edx
    sub     eax, edx
    ret
    mov     eax, edi
    neg     eax                 ; 0 - x
    cmovl   eax, edi            ; copy the original if 0 was < x
    ret
    ; shorter critical path on CPUs where mov is not zero latency
    xor     eax, eax
    sub     eax, edi            ; 0 - x
    cmovl   eax, edi            ; copy the original if 0 was < x
    ret
; this is practicaly the SAR instruction, 
; the mask for the absolute value is 
; number >> (sizeof(short)) * CHAR_BIT -1)
; number >>        (2 * 8) - 1 = 15
; so normaly we would do SAR bx, 15 and done

mov bl, ah  ; BX = AX>>8
add bx, bx  ; BX <<= 1
neg bh      ; 0 or -1 
mov bl, bh  ; duplicate the full BX

mov cx, ax  ;
add cx, bx  ; the number + mask 
xor bx, cx  ; (number+mask) ^ mask