汇编 - 将浮点数舍入到.001精度朝向-∞

时间:2014-04-29 07:41:03

标签: assembly x86 masm irvine32

我正在尝试将所有浮点数写入.001精度到-∞。我已将RC字段设置为01二进制,但我只能打印出所需精度的初始浮点数,然后忽略舍入。我想我可能会错过一些关于如何处理-∞精度的明显内容,但我不确定。

INCLUDE Irvine32.inc

.data

ctrlWord  WORD  010000000000b ; set the RC field to round down toward -∞.

.code

     fild   sum                         ; load integer into ST(0)
     fidiv  count                       ; divide ST(0) by mem int
     fstcw  ctrlWord                    ; store control word
     fldcw  ctrlWord                    ; load control word
     call   WriteFloat                  ; +2.5000000E+000

     fild   stdDev                      ; load variance integer into ST(0)
     fidiv  count                       ; average the result 
     fsqrt                  ; ST(0) = square root
     call   WriteFloat                  ; +2.5495097E+000

1 个答案:

答案 0 :(得分:1)

FPU的舍入模式仅适用于浮点尾数的最后二进制数字。它不能用于十进制舍入。该舍入规则有一个例外:FRNDINT。该指令“将ST(0)寄存器中的源值舍入为最接近的整数值,具体取决于当前的舍入模式(FPU控制字的RC字段的设置),并将结果存储在ST(0)中。” (Intel Manual)。

对于十进制舍入,您可以使用FRNDINT使用技巧:首先计算n * 10 ^ x(x是小数部分的所需小数精度)。然后使用FRNDINT对整数部分进行舍入并截断小数部分。最后,您可以将数字除以10 ^ x,或者您可以将数字转换为字符串并插入适当的小数点。

看看这个例子(这是你的代码,只是稍作修改):

INCLUDE Irvine32.inc

.data

newCtrlWord  WORD 010000000000b ; set the RC field to round down toward -∞.
oldCtrlWord  WORD ?
sum WORD 25
count WORD 10
stdDev WORD 65
thousand WORD 1000

.code
main:

    fstcw oldCtrlWord               ; store control word
    mov ax, oldCtrlWord
    and ah, 11110011b               ; clear _only_ RC field
    or  ah, 00000100b               ; set _only_ RC field (rounding to -∞)
    mov newCtrlWord, ax
    fldcw newCtrlWord               ; load control word

    fild   sum                      ; load integer into ST(0)
    fidiv  count                    ; divide ST(0) by mem int
    fimul thousand                  ; thousand=10^3 - preserve three decimal digits of the fractional part
    frndint                         ; only for this you need the control word
    fidiv thousand                  ; adjust integer to a correct rational number (reverse the `fimul thousand`)
    call WriteFloat                 ; +2.5000000E+000
    call CRLF

    fild stdDev                     ; load variance integer into ST(0)
    fidiv count                     ; average the result
    fsqrt                           ; +2.5495097E+000
    fimul thousand                  ; thousand=10^3 - preserve three decimal digits of the fractional part
    frndint                         ; only for this you need the control word
    fidiv thousand                  ; adjust integer to a correct rational number (reverse the `fimul thousand`)
    call WriteFloat                 ; +2.5490000E+000
    call CRLF

    fldcw  oldCtrlWord              ; restore control word

    exit

END main