Pergunta

I would like to know, what values should I use to change FPU rounding mode.

.data
nearest:
    ??
down:
    ??
up:
    ??
zero:
    ??
.text
.global round
    pushl   %ebp
    movl    %esp, %ebp
    movl 8(%ebp), %ecx

    cmpl $1, %ecx
je
    fldcw nearest

    cmpl $2, %ecx
je
    fldcw down

    cmpl $3, %ecx
je
    fldcw up

    cmpl $4, %ecx
je
    fldcw zero
leave
ret

I found something like this:

down:
    .byte 0x7f, 0x07
up:
    .byte 0x7f, 0x0b

but I don't know why somebody used it. I know I should change 8 and 9 bits, like this: 00 — round to nearest 01 — round down (toward negative infinity) 10 — round up (toward positive infinity) 11 — round toward zero

Foi útil?

Solução

The type of rounding is determined by two bits in the control word of the FPU. You can get information about the FPU here: http://www.website.masmforum.com/tutorials/fptute/fpuchap1.htm. It's a little bit tricky to change only these two bits and left the others unchanged. Take a look at my example. I tried to be as close as possible to your code:

.data
    num:        .double 6.5     # play with the number!

    old:        .word 0
    nearest:    .word 0x0000
    down:       .word 0x0400
    up:         .word 0x0800
    zero:       .word 0x0C00
    result:     .double 0
    fmt1:       .asciz "nearest: %f -> %f\n"
    fmt2:       .asciz "down:    %f -> %f\n"
    fmt3:       .asciz "up:      %f -> %f\n"
    fmt4:       .asciz "zero:    %f -> %f\n"

.text
.globl main
main:

    fstcw old               # store old control word

    movw old, %ax
    andb $0b11110011, %ah   # clear RC field
    orw %ax, nearest
    orw %ax, down
    orw %ax, up
    orw %ax, zero

    fldcw nearest           # banker's rounding
    call round
    mov $fmt1, %esi
    call out

    fldcw down              # down toward -infinity
    call round
    mov $fmt2, %esi
    call out

    fldcw up                # up toward +infinity
    call round
    mov $fmt3, %esi
    call out

    fldcw zero              # truncating
    call round
    mov $fmt4, %esi
    call out

    fldcw old               # restore old control word

    xor %eax, %eax          # exit(0)
    ret                     # GCC only needs RET

round:
    fldl num
    frndint
    fstpl result
    ret

out:
    push result+4
    push result
    push num+4
    push num
    push %esi
    call printf             # "%f" needs a double
    add $20, %esp
    ret
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top