SIMD

Числа с плавающей точкой

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

Кроме целых чисел в ассемблере мы можем работать с числами с плавающей точкой. Числа с плавающей точкой или floating-point numbers представляют запись вещественных чисел, в которой число хранится в виде мантиссы и порядка (показателя степени), например,

1.12345 x 102

Для определения чисел с плавающей точкой процессоры x86-64 используют стандарт IEEE 754, согласно которому каждое число содержит ряд компонентов:

  • бит знака, который указывает, является ли число положительным или отрицательным

  • мантисса, в примере выше 1.12345

  • экспонента или показатель степени, в примере 102 это число 2.

Также числа с плавающей точкой характеризуются таким показателем, как десятичные знаки (decimal digits) или еще называют "десятичная точность" (decimal precision). Этот показатель указывает, сколько десятичных знаков может хранить число. Например, в числе 123.45 десятичная точность равна 5 (5 цифр).

Архитектура x86-64 поддерживает три типа данных для работы с числами с плавающей точкой:

Размер

Бит знака

Дробная часть

Экспонента

32 бита

1

23

8

64 бита

1

52

11

80 бит

1

64

15

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

Числа с плавающей точкой с одинарной точностью используют 23-битную мантисса с дополнением до единицы, 8-битную экспоненту и бит с одним знаком.

Float в ассемблере Intel

Фактически мантисса имеет 24 бита, где старший бит подразумевается, и он всегда равен 1. То есть мантисса выглядит следующим образом:

1.mmmmmmm mmmmmmmm

где mmmmmmm mmmmmmmm - это 23 бита мантисы. Эти 23 бита представляют беззнаковое число, которые идут после десятичной точки. То есть мантиса обычно представляет значение от 1,0 до чуть меньше 2,0.

Для представления значений вне диапазона от 1,0 до 2,0 применяется экспонента. Формат с плавающей точкой возводит 2 в степень, указанную экспонентой, а затем умножает мантиссу на это значение. Показатель степени составляет 8 бит и хранится в формате "excess-127". В этом формате экспонента 0 представляет значение 127 (7Fh), отрицательные показатели представляют собой значения в диапазоне от 0 до 126, а положительные показатели — значения в диапазоне от 128 до 255. Для преобразования экспоненты в формат "excess-127", к значению экспоненты добавляется число 127.

С 24-битной мантиссой можно получить примерно шесть с половиной (десятичных) знаков точности (половина означает, что все первые шесть цифр могут быть в диапазоне от 0 до 9, а седьмая цифра может быть только в диапазоне от 0 до n, где n < 9 и обычно близко к 5). Благодаря этому можно представлить 2±127 значений или примерно 10±38.

Числа с плавающей точкой двойной точности

Числа с плавающей точкой двойной точности - данные типа .double занимают 64 бита. Первый бит числа также представляет знаковый бит. Однако теперь мантисса занимает 52 бита плюс 1 подразумеваемый бит - старший бит, равный 1. А экспонента занимает 11 бит и использует формат "excess-1023". Это обеспечивает диапазон значений 10±308 и 14,5 знаков точности

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

Для определения чисел c плавающей точкой ассемблер NASM предоставляет ряд директив:

  • db: число с плавающей точкой размером в 1 байт (byte)

  • dw: число с плавающей точкой размером в 2 байта (word)

  • dd: 4 байта (dword)

  • dq: 8 байт (qword)

  • dt: 10 байт (tword)

  • do: 16 байт (oword)

  • dy: 32 байта (yword)

  • dz: 64 байта (zword)

Первые четыре директивы также применяются для определения целочисленных переменных

В NASM число с плавающей точкой должно начинаться с десятичной цифры, за которой может следовать точка как разделитель целой и дробной частей и некоторое количество десятичных цифр. Если число отрицательное, то перед ним указывается минус (для положительных можно указать знак +, но он необязателен). Например:

1.234  -23.456 0.23 -1.0 

Если в целой части только 0, то его можно опустить

.23 (или 0.23)  .01567 (или 0.01567)

Также можно использовать экспоненциальную запись, при которой после числа следует буква e или E, за которой может следовать знак (+ или -) и одна или несколько десятичных цифр.

3.75e2 1.1e-1 1.e+4 -123.456e+789 +25.0e0 1.e3

Пример определения переменных чисел с плавающей точкой в программе

section .data
n1 dw 0.0
n2 dw 2.7
n3 dq 3.14159
n4 dq 0
n5 dq 1.234567e+2  ; 123.4567

В дальнейшем мы подробнее рассмотрим инструкции для работы с подобными числами. А пока для небольшого примера рассмотрим следующую задачу на Linux:

global _start

section .data
num dq 4.6

section .text
_start:
    movq xmm0, [num]         ; помещаем в регистр xmm0 число num
    cvtsd2si rdi, xmm0    ; преобразуем число из xmm0 в целое число и помещаем в rdi

    mov rax, 60
    syscall

Здесь первая инструкция - movq помещает в регистр xmm0 значение переменной num. Вторая инструкция - cvtsd2si преобразует значение из xmm0 в целое число, которое помещается в регистр rdi. Компиляция и работа программы:

root@Eugene:~/asm# nasm -f elf64 hello.asm -o hello.o
root@Eugene:~/asm# ld hello.o -o hello
root@Eugene:~/asm# ./hello
root@Eugene:~/asm# echo $?
5
root@Eugene:~/asm#

В данном случае видно, что число 4.6 при преобразовании в целое число было округлено до 5.

Аналогичный пример на Windows:

global _start

section .data
num dq 4.6

section .text
_start:
    movq xmm0, [rel num]         ; помещаем в регистр xmm0 число num
    cvtsd2si rax, xmm0    ; преобразуем число из xmm0 в целое число и помещаем в rax
    ret
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850