[Программирование, Assembler] Перевод числа в строку с помощью FPU

Автор Сообщение
news_bot ®

Стаж: 6 лет 4 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
07-Фев-2021 22:30

Каждый человек увлекающийся программированием обязан написать свой вариант решения этой задачи. Я решил не быть исключением.В соответствии с x64 software conventions будем считать что число подлежащие конвертированию расположено в XMM0.Будем использовать x64 битный код при x32 битной адресации. Такой способ адресации позволяет использовать преимущества обоих диалектов.Сохраняем значение стека и создаем точку размещения данных выровненную про параграфу для повышения быстродействия:
; старт процедуры
  mov    r9d, esp
  lea    r8d,[r9d - 70h]
  and    r8d, 0FFFFFFF0h
  mov    esp, r8d
Подготавливаем FPU освобождая его от данных и устанавливаем повышенную точность и округление к нулю:
fsave [esp]
  finit
  mov  dword ptr[esp - dword], 037F0F7Fh
  fldcw         [esp - dword]
Перегружаем число из XMM0 в FPU:
movd qword ptr[esp - xmmword], xmm0
  fld  qword ptr[esp - xmmword]
Находим десятичный порядок Числа:
fld     st(0)
  fxtract
  fldl2t
  fst     st(1)
  fdivr   st(0),st(2)
  frndint
Устанавливаем округление к ближайшему числу:
fldcw  [esp - word]
Сохраняем порядок Числа и находим десятичный порядок Множителя для перевода значащих цифр Числа в целую часть:
fist      dword ptr[esp - dword]
  movzx edx, word ptr[esp - dword]
  mov       dword ptr[esp - dword], 10h
  fisubr    dword ptr[esp - dword]
Находим десятичный Множитель и перемножаем его на Число:
fmulp   st(1),st(0)
  fst     st(1)
  frndint
  fsub    st(1),st(0)
  fld1
  fscale
  fstp    st(1)
  fmulp   st(2),st(0)
  f2xm1
  fld1
  faddp   st(1),st(0)
  fmulp   st(1),st(0)
  frndint
Перегружаем полученное число из FPU в регистры AX и XMM0 в размере 2 первых и 8 последующих байтов соответственно. При загрузки 8 байт в регистр XMM0 одновременно меняем порядок расстановки байт за счет предварительного выравнивания указателя стека по параграфу:
fbstp           tbyte ptr[esp - xmmword]
  mov       ax,    word ptr[esp -   qword]
  pshuflw xmm0, xmmword ptr[esp - xmmword], 00011011b
Восстанавливаем состояние FPU:
frstor [esp]
Переставляем байты регистра ХММ0 до состояния их полного разворота с одновременным удвоением:
punpcklbw xmm0, xmm0
  pshuflw   xmm0, xmm0, 10110001b
  pshufhw   xmm0, xmm0, 10110001b
Загружаем маску и разделяем числовые тетрады:
mov            dword ptr[esp], 0FF00FF0h
  pshufd xmm1, xmmword ptr[esp], 0
  pand   xmm0, xmm1
  psrlw  xmm1, 4
  movdqa xmm2, xmm1
  pand   xmm1, xmm0
  psrlw  xmm1, 4
  pandn  xmm2, xmm0
  paddb  xmm1, xmm2
Создаем маску и находим байты содержащие значащие цифры:
pxor    xmm0, xmm0
  pcmpeqb xmm0, xmm1
Преобразуем числа в соответствующие им символы:
mov            dword ptr[esp], 30303030h
  pshufd xmm2, xmmword ptr[esp], 0
  paddb  xmm1, xmm2
Преобразуем первые два байта числа в символы и сохраняем их в память:
mov  byte ptr[esp],'-'
  btr             ax, 0Fh
  adc            esp, 0
  add             ax,'.0'
  mov  word ptr[esp], ax
Находим длину значащей части числа в регистре ХММ0 :
movdqu        xmmword ptr[esp + word], xmm1
  pmovmskb ecx, xmm0
  bsf      ecx, ecx
  add      esp, ecx
Проверка порядка Числа на нулевое значение и отрицательную величину:
mov    ecx,(word + dword)
  mov    eax, edx
  neg     dx
  jnc     @f
  cmovns eax, edx
  setns   dh
Преобразуем значение порядка числа в символы и сохраняем их в память:
cmp   ax, 0Ah
  sbb  ecx, ecx
  mov   dl, 0Ah
  div   dl
  cmp   al, 0Ah
  sbb  ecx, 0
  shl  eax, 8
  shr   ax, 8
  div   dl
  add eax, 303030h
  lea edx,[edx * 2 + 2B51h]
  mov dword ptr[esp + word + ecx + word], eax
  mov  word ptr[esp + word], dx
Вычисляем длину числа и сохраняем ее в регистрах EAX и ECX:
@@:  lea ecx,[esp + ecx + qword]
  sub ecx, r8d
  mov eax,ecx
Сохраняем строку символов в паре регистров XMM1 и XMM2:
movdqa xmm1, xmmword ptr[r8d]
  movdqa xmm2, xmmword ptr[r8d + xmmword]
Восстанавливаем значение стека:
mov esp, r9d
Выходим из процедуры.В своем коде я применяю недокументированное соглашение о передаче / возврате из функции множественных параметров. Соглашение абсолютно зеркально соглашению x64 software conventions за тем исключением что описывает правила размещения параметров при выходе из процедуры.Зачем писать этот код если уже есть готовые решения - потому что мое решение лучше.Чем оно лучше других - мой код прямой и не имеет циклов или ветвлений, а также содержит минимальное количество обращений к памяти.Зачем писать его на ассемблере если есть другие более удобные языки - потому что ассемблер лучше.Чем ассемблер лучше в данном случае - полным доступом к SIMD и FPU командам.Лишь часть данного кода векторная, вычисление числа скалярно - это не выполнимое требование так как при вызове процедуры ей передается только одно число.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_assembler, #_assembler (ассемблер), #_programiirovanie (програмиирование), #_programmirovanie (
Программирование
)
, #_assembler
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 07-Июл 04:34
Часовой пояс: UTC + 5