Мне нужно получить разницу в 2 значащих целых числа. Есть ли функция ABS() на языке ассемблера x86, чтобы я мог это сделать. Любая помощь будет принята с благодарностью.x86 assembly abs() реализация?
ответ
Если это сборка x86, то должны работать следующие according to the ever useful wikipedia. Вычесть одно значение из другого, а затем использовать эти инструкции по результату:
cdq
xor eax, edx
sub eax, edx
Если вы хотите, чтобы обрабатывать все случаи правильно, вы не можете просто вычитать, а затем взять абсолютное значение. Вы столкнулись с проблемой, потому что различие двух значащих целых чисел не обязательно представляется в виде целого числа со знаком. Например, предположим, что вы используете 32-битные целые числа дополнений, и вы хотите найти разницу между 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
Использование 'jge' может привести к« предсказанию ветвления »в процессоре« неправильное предсказание », что резко снизит процессор. Итак, если производительность вызывает беспокойство, лучше использовать ответ от @bits или @Hal –
Существует команда SUB, если то, что вы хотите это сделать AB. НТН
Предполагая, что ваши числа в 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
Инструкция к югу устанавливает флаги такие же, как в инструкции КСС.
. Cmov был новым с P6 (ppro/PII), но да, вы можете предположить это в наши дни. gcc делает. –
Старая ветка, но если бы я зашел сюда поздно, возможно, тоже ... abs - блестящий пример, так что это должно быть здесь.
; abs(eax), with no branches.
; intel syntax (dest, src)
mov ebx, eax ;store eax in ebx
neg eax
cmovl eax, ebx ;if eax is now negative, restore its saved value
Это действительно просто и эффективно, избегая «прогнозирования ветвей», определенно должно быть принято как ответ. –
Это, как функция abs()
С библиотекой делает это в сборке без ветвления:
abs(x) = (x XOR y) - y
, где y = x >>> 31
(предполагая, что 32-битный вход), а >>>
является арифметическим оператором сдвига вправо.
Пояснение по вышеприведенной формуле: Мы хотим, чтобы произвести дополнение 2 по единственной отрицательной x
.
y = 0xFFFF, if x is negative
0x0000, if x is positive
Так что, когда x
положительна x XOR 0x0000
равна x
. И когда x
отрицательный x XOR 0xFFFF
равен 1 дополнению x
. Теперь нам просто нужно добавить 1
, чтобы получить его дополнение 2, которое является выражением -y
. Потому что 0xFFFF
равно -1 в десятичной системе.
Давайте посмотрим на сборки генерируется для следующего кода по gcc
(4.6.3 на моей машине):
код C:
main()
{
int x;
int output = abs(x);
}
GCC 4.6.3 генерируется сборка сниппет (AT & T синтаксис), с моими комментариями:
movl -8(%rbp), %eax # -8(%rbp) is memory for x on stack
sarl $31, %eax # shift arithmetic right: x >>> 31, eax now represents y
movl %eax, %edx #
xorl -8(%rbp), %edx # %edx = x XOR y
movl %edx, -4(%rbp) # -4(%rbp) is memory for output on stack
subl %eax, -4(%rbp) # (x XOR y) - y
БОНУС (от Hacker's Delight): Если у вас есть быстрый умножить на +1 и -1, следующий даст вам abs(x)
:
((x >>> 30) | 1) * x
Дополнительные скобки в формуле BONUS – socketpair
спасибо! обновлено :) – bits
ABS (EAX)
test eax, eax ; Triger EFLAGS [CF, OF, PF, SF, and ZF]
jns AbsResult ; If (SF) is off, jmp AbsResult
neg eax ; If (SF) is on. (negation nullify by this opcode)
AbsResult:
Если флаги уже установлены любым генерирует значение в eax, вам не нужно test
. Неправильные предсказания отрасли сделают это медленным, если входные значения будут случайным образом распределены между положительным и отрицательным.
Это работает одинаково для RAX, AX, AL.
'или reg, reg' всегда хуже, чем' test reg, reg'. Http: // StackOverflow.ком/вопросы/33721204/x86 сборка-ОГТ-р-0-против-или-р-р/33724806 # 33724806. Кроме того, ветви не являются «одним часом». Они либо равны нулю (предсказано правильно), либо ~ 15 часов (неверно предсказано). –
- 1. x86 assembly - GetStdHandle & WriteConsole
- 2. x86 Assembly Cache Store
- 3. Sqrt in Assembly x86
- 4. x86 assembly program output
- 5. x86-64 GNU Assembly
- 6. x86 assembly programming
- 7. x86 intel opcode assembly
- 8. Factorial Assembly x86
- 9. Loop x86 Assembly
- 10. Loop Assembly x86
- 11. x86 assembly GAS, padding
- 12. Assembly x86 Win32
- 13. Windows Assembly Doubt - x86
- 14. Перестановка в x86 Assembly
- 15. Android: Реализация SlidingMenu и ABS
- 16. X86 assembly - Обработка параметров массива
- 17. Отдел в x86 Assembly GAS
- 18. Assembly x86 NULL terminator (TASM)
- 19. X86 assembly - Обработка инструкции IDIV
- 20. Таймер прерывания в x86 Assembly
- 21. intel x86 assembly to C
- 22. X86 Assembly - доступ к чипу
- 23. Сито из Eratosthenes x86 Assembly
- 24. x86 assembly: Compare DWORD variable
- 25. Объявление массивов в x86 Assembly
- 26. x86 assembly print register ascii
- 27. x86 assembly-masm32: неправильные операнды команд
- 28. Assembly AT & T x86 read from file
- 29. Условное в Loop MASM x86 Assembly
- 30. x86 Assembly - idiv, чтобы получить десятичные знаки
Вы можете сравнить и условно обменять, а затем вычесть. –
На какой платформе вы работаете? Нет такой вещи, как «Язык ассемблера», только «сборка x86» или «сборка ARM» и т. Д. –
Является ли сборка x86 .. –