Округление до целого числа - Округление контрольного поля? - PullRequest
1 голос
/ 08 февраля 2010

Я пытаюсь написать функцию с именем roundD, которая округляет свой первый аргумент до целочисленного значения в соответствии с режимом, указанным во втором аргументе.

Я буду писать функцию на языке ассемблера, используя встроенный ассемблер gcc. Я не хочу использовать какие-либо предопределенные функции ..

Я думаю, мне нужно установить поле управления округлением управляющего слова FPU в соответствии со вторым аргументом ?. Я также думаю, что мне нужно восстановить исходное значение поля управления округлением, прежде чем RoundD вернется?

Я пытаюсь понять, как мне сделать это в правильном порядке ..

Должен ли я использовать управляющее слово FPU?

  1. Загружаю ли я значение в FPU?
  2. Использовать контрольное слово - БИТОВЫЕ ПОЛЯ для выполнения расчетов?

like: поле RC (биты 11 и 10) или Rounding Control определяет, как FPU будет округлять результаты.

Может кто-нибудь дать мне пример того, как я бы использовал поля RC? Или я далеко от базы, что мне нужно сделать?

Я ухожу с этой страницы .. http://www.website.masmforum.com/tutorials/fptute/fpuchap1.htm

это хорошая страница для перехода? Что еще мне нужно Google для информации? Любая помощь высоко ценится.. Я думаю, что мне просто нужен подробный анализ шагов, которые мне нужно предпринять, чтобы выполнить это ..

Это то, что я имею до сих пор ..

#include <stdio.h>
#include <stdlib.h>

#define PRECISION           3
#define RND_CTL_BIT_SHIFT   10

// floating point rounding modes: IA-32 Manual, Vol. 1, p. 4-20
typedef enum {
ROUND_NEAREST_EVEN =    0 << RND_CTL_BIT_SHIFT,
ROUND_MINUS_INF =       1 << RND_CTL_BIT_SHIFT,
ROUND_PLUS_INF =        2 << RND_CTL_BIT_SHIFT,
ROUND_TOWARD_ZERO =     3 << RND_CTL_BIT_SHIFT
} RoundingMode;

double roundD (double n, RoundingMode roundingMode)
{

return n;


}

int main (int argc, char **argv)
{
double  n = 0.0;

printf("Rounding - Assembly");
if (argc > 1)
    n = atof(argv[1]);

printf("roundD even %.*f = %.*f\n",
       PRECISION, n, PRECISION, roundD(n, ROUND_NEAREST_EVEN));
printf("roundD down %.*f = %.*f\n",
       PRECISION, n, PRECISION, roundD(n, ROUND_MINUS_INF));
printf("roundD up   %.*f = %.*f\n",
       PRECISION, n, PRECISION, roundD(n, ROUND_PLUS_INF));
printf("roundD zero %.*f = %.*f\n",
       PRECISION, n, PRECISION, roundD(n, ROUND_TOWARD_ZERO));

return 0;
}

Ответы [ 4 ]

1 голос
/ 14 октября 2011
 __ftol          proc near
 var_C           = qword ptr -0Ch
 var_4           = word ptr -4
 var_2           = word ptr -2
                 push    ebp
                 mov     ebp, esp
                 add     esp, 0FFFFFFF4h
                 fstcw   [ebp+var_2]
                 wait
                 mov     ax, [ebp+var_2]
                 or      ah, 0Ch         ; 00001100
                                         ;
                                         ; ROUNDING CONTROL FIELD
                                         ;     The rounding control (RC) field of the FPU
                                         ;     control register (bits 10 and 11)
                                         ;
                                         ;     Rounding Mode                  RC Field Setting
                                         ;
                                         ;     Round nearest     (even)       00b
                                         ;     Round down        (toward -)   01b
                                         ;     Round up          (toward +)   10b
                                         ;     Round toward zero (Truncate)   11b
                 mov     [ebp+var_4], ax
                 fldcw   [ebp+var_4]
                 fistp   [ebp+var_C]
                 fldcw   [ebp+var_2]
                 mov     eax, dword ptr [ebp+var_C]
                 mov     edx, dword ptr [ebp+var_C+4]
                 leave
                 retn
 __ftol          endp
0 голосов
/ 21 февраля 2017
 oldcw   dw   ?

  fstcw oldcw     ;get the current Control Word to retain all setting bits
                  ;not related to the rounding control (RC) bits
  fwait       ;to insure the storage instruction is completed
  mov   ax,oldcw
; and   ax,0F3FFh ;clears only the RC bits, leaving all other bits unchanged
                  ;not necessary here because both bits will be set
  or    ax,0C00h  ;this will set both bits of the RC field to the truncating mode
                  ;without affecting any of the other field's bits
  push  eax       ;use the stack to store the modified Control Word in memory
  fldcw [esp]     ;load the modified Control Word

  fxxxx           ;other FPU instruction(s) needing the truncating mode

  fldcw oldcw     ;restore the previous Control Word
  pop   eax       ;clean-up the stack
                  ;this could also retrieve a 16-bit or 32-bit integer
                  ;possibly returned by the "other FPU instruction(s)"
0 голосов
/ 08 февраля 2010

Если у вас есть переменная памяти hwcntrlwd с правильно установленными битами: (синтаксис intel)

mov eax,[hwcntrlwd]
fstcw ax
0 голосов
/ 08 февраля 2010

Проверяли ли вы, поддерживает ли ваша среда улучшенную поддержку C99 с плавающей запятой? C99 определяет функции fegetround() и fesetround() для получения и установки текущего режима округления с плавающей запятой. Затем можно использовать функцию rint() для округления в соответствии с текущим режимом округления.

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