Сравнение чисел с плавающей точкой в SSE

Последнее обновление: 02.07.2023

Для сравнения чисел с плавающей точкой расширения SSE предоставляют набор инструкций сравнения для конкретных условий, которые сохраняют значение true (все биты 1) или false (все биты 0) в первом операнде:

cmpss xmmn, xmmm/mem32, imm8
cmpsd xmmn, xmmm/mem64, imm8

cmpeqss xmmn, xmmm/mem32       ; операнды равны
cmpltss xmmn, xmmm/mem32       ; первый операнд меньше второго
cmpless xmmn, xmmm/mem32       ; первый операнд меньше или равен второму
cmpunordss xmmn, xmmm/mem32    ; неупорядоченное сравнение (один из операндов или оба равны NaN)
cmpneqss xmmn, xmmm/mem32      ; операнды не равны
cmpnltss xmmn, xmmm/mem32      ; первый операнд НЕ меньше второго
cmpnless xmmn, xmmm/mem32      ; первый операнд НЕ меньше или равен второму
cmpordss xmmn, xmmm/mem32      ; упорядоченное сравнение
cmpeqsd xmmn, xmmm/mem64       ; операнды равны
cmpltsd xmmn, xmmm/mem64       ; первый операнд меньше второго
cmplesd xmmn, xmmm/mem64       ; первый операнд меньше или равен второму
cmpunordsd xmmn, xmmm/mem64    ; неупорядоченное сравнение (один из операндов или оба равны NaN)
cmpneqsd xmmn, xmmm/mem64      ; операнды не равны
cmpnltsd xmmn, xmmm/mem64      ; первый операнд НЕ меньше второго
cmpnlesd xmmn, xmmm/mem64      ; первый операнд НЕ меньше или равен второму
cmpordsd xmmn, xmmm/mem64      ; упорядоченное сравнение

Первые две инструкции могут в качестве третьего операнда (imm8) принимать значение от 0 до 7, которое указывает на принцип сравнения:

  • 0: Первый операнд == второй операнд

  • 1: Первый операнд < второй операнд

  • 2: Первый операнд <= второй операнд

  • 3: Неупорядоченное сравнение

  • 4: Первый операнд ≠ второй операнд

  • 5: Первый операнд не меньше второго операнда (>=)

  • 6: Первый операнд не меньше или равен второму операнду (>)

  • 7: Упорядоченное сравнение

Эти инструкции устанавливают в 0 (неверно, ложь) или 1 (верно, истина) все биты в первом операнде. После сравнения значение из регистра XMM можно поместит в регистр общего назначения и проверить этот регистр на наличие нуля/не нуля. Для этого можно использовать инструкции movq или movd:

.data
    double1 real8 1.2
    double2 real8 1.2
.code
main proc 
    movsd xmm0, double1
    movsd xmm1, double2

    cmpeqsd xmm0, xmm1      ; равны ли операнды
    movd eax, xmm0
    ret
main endp
end

Здесь помещаем в XMM0 и XMM1 два числа real8 и инструкцией cmpeqsd сравниваем их на равенство. Если они равны, то в xmm0 все биты будут равны 1, если нет - то 0. Для проверки значения помещаем его в регистр EAX. Поскольку при равестве все биты будут установлены в 1, то фактически в десятичной системе это будет число -1.

Получив результат проверки в регистр EAX, мы можем использовать уже стандартные инструкции перехода, чтобы определить условные конструкции:

.data
    double1 real8 1.2
    double2 real8 1.2
.code
main proc        
    movsd xmm0, double1
    movsd xmm1, double2

    cmpeqsd xmm0, xmm1      ; равны и=ли операнды
    movd eax, xmm0
    and eax, eax            ; проверяем на равенство
    jnz equal               ; если xmm0 == xmm1
    mov eax, 0
    jmp proc_end
equal:
    mov eax, 1
proc_end:
    ret
main endp
end

Здесь по сравнению с предыдущим примером добавили проверку на 0 с помощью инструкции and - если результат этой инструкии равен 0, то будет установлен флаг нуля ZF, который мы можем проверить с помощью инструкции jnz - если флаг не установлен (то есть по сути если xmm0 и xmm1 были равны), то далее выполняем переход на метку equal.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850