FAQ der Newsgroup de.comp.lang.assembler (d.c.l.a.)

Wie wandle ich ein Integer (Dword) in eine Gleitkommazahl (Double) um?

Am einfachsten ist es, die Arbeit der FPU zu überlassen:

Nasm
BITS 32
SEGMENT .data
        int32:  dd 1919641698  ; Integer
        int64:  dq 1919641698  ; Long
SEGMENT .bss
        dbl: resq 1            ; Double (Ergebnis)
SEGMENT .text
SignedInt2Double:
    fninit
    push dword [int32]
    fild dword [esp]
    add esp, 4
    fstp qword [dbl]
    fninit
    ret

SignedLong2Double:
    fninit
    push dword [int64+4]       ; ACHTUNG! 'push qword' geht nicht gut
    push dword [int64+0]
    fild qword [esp]
    add esp, 8
    fstp qword [dbl]
    fninit
    ret

UnsignedInt2Double:
    fninit
    push 0
    push dword [int32]
    fild qword [esp]
    add esp, 8
    fstp qword [dbl]
    fninit
    ret

Das erste 'fninit' ist für den Fall, dass die FPU nach der letzten Operation nicht aufgeräumt wurde. Das zweite 'fninit' räumt die FPU auf (sinnvoll für Programmierfehler). Beide 'fninit' können meistens weggelassen werden.

Man kann es aber auch umständlich ohne FPU machen:

Nasm
BITS 32
SEGMENT .data
        int32:  dd 1919641698  ; Int
SEGMENT .bss
        dbl: resq 1            ; Double (Ergebnis)
SEGMENT .text
UnsignedInt2Double:
        xor edx, edx
        mov eax, [int32]
        or eax, eax
        jz .J2                 ; EAX = 0

        bsr ebx, eax           ; erste 1 von links finden
        lea edx, [ebx+1023]    ; Bias
        mov cl, 32             ; Anzahl Bits des Integer
        sub cl, bl             ; bl: Stelle der ersten 1
        shl eax, cl            ; nach links (führende Nullen & führende 1 löschen)
        shld edx, eax, 20      ; in das Double (high) schieben (Bias nach links)
        shl eax, 20            ; Double(low) anpassen

    .J2:
        mov [dbl], eax
        mov [dbl+4], edx

        ret

SignedInt2Double:
        mov eax, [int32]

        xor ecx, ecx           ; OR-Maske Vorzeichen
        or eax, eax
        jz .J2                 ; EAX = 0
        jns .J1                ; EAX > 0
        mov ecx, 100000000000b ; OR-Maske Vorzeichen
        neg eax                ; EAX = |EAX|

    .J1:
        bsr ebx, eax           ; erste Eins von links finden
        lea edx, [ebx+1023]    ; Bias
        or  edx, ecx           ; Vorzeichen
        mov cl, 32             ; Anzahl Bits des Integer
        sub cl, bl             ; bl: Stelle der ersten 1
        shl eax, cl            ; nach links (führende Nullen & führende 1 löschen)
        shld edx, eax, 20      ; in das Double (high) schieben (Bias nach links)
        shl eax, 20            ; Double(low) anpassen

    .J2:
        mov [dbl], eax
        mov [dbl+4], edx

        ret

Ralph 'rkhb' Bauer Aug 2008