Преобразование чисел с плавающей точкой в целые числа и обратно

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

Расширения SSE/AVX/AVX2 предоставляют ряд инструкций для преобразования чисел с плавающей точкой в целые числа и наоборот. Подобные инструкции могут преобразовывать как одно скалярное значение, так и вектор значений.

Преобразование скалярных значений

Для преобразования одного числа в другое имеются следующие инструкции:

  • cvtsd2si: преобразует 64-разрядное число с плавающей точкой в 32- или 64-битное целое число. Для округления применет режим, установленный в регистре MXCSR. Результат сохраняется в 32- или 64-битном регистре общего назначения.

    cvtsd2si xmmn/mem64, reg32/64
  • cvtsd2ss: преобразует 64-разрядное число с плавающей точкой (в регистре XMM или переменной) в число 32-разрядное число с плавающей точкой и оставляет результат в втором операнде - регистре XMM. Для округления применет режим, установленный в регистре MXCSR.

    cvtsd2ss xmmn/mem64, xmmn
  • cvtsi2sd: преобразует 32- или 64-разрядное целое число из регистра общего назначения или переменной в 64-разрядное число с плавающей точкой, оставляя результат в регистре XMM.

    cvtsi2sd reg32/64/mem32/64,  xmmn
  • cvtsi2ss: преобразует 32- или 64-разрядное целое число в целочисленном регистре или переменной в 32-разрядное число с плавающей точкой, оставляя результат в регистре XMM.

    cvtsi2ss reg32/64/mem32/64, xmmn
  • cvtss2sd: преобразует 32-разрядное число с плавающей точкой из регистра XMM или переменной в 64-разрядное число с плавающей точкой, оставляя результат в регистре XMM в первом операнде.

    cvtss2sd xmmn/mem32, xmmn
  • cvtss2si: преобразует 32-разрядное число с плавающей точкой из регистра XMM или переменной в целое число и оставляет результат в 32- или 64-битном регистре общего назначения. Для округления применет режим, установленный в регистре MXCSR.

    cvtss2si xmmn/mem32, reg32/64
  • cvttsd2si: преобразует 64-разрядное число с плавающей точкой в 32- или 64-битное целое число. Преобразование выполняется с использованием усечения (не использует биты управления округлением в MXCSR). Результат сохраняется в 32- или 64-битном регистре общего назначения.

    cvttsd2si xmmn/mem64, reg32/64
  • cvttss2si: преобразует 32-разрядное число с плавающей точкой в 32- или 64-битное целое число. Преобразование выполняется с использованием усечения (не использует биты управления округлением в MXCSR). Результат сохраняется в 32- или 64-битном регистре общего назначения.

    cvttss2si xmmn/mem32, reg32/64

Стоит отметить, что названиях всех инструкций следует определенному шаблону. Например, cvtsi2sd: cvt (convert - преобразовать) + s (single - значение .float - число одинарной точности) + i (integer - целое чисор) + 2 (to - в) + s (scalar - скалярное значение) + d(значение .double).

Пример преобразования:

.globl _start

.data
number: .double 3.4
.text
_start: 
    movsd number, %xmm0     # помещаем число number в xmm0
    cvtsd2si %xmm0, %rdi    # преобразуем число из xmm0 в целое число и помещаем в rdi

    movq $60, %rax
    syscall

В данном случае число 3.4, которое хранится в XMM0, преобразуется в целочисленное значение. И мы получим в регистре %rdi число 3.

По умолчанию для округления чисел применяются 13-14 биты регистра состояния MXCSR:

  • 00: округление до ближайшего

  • 01: округление до -бесконечности

  • 10: округление до +бесконечности

  • 11: округление до 0 (усечение)

По умолчанию округление идет до ближайшего. Так, число 3.4 округляется до 3, а число 3.5 - до 4. Управляя этими битами, можно настроить округление при преобразовании. Например:

.globl _start

.data
number: .double 5.6
state: .long 0
.text
_start: 
    stmxcsr state       # загружаем регистр в переменную state
    orl $0b110000000000000, state   # устанавливаем 13 и 14 биты
    ldmxcsr state       # сохраняем данные из переменной state в регистр

    movsd number, %xmm0     # помещаем число number в xmm0
    cvtsd2si %xmm0, %rdi    # преобразуем число из xmm0 в целое число и помещаем в rdi

    movq $60, %rax
    syscall

В данном случае загружаем состояние регистра в переменную state, устанавливаем в ней 13 и 14 биты (для этого применяется инструкция orl). Это означет, что при округлении дробная часть будет отбрасываться. Затем инструкцией ldmxcsr сохраняем данные из переменной обратно в регистр. В итоге при преобразовании числа 5.6 оно будет округляться до 5.

Преобразования векторов

Кроме того, есть отдельный набор инструкций, которые выполняет преобразование чисел в векторах из одного типа в другой.

  • cvtdq2pd: преобразует два 32-разрядных целых числа со знаком в два 64-разрядных числа с плавающей точкой

    cvtdq2pd xmmsrc/mem64, xmmdest
  • vcvtdq2pd: преобразует два 32-разрядных целых числа со знаком в два 64-разрядных числа с плавающей точкой (результат в XMM)

    vcvtdq2pd xmmsrc/mem64, xmmdest

    либо преобразует четыре 32-разрядных целых числа со знаком в четыре 64-разрядных числа с плавающей точкой (результат в YMM)

    vcvtdq2pd xmmsrc/mem128, ymmdest
  • cvtdq2ps: преобразует 4 32-разрядных целых числа со знаком в 4 32-разрядных числа с плавающей точкой

    cvtdq2ps xmmsrc/mem128, xmmdest
  • vcvtdq2ps: преобразует 4 32-разрядных целых числа со знаком в 4 32-разрядных числа с плавающей точкой

    vcvtdq2ps xmmsrc/mem128, xmmdest

    Другая форма инструкции преобразует 8 32-разрядных целых числа со знаком в 8 32-разрядных чисел с плавающей точкой

    vcvtdq2ps ymmsrc/mem256, ymmdest
  • cvtpd2dq: преобразует два 64-разрядных числа с плавающей точкой в два 32-разрядных целых числа со знаком

    cvtpd2dq xmmsrc/mem128, xmmdest
  • vcvtpd2dq: преобразует два 64-разрядных числа с плавающей точкой в два 32-разрядных целых числа со знаком (результат в XMM)

    vcvtpd2dq xmmsrc/mem128, xmmdest

    Другая форма преобразует преобразует 4 64-разрядных числа с плавающей точкой в 4 32-разрядных целых числа со знаком

    vcvtpd2dq ymmsrc/mem256, xmmdest
  • cvtpd2ps: преобразует два 64-разрядных числа с плавающей точкой в два 32-разрядных числа с плавающей точкой

    cvtpd2ps xmmsrc/mem128, xmmdest
  • vcvtpd2ps: преобразует два 64-разрядных числа с плавающей точкой в два 32-разрядных числа с плавающей точкой

    vcvtpd2ps xmmsrc/mem128, xmmdest

    Другая форма преобразует преобразует 4 64-разрядных числа с плавающей точкой в 4 32-разрядных числа с плавающей точкой

    vcvtpd2ps ymmsrc/mem256, xmmdest
  • cvtps2dq: преобразует 4 32-разрядных числа с плавающей точкой в 4 32-разрядных целых числа со знаком

    cvtps2dq xmmsrc/mem128, xmmdest
  • vcvtps2dq: преобразует 4 32-разрядных числа с плавающей точкой в 4 32-разрядных целых числа со знаком

    vcvtps2dq xmmsrc/mem128, xmmdest

    Другая форма преобразует 8 32-разрядных числа с плавающей точкой в 8 32-разрядных целых числа со знаком

    vcvtps2dq ymmsrc/mem256, ymmdest
  • cvtps2pd: преобразует два 32-разрядных числа с плавающей точкой в два 64-разрядных числа с плавающей точкой

    cvtps2pd xmmsrc/mem64, xmmdest
  • vcvtps2pd: преобразует два 32-разрядных числа с плавающей точкой в два 64-разрядных числа с плавающей точкой

    vcvtps2pd xmmsrc/mem64, xmmdest

    другая форма преобразует 4 32-разрядных числа с плавающей точкой в 4 64-разрядных числа с плавающей точкой

    vcvtps2pd xmmsrc/mem128, ymmdest
  • cvttpd2dq: преобразует два 64-разрядных числа с плавающей точкой в два 32-разрядных целых числа со знаком

    cvttpd2dq xmmsrc/mem128, xmmdest
  • vcvttpd2dq: преобразует два 64-разрядных числа с плавающей точкой в два 32-разрядных целых числа со знаком

    vcvttpd2dq xmmsrc/mem128, xmmdest

    другая форма преобразует 4 64-разрядных числа с плавающей точкой в 4 32-разрядных целых числа со знаком

    vcvttpd2dq ymmsrc/mem256, xmmdest
  • cvttps2dq: преобразует 4 32-разрядных числа с плавающей точкой в 4 32-разрядных целых числа со знаком

    cvttps2dq xmmsrc/mem128, xmmdest
  • vcvttps2dq: преобразует 4 32-разрядных числа с плавающей точкой в 4 32-разрядных целых числа со знаком

    vcvttps2dq xmmsrc/mem128, xmmdest

    другая форма преобразует 8 32-разрядных чисел с плавающей точкой в 8 32-разрядных целых чисел со знаком

    vcvttps2dq ymmsrc/mem256, ymmdest

Эти инструкции удобно использовать в ситуации, когда надо преобразовать вектор значений. Например, преобразуем набор значений .float в набор чисел типа .long:

.globl _start

.data
floatNums: .float 4.2, 5.3, 6.4, 7.5
intNums: .fill 4, 4, 0
.text
_start: 
    cvttps2dq floatNums, %xmm0  # преобразуем .float в .long, результат помещаем в xmm0
    movaps %xmm0, intNums       # результат помещаем в intNums

    movl intNums, %edi          # %edi = 4

    movq $60, %rax
    syscall

Здесь вектор из 4 чисел .float преобразуем вектор чисел .long и помещаем результат в регистр xmm0. Затем результат помещаем в переменную intNums.

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