SIMD

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

Последнее обновление: 30.09.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

Для определения чисел первых двух типов в программе GNU ассемблер GAS предоставляет две директивы:

  • .float: числа с плавающей точкой одинарной точности по 4 байта. Имеет также псевдоним .single

  • .double: числа с плавающей точкой двойной точности по 8 байт

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

Формат типа .float - чисел с плавающей точкой с одинарной точностью использует 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 знаков точности

Нечисловые значения

Стандарт IEEE для чисел с плавающей токой распознает три специальных нечисловых значения: -infinity (минус бесконечность), +infinity (плюс бесконечность) и NaN (не число). Для каждого из этих специальных чисел поле экспоненты заполняется всеми битами 1. Если в экспоненте все биты 1, а в мантиссе все биты 0, то значение равно бесконечности. Бит знака будет равен 0 для +infinity и 1 для -infinity. Если в экспоненте все биты 1, а в мантиссе не все биты 0, то значение представляет NaN.

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

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

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

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

.data
n1: .float 0.0
n2: .float 2.7
n3: .double 3.14159
n4: .double 0
n5: .double 1.234567e+2  # 123.4567

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

.globl _start
 
.data
num: .double 4.6

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

    movq $60, %rax
    syscall

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

root@Eugene:~/asm# as hello.s -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.

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