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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.globl _start

.data
num1: .double 3.4
num2: .double 3.4
.text
_start: 
    movsd num1, %xmm0       # помещаем в xmm0 число num1
    movsd num2, %xmm1       # помещаем в xmm1 число num2

    cmpeqsd %xmm1, %xmm0      # равны ли операнды
    movq %xmm0, %rdi

    movq $60, %rax
    syscall

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

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

.data
num1: .double 3.5
num2: .double 3.6

str_equal: .asciz "Equal\n"
str_equal_len= . - str_equal
str_notequal: .asciz "Not equal\n"
str_notequal_len= . - str_notequal
.text
_start: 
    movsd num1, %xmm0       # помещаем в xmm0 число num1
    movsd num2, %xmm1       # помещаем в xmm1 число num2

    cmpeqsd %xmm1, %xmm0      # равны ли операнды
    movq %xmm0, %rdi

    test %rdi, %rdi         # проверяем на равенство - на единицы
    jnz equal               # если xmm0 == xmm1
    
    movq $str_notequal, %rsi     # адрес строки
    movq $str_notequal_len, %rdx # размер строки
    jmp exit
equal:
    movq $str_equal, %rsi     # адрес строки
    movq $str_equal_len, %rdx # размер строки
exit:
    movq $1, %rax           # номер системной функци
    movq $1, %rdi           # дескриптор стандартного (консольного) вывода
    syscall                 # выполняем системный вызов

    movq $60, %rax
    syscall

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

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