Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 浮点程序给出的结果无效_Assembly_Floating Point_X86_Masm_Irvine32 - Fatal编程技术网

Assembly 浮点程序给出的结果无效

Assembly 浮点程序给出的结果无效,assembly,floating-point,x86,masm,irvine32,Assembly,Floating Point,X86,Masm,Irvine32,最近编辑 我试图在x86 MASM上运行这个浮点二次方程程序。这段代码可以在Kip Irvine x86教科书中找到,我想看看它是如何可视化工作的。以下代码如下: include irvine32.inc .DATA a REAL4 3.0 b REAL4 7.0 cc REAL4 2.0 posx REAL4 0.0 negx REAL4 0.0 .CODE main proc ; Solve quadratic equation - no error checking ; The

最近编辑

我试图在x86 MASM上运行这个浮点二次方程程序。这段代码可以在Kip Irvine x86教科书中找到,我想看看它是如何可视化工作的。以下代码如下:

include irvine32.inc 
.DATA
a REAL4 3.0
b REAL4 7.0
cc REAL4 2.0
posx REAL4 0.0
negx REAL4 0.0

.CODE


main proc 
; Solve quadratic equation - no error checking
; The formula is: -b +/- squareroot(b2 - 4ac) / (2a)
fld1 ; Get constants 2 and 4
fadd st,st ; 2 at bottom
fld st ; Copy it
fmul a ; = 2a

fmul st(1),st ; = 4a
fxch ; Exchange
fmul cc ; = 4ac

fld b ; Load b
fmul st,st ; = b2
fsubr ; = b2 - 4ac
; Negative value here produces error
fsqrt ; = square root(b2 - 4ac)
fld b ; Load b
fchs ; Make it negative
fxch ; Exchange

fld st ; Copy square root
fadd st,st(2) ; Plus version = -b + root(b2 - 4ac)
fxch ; Exchange
fsubp st(2),st ; Minus version = -b - root(b2 - 4ac)

fdiv st,st(2) ; Divide plus version
fstp posx ; Store it
fdivr ; Divide minus version
fstp negx ; Store it

call writeint
exit 
main endp 
end main
因此,我能够让我的程序编译、执行并完全正常工作。但是,每当我运行程序时,我都会得到以下结果:

+1694175115
为什么结果如此之大?我还尝试调用writefloat,但它说这个过程不在Irvine32.inc或Macros.inc库中。有人能告诉我为什么它不工作以及需要修复什么吗?谢谢

感谢迈克尔·佩奇

您的错误不在于计算本身,MASM中的计算是正确的,而在于打印结果。对于打印浮点数,
writeint
不正确;您应该使用
WriteFloat
,它有自己的调用约定

WriteFloat
接受
st(0)
中的单个浮点,并将其打印到控制台[1]。它不会弹出x87堆栈中的值

因此,在您的FPU代码之后,您应该立即添加

fld  posx
call WriteFloat
call Crlf
fld  negx
call WriteFloat
call Crlf
emms
您还应该在开始时包含正确的MASM。类似于:

INCLUDE     irvine32.inc
INCLUDE     floatio.inc
INCLUDE     macros.inc
INCLUDELIB  kernel32.lib
INCLUDELIB  user32.lib
INCLUDELIB  Irvine32.lib
由于我的机器上没有MASM,我将您的程序重写为带有内联汇编的GNUC程序,除了每条指令都放在注释中外,还记录了当时浮点堆栈的状态

#包括
内部主(空){
asm(
“.intel\u语法\n”
“.data\n”
“a:。单个3.0\n”
“b:.单个7.0\n”
“抄送:。单个2.0\n”
“posx:。单个0.0\n”
“negx:。单个0.0\n”
“.text\n”
“fld1\n”//[1]
“fadd%st,%st\n”//[2]
“fld%st\n”//[2,2]
“fmul dword ptr a\n”//[2a,2]
“fmul%st(1),%st\n”//[2a,4a]
“fxch\n”//[4a,2a]
“fmul dword ptr抄送\n”//[4ac,2a]
“fld dword ptr b\n”//[b,4ac,2a]
“fmul%st,%st\n”//[b^2,4ac,2a]
“fsubrp\n”//[b^2-4ac,2a]
“fsqrt\n”//[sqrt(b^2-4ac),2a]
“fld dword ptr b\n”//[b,sqrt(b^2-4ac),2a]
“fchs\n”//[-b,sqrt(b^2-4ac),2a]
“fxch\n”//[sqrt(b^2-4ac),-b,2a]
“fld%st\n”//[sqrt(b^2-4ac),sqrt(b^2-4ac),-b,2a]
“fadd%st,%st(2)\n”//[-b+sqrt(b^2-4ac),sqrt(b^2-4ac),-b,2a]
“fxch\n”//[sqrt(b^2-4ac),-b+sqrt(b^2-4ac),-b,2a]
“fsubp%st(2),%st\n”//[-b+sqrt(b^2-4ac),-b-sqrt(b^2-4ac),2a]
“fdiv%st,%st(2)\n”//[(-b+sqrt(b^2-4ac))/2a,-b-sqrt(b^2-4ac),2a]
“fstp dword ptr posx\n”//[-b-sqrt(b^2-4ac),2a]
“fdivrp\n”//[(-b-sqrt(b^2-4ac))/2a]
“fstp dword ptr negx\n”//[]
“.att_语法\n”
);
外部浮点数posx,negx;
printf(“posx:%+0.17f\nnegx:%+0.17f\n”,posx,negx);
返回0;
}
印刷品

posx: -0.33333334326744080
negx: -2.00000000000000000
这是正确的:

  • 3*(-1/3)^2+7*(-1/3)+2=3/9-7/3+2=1/3-7/3+2=-6/3+2=-2+2=0
  • 3*(-2)^2+7*(-2)+2=3*4-14+2=12-14+2=-2+2=0

[1]§12.2.7读取和写入浮点值

浮点数在专用处理器(FPU)的专用寄存器中进行处理,并以特殊格式存储,不能被视为整数(
WriteInt
)。浮点数包含有关数字的更多信息,如符号和指数。数字本身更改为1到2之间的数字,并具有适当的指数,其中前导1通常隐藏。请在此处查看双格式:。这些数字不太可能精确

至少从11年以来,Irvine32库提供函数
WriteFloat
,以指数形式显示FPU寄存器ST0的值。它不会弹出或释放该寄存器

改变

call writeint

如果您的库没有
WriteFloat
,我建议从Irvine的主页下载并安装最新文件:(第七版的示例程序和链接库源代码)。您还可以使用其他库,例如C-runtime库(msvcrt.inc和msvcrt.lib)或

如果无法使用提供浮点例程的库,则必须自己转换数字:

INCLUDE irvine32.inc

.DATA
    a REAL4 3.0
    b REAL4 7.0
    cc REAL4 2.0
    posx REAL4 0.0
    negx REAL4 0.0

    buf BYTE 1024 DUP (?)

.CODE

double2dec PROC C USES edi              ; Args: ST(0): FPU-register to convert, EDI: pointer to string
LOCAL CONTROL_WORD:WORD, TEN:WORD, TEMP:WORD, DUMMY:QWORD

    ; modifying rounding mode
    fstcw CONTROL_WORD
    mov ax, CONTROL_WORD
    or ah, 00001100b            ; Set RC=11: truncating rounding mode
    mov TEMP, ax
    fldcw TEMP                  ; Load new rounding mode

    ; Check for negative
    ftst                        ; ST0 negative?
    fstsw ax
    test ah, 001b
    jz @F                       ; No: skip the next instructions
    mov byte ptr [edi], '-'     ; Negative sign
    add edi, 1
    @@:
    FABS                        ; Abs (upper case to differ from C-library)

    ; Separate integer and fractional part & convert integer part into ASCII
    fst st(1)                   ; Doubling ST(0) - ST(1)=ST(0)
    frndint                     ; ST(0) to integer
    fsub st(1), st(0)           ; Integral part in ST(0), fractional part in ST(1)

    ; Move 10 to st(1)
    mov TEN, 10
    fild TEN
    fxch

    xor ecx, ecx                ; Push/pop counter

    @@:                         ; First loop
    fst st(3)                   ; Preserve ST(0)
    fprem                       ; ST(0) = remainder ST(0)/ST(1)
    fistp word ptr TEMP         ; ST(3) -> ST(2) !
    push word ptr TEMP
    inc ecx
    fld st(2)                   ; Restore ST(0)
    fdiv st(0), st(1)
    frndint                     ; ST(0) to integer
    fxam                        ; ST0 == 0.0?
    fstsw ax
    sahf
    jnz @B                      ; No: loop

    fxch st(2)                  ; ST(0) <-> ST(2) (fractional part)
    ffree st(2)
    ffree st(3)

    @@:                         ; Second loop
    pop ax
    or al, '0'
    mov [edi], al
    inc edi
    loop @B                     ; Loop ECX times

    mov byte ptr [edi], '.'     ; Decimal point
    add edi, 1

    ; Isolate digits of fractional part and store ASCII
    get_fractional:
    fmul st(0), st(1)           ; Multiply by 10 (shift one decimal digit into integer part)
    fist word ptr TEMP          ; Store digit
    fisub word ptr TEMP         ; Clear integer part
    mov al, byte ptr TEMP       ; Load digit
    or al, 30h                  ; Convert digit to ASCII
    mov byte ptr [edi], al      ; Append it to string
    add edi, 1                  ; Increment pointer to string
    fxam                        ; ST0 == 0.0?
    fstsw ax
    sahf
    jnz get_fractional          ; No: once more
    mov byte ptr [edi], 0       ; Null-termination for ASCIIZ

    ; clean up FPU
    ffree st(0)                 ; Empty ST(0)
    ffree st(1)                 ; Empty ST(1)
    fldcw CONTROL_WORD          ; Restore old rounding mode

    ret                         ; Return: EDI points to the null-terminated string
double2dec ENDP


main proc
    ; Solve quadratic equation - no error checking
    ; The formula is: -b +/- squareroot(b2 - 4ac) / (2a)
    fld1 ; Get constants 2 and 4
    fadd st,st ; 2 at bottom
    fld st ; Copy it
    fmul a ; = 2a

    fmul st(1),st ; = 4a
    fxch ; Exchange
    fmul cc ; = 4ac

    fld b ; Load b
    fmul st,st ; = b2
    fsubr ; = b2 - 4ac
    ; Negative value here produces error
    fsqrt ; = square root(b2 - 4ac)
    fld b ; Load b
    fchs ; Make it negative
    fxch ; Exchange

    fld st ; Copy square root
    fadd st,st(2) ; Plus version = -b + root(b2 - 4ac)
    fxch ; Exchange
    fsubp st(2),st ; Minus version = -b - root(b2 - 4ac)

    fdiv st,st(2) ; Divide plus version
    fstp posx ; Store it
    fdivr ; Divide minus version
    fstp negx ; Store it

    ; Write the results

    fld posx            ; Load floating point number into ST0
    lea edi, buf        ; EDI: pointer to a buffer for a string
    call double2dec     ; Convert ST0 to buf and pop
    mov edx, edi        ; EDX: pointer to a null-terminated string
    call WriteString    ; Irvine32

    call Crlf           ; Irvine32: New line

    fld negx            ; Load floating point number into ST0
    lea edi, buf        ; EDI: pointer to a buffer for a string
    call double2dec     ; Convert ST0 to buf and pop
    mov edx, edi        ; EDX: pointer to a null-terminated string
    call WriteString    ; Irvine32

    call Crlf           ; Irvine32: New line

    exit                ; Irvine32: ExitProcess
main ENDP
end main
包括irvine32.inc
.数据
REAL4 3.0
b REAL4 7.0
cc REAL4 2.0
posx REAL4 0.0
negx REAL4 0.0
字节1024重复(?)
.代码
double2dec程序C使用edi;Args:ST(0):要转换的FPU寄存器,EDI:指向字符串的指针
本地控制字:字、十字、温度字、虚拟字
; 修改舍入模式
控制字
mov-ax,控制字
或者啊,0000110b,;设置RC=11:截断舍入模式
移动温度
fldcw温度;加载新的舍入模式
; 检查是否为阴性
ftst;ST0阴性?
fstsw ax
测试ah,001b
jz@F;否:跳过下一个说明
mov字节ptr[edi],“-”;负号
添加edi,1
@@:
晶圆厂;Abs(大写字母与C-library不同)
; 分离整数和小数部分&将整数部分转换为ASCII
fst-st(1);加倍ST(0)-ST(1)=ST(0)
第一次;ST(0)到整数
fsub-st(1),st(0);ST(0)中的整数部分,ST(1)中的小数部分
; 移动10到街(1)
第十节,第十节
第十卷
fxch
异或ecx,ecx
INCLUDE irvine32.inc

.DATA
    a REAL4 3.0
    b REAL4 7.0
    cc REAL4 2.0
    posx REAL4 0.0
    negx REAL4 0.0

    buf BYTE 1024 DUP (?)

.CODE

double2dec PROC C USES edi              ; Args: ST(0): FPU-register to convert, EDI: pointer to string
LOCAL CONTROL_WORD:WORD, TEN:WORD, TEMP:WORD, DUMMY:QWORD

    ; modifying rounding mode
    fstcw CONTROL_WORD
    mov ax, CONTROL_WORD
    or ah, 00001100b            ; Set RC=11: truncating rounding mode
    mov TEMP, ax
    fldcw TEMP                  ; Load new rounding mode

    ; Check for negative
    ftst                        ; ST0 negative?
    fstsw ax
    test ah, 001b
    jz @F                       ; No: skip the next instructions
    mov byte ptr [edi], '-'     ; Negative sign
    add edi, 1
    @@:
    FABS                        ; Abs (upper case to differ from C-library)

    ; Separate integer and fractional part & convert integer part into ASCII
    fst st(1)                   ; Doubling ST(0) - ST(1)=ST(0)
    frndint                     ; ST(0) to integer
    fsub st(1), st(0)           ; Integral part in ST(0), fractional part in ST(1)

    ; Move 10 to st(1)
    mov TEN, 10
    fild TEN
    fxch

    xor ecx, ecx                ; Push/pop counter

    @@:                         ; First loop
    fst st(3)                   ; Preserve ST(0)
    fprem                       ; ST(0) = remainder ST(0)/ST(1)
    fistp word ptr TEMP         ; ST(3) -> ST(2) !
    push word ptr TEMP
    inc ecx
    fld st(2)                   ; Restore ST(0)
    fdiv st(0), st(1)
    frndint                     ; ST(0) to integer
    fxam                        ; ST0 == 0.0?
    fstsw ax
    sahf
    jnz @B                      ; No: loop

    fxch st(2)                  ; ST(0) <-> ST(2) (fractional part)
    ffree st(2)
    ffree st(3)

    @@:                         ; Second loop
    pop ax
    or al, '0'
    mov [edi], al
    inc edi
    loop @B                     ; Loop ECX times

    mov byte ptr [edi], '.'     ; Decimal point
    add edi, 1

    ; Isolate digits of fractional part and store ASCII
    get_fractional:
    fmul st(0), st(1)           ; Multiply by 10 (shift one decimal digit into integer part)
    fist word ptr TEMP          ; Store digit
    fisub word ptr TEMP         ; Clear integer part
    mov al, byte ptr TEMP       ; Load digit
    or al, 30h                  ; Convert digit to ASCII
    mov byte ptr [edi], al      ; Append it to string
    add edi, 1                  ; Increment pointer to string
    fxam                        ; ST0 == 0.0?
    fstsw ax
    sahf
    jnz get_fractional          ; No: once more
    mov byte ptr [edi], 0       ; Null-termination for ASCIIZ

    ; clean up FPU
    ffree st(0)                 ; Empty ST(0)
    ffree st(1)                 ; Empty ST(1)
    fldcw CONTROL_WORD          ; Restore old rounding mode

    ret                         ; Return: EDI points to the null-terminated string
double2dec ENDP


main proc
    ; Solve quadratic equation - no error checking
    ; The formula is: -b +/- squareroot(b2 - 4ac) / (2a)
    fld1 ; Get constants 2 and 4
    fadd st,st ; 2 at bottom
    fld st ; Copy it
    fmul a ; = 2a

    fmul st(1),st ; = 4a
    fxch ; Exchange
    fmul cc ; = 4ac

    fld b ; Load b
    fmul st,st ; = b2
    fsubr ; = b2 - 4ac
    ; Negative value here produces error
    fsqrt ; = square root(b2 - 4ac)
    fld b ; Load b
    fchs ; Make it negative
    fxch ; Exchange

    fld st ; Copy square root
    fadd st,st(2) ; Plus version = -b + root(b2 - 4ac)
    fxch ; Exchange
    fsubp st(2),st ; Minus version = -b - root(b2 - 4ac)

    fdiv st,st(2) ; Divide plus version
    fstp posx ; Store it
    fdivr ; Divide minus version
    fstp negx ; Store it

    ; Write the results

    fld posx            ; Load floating point number into ST0
    lea edi, buf        ; EDI: pointer to a buffer for a string
    call double2dec     ; Convert ST0 to buf and pop
    mov edx, edi        ; EDX: pointer to a null-terminated string
    call WriteString    ; Irvine32

    call Crlf           ; Irvine32: New line

    fld negx            ; Load floating point number into ST0
    lea edi, buf        ; EDI: pointer to a buffer for a string
    call double2dec     ; Convert ST0 to buf and pop
    mov edx, edi        ; EDX: pointer to a null-terminated string
    call WriteString    ; Irvine32

    call Crlf           ; Irvine32: New line

    exit                ; Irvine32: ExitProcess
main ENDP
end main