【问题标题】:Rounding to an integer - Rounding control field?舍入为整数 - 舍入控制字段?
【发布时间】:2010-02-08 00:21:01
【问题描述】:

我正在尝试编写一个名为 roundD 的函数,该函数根据其第二个参数指定的模式将其第一个参数四舍五入为整数值。

我将使用 gcc 的内联汇编器用汇编语言编写函数。我不想使用任何预定义的函数..

我想我需要根据第二个参数来设置 FPU 控制字的舍入控制字段?我也认为我需要在roundD返回之前恢复Rounding Control字段的原始值?

我正在尝试弄清楚我应该如何以正确的顺序完成此操作..

我应该使用 FPU 的控制字吗?

  1. 我是否将值加载到 FPU 中?
  2. 使用控制字 - BIT FIELDS 进行计算?

like:RC 字段(位 11 和 10)或舍入控制确定 FPU 如何舍入结果。

谁能给我一个如何使用 RC 字段的例子? 或者我离我需要做的事情还有很长的路要走?​​p>

我要离开这个页面.. http://www.website.masmforum.com/tutorials/fptute/fpuchap1.htm

这是一个不错的页面吗? 我还需要谷歌搜索什么信息? 任何帮助深表感谢.. 我想我只需要详细分析我需要采取的步骤来完成这个..

这就是我目前所拥有的......

#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;
}

【问题讨论】:

标签: c assembly


【解决方案1】:

您是否检查过您的环境是否包含改进的 C99 浮点支持? C99 定义了函数fegetround()fesetround() 来获取和设置当前的浮点舍入模式。然后可以使用rint()函数根据当前的舍入模式进行舍入。

【讨论】:

  • 我想自己做。我不想使用预先构建的功能。我正在尝试用汇编学习 c。
【解决方案2】:
 __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

【讨论】:

    【解决方案3】:
     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)"
    

    【讨论】:

      【解决方案4】:

      如果您有一个名为 hwcntrlwd 且位设置正确的内存变量: (英特尔语法)

      mov eax,[hwcntrlwd]
      fstcw ax
      

      【讨论】:

      • 所以,在我的情况下,我可以这样做: mov eax,[n - ROUND_NEAREST_EVEN] // 任何枚举模式? fstcw 斧头
      • fstcw 需要一个内存目标,而不是 AX。 stackoverflow.com/questions/48981197/….
      • @Peter Cordes 它可以是 AX 或内存位置。 felixcloutier.com/x86/fstsw:fnstsw 我记得很清楚几年前,当一个图形库程序集文件开始使用 gcc 在最新的 GAS 上阻塞时,我们都不得不将 FSTCW EAX 更改为 FSTCW AX
      • 您链接了fstSW(状态字),它确实有一个 AX 目标表单。但是您的答案使用了fstCW(控制字),但没有;请参阅我的链接答案。从我之前的评论。这就是问题所在。
      • @Peter Cordes 我什至没看到! 抱歉。
      猜你喜欢
      • 1970-01-01
      • 2012-06-19
      • 2022-07-27
      • 1970-01-01
      • 1970-01-01
      • 2011-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多