Я должен получить различие 2 целых чисел со знаком. Есть ли ABS () функция в x86 ассемблере, таким образом, я могу сделать это. Любая справка значительно ценилась бы.
Есть инструкция SUB, если вы хотите выполнить AB. HTH
{{1} }Если это сборка x86, следующая согласно постоянно полезной википедии должна работать. Вычтите одно значение из другого, а затем используйте эти инструкции для получения результата:
cdq
xor eax, edx
sub eax, edx
Если вы хотите правильно обрабатывать все случаи , вы не можете просто вычесть, а затем взять абсолютное значение. У вас возникнут проблемы, потому что разница двух целых чисел со знаком не обязательно может быть представлена как целое число со знаком. Например, предположим, что вы используете 32-битные целые числа с дополнением до 2 и хотите найти разницу между INT_MAX
( 0x7fffffff
) и INT_MIN
( 0x80000000
). Вычитание дает:
0x7fffffff - 0x80000000 = 0xffffffff
, что равно -1
; когда вы берете абсолютное значение, вы получаете результат 1
, тогда как фактическая разница между двумя числами составляет 0xffffffff
, интерпретируемая как целое число без знака ( UINT_MAX
) .
Разница между двумя целыми числами со знаком всегда может быть представлена как целое число без знака. Чтобы получить это значение (с аппаратным дополнением 2s), вы просто вычитаете меньший ввод из большего и интерпретируете результат как целое число без знака; нет необходимости в абсолютном значении.
Вот один (из многих, и не обязательно лучший) способ сделать это на x86, предполагая, что два целых числа находятся в eax
и edx
:
cmp eax, edx // compare the two numbers
jge 1f
xchg eax, edx // if eax < edx, swap them so the bigger number is in eax
1: sub eax, edx // subtract to get the difference
Предполагая, что ваши целые числа находятся в регистрах MMX или XMM, используйте psubd
для вычисления разницы, затем pabsd
, чтобы получить абсолютное значение разницы.
Если ваши целые числа находятся в простых, «обычных» регистрах, выполните вычитание, а затем трюк cdq
, чтобы получить абсолютное значение. Это требует использования некоторых специальных регистров ( cdq
sign-extends eax
в edx
, без использования других регистров), так что вы можете делать что-то с другими кодами операций. Например:
mov r2, r1
sar r2, 31
вычисляет в регистре r2
знаковое расширение r1
(0, если r1
положительное значение или ноль, 0xFFFFFFFF, если r1
] отрицательно). Это работает для всех 32-битных регистров r1
и r2
и заменяет инструкцию cdq
.
Короткий, но простой способ с использованием инструкции условного перемещения (я думаю, доступна Pentium и выше):
; compute ABS(r1-r2) in eax, overwrites r2
mov eax, r1
sub eax, r2
sub r2, r1
cmovg eax, r2
Подкоманда устанавливает флаги так же, как инструкция cmp.