Плавающая точка в сборке x86 - PullRequest
2 голосов
/ 09 февраля 2012

Я сейчас пытаюсь получить среднее значение в виде числа с плавающей запятой, округленное до ближайшего .001

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

sum : DWORD, содержащий значение 90 (сумма acc количество элементов)

в соответствии : DWORD, содержащий значение 7 (количество элементов)

res : DWORD для хранения ответа.

В конце концов, edx имеет значение 0. Почему это? Кроме того, как округлить число с плавающей запятой?

Или ... есть ли лучший способ сделать это?

Мой асм:

   push dword ptr sum
   fild dword ptr [esp]
   push dword ptr acc
   fild dword ptr [esp]
   add esp,4
   fdiv st(0), st(1)
   sub esp,4
   fstp dword ptr [esp]
   pop eax
   add esp,4
   mov edx, eax

Также я попробовал это:

   finit
   fild sum
   fidiv acc
   frndint
   fist res
   mov eax, res

Но ... это приводит к: 2147483648 (диапазон DWORD)

Ответы [ 2 ]

1 голос
/ 09 февраля 2012

Я не уверен, что правильно понял ваш вопрос, но, по крайней мере, 2-й бит кода кажется верным.Делает ли он то, что вы хотите, это другой вопрос.Он делает это:

   finit
   fild sum        ;//ST(0) = 90
   fidiv acc       ;//ST(0) = ST(0) / acc = 90 / 7 = 12.857..
   frndint         ;//ST(0) = 13
   fist res        ;//RES= ST(0) = 13
   mov eax, res    ;//EAX = RES = 13

Другими словами, вы рассчитываете раунд (90/7) = 13.

Теперь это прямое деление, а не среднее.Вы, очевидно, вычислили бы среднее значение, суммируя по N элементам, а затем деля на количество элементов.

Вторым моментом является то, что вы работаете с целыми числами, а не со значениями с плавающей запятой: fIld, *Инструкции 1009 * и fIst предназначены для работы с целыми числами, а не со значениями с плавающей запятой.Если вы сохраняете значение из FPU в памяти с fIst вместо fst/fstp, это значение в памяти будет целочисленным, а не значением с плавающей запятой.Это то, что вам нужно?

Чтобы сохранить значение с плавающей запятой из FPU в памяти, на которую указывает [eax], вы можете использовать

   fstp dword ptr [eax] ;// Store Single-Precision Floating point value (4 bytes)
   fstp qword ptr [eax] ;// Store Double-Precision Floating point value (8 bytes)
   fstp tbyte ptr [eax] ;// Store Long Double-Precision Floating point value (10 bytes)

Одиночные и двойные хранилища (но неtbyte ptr) также работает с fst вместо fstp.

1 голос
/ 09 февраля 2012

у вас в коде много ненужных стековых операций, однако здесь есть более зловещая проблема: сохранение результата fp в DWORD будет его усекать, поэтому нет смысла его округлять, если вы планируйте округление до ближайшего целого числа (что и делает ваша вторая попытка).

Таким образом, я приведу пример из вашей второй попытки:

PUSH ECX
FILD [ESP]
PUSH EDX
FILD [ESP]
FDIV
FRNDINT
ADD ESP,4
FISTP DWORD PTR [ESP]
POP EAX
RETN

эта функция принимает значение в ECX, число в EDX и возвращает округленное среднее значение в EAX. поскольку здесь вы можете просто изменить его на использование глобальных переменных или вызвать его как функцию с использованием глобальных переменных

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...