我明天有一个作业,我需要找到一个数组中浮点值的平均值。我似乎无法在本书或我的笔记中找到任何关于将整数转换为浮点数(ecx(数组长度)中的值为5到5.0)的任何相对有用的内容,因此我可以在不截断的情况下进行除法。)
这是我给出的代码,只有两行标记为line1和line2需要更改,但我似乎无法弄清楚他们需要改变什么。关于如何使这项工作的任何想法?
c ++文件
#include <stdio.h>
extern"C"
{
float average(float [], int); // external assembly function prototypes
float max(float [], int);
float min(float [], int);
}
int main()
{
const int SIZE = 5;
float floatArr[SIZE] = {2.2, 3.75, 1.11, 5.9, 4.64};
printf("The array contains the float numbers: ");
for (int i = 0; i<SIZE; i++)
printf("%f ", floatArr[i]);
float val1 = average(floatArr, SIZE);
printf("\n\nThe average of the floats are: %f\n", val1);
float val2 = max(floatArr, SIZE);
printf("The largest float is: %f\n", val2);
float val3 = min(floatArr, SIZE);
printf("The smallest float is: %f\n", val3);
return 0;
}
asm文件
.686
.model flat
.code
_average PROC
push ebp ; save the caller frame pointer
mov ebp, esp
mov ebx, [ebp+8] ; address of first element in array
mov ecx, [ebp+12] ; store size of array in ecx
xor edx, edx ; counter for loop
fldz ; set top of FPU stack to zero
loopAdd:
fld dword ptr[ebx+edx*4] ; load next array onto register stack at st(1)
faddp ; add st(0) to st(1) and pop register stack
inc edx ; increment counter
cmp ecx, edx ; compare size of array in ecx with counter in edx
jg loopAdd ; if ecx > edx jump to loopAdd and continue
line1 cvtsi2sd eax, xmm0 ;load array size as float to compute average
line2 fdivp ;divide st(0) by st(1) and pop register stack
pop ebp ; restore caller frame pointer
ret ; content of st(0) is returned
_average ENDP
END
答案 0 :(得分:2)
我决定查看您的代码以提出解决方案。不要使用xmm寄存器。这些是SIMD指令,由于其余代码使用的是x87 FPU,我建议继续使用x87 FPU指令。
看来您的代码正确地对数组中的所有数字求和,并将该总和留在寄存器 st(0)中。您还可以在 ECX 中分配项目数。因此,您需要将 st(0)除以 ECX 中的整数值。
要完成此操作,您必须将 ECX 的值临时存储在临时内存变量中。这是因为FIDIV instruction不接受寄存器操作数。 FIDIV
将要做的是除去 st(0)(FPU堆栈的顶部)并将其除以32位内存位置指定的32位整数。
您需要先在函数中添加.data
部分以保存整数值(numitems):
.data
numitems DWORD 0
.code
而不是你在这里尝试的东西:
line1 cvtsi2sd eax, xmm0 ;load array size as float to compute average
line2 fdivp ;divide st(0) by st(1) and pop register stack
这样做:
mov numitems, ecx ;Move ecx(# of items in array) to numitems variable
FIDIV numitems ;divide st(0) by value in numitems variable
;After division st(0) should contain the average
代码如下所示:
.686
.model flat
.code
_average PROC
.data
numitems DWORD 0
.code
push ebp ; save the caller frame pointer
mov ebp, esp
mov ebx, [ebp+8] ; address of first element in array
mov ecx, [ebp+12] ; store size of array in ecx
xor edx, edx ; counter for loop
fldz ; set top of FPU stack to zero
loopAdd:
fld dword ptr[ebx+edx*4] ; load next array onto register stack at st(1)
faddp ; add st(0) to st(1) and pop register stack
inc edx ; increment counter
cmp ecx, edx ; compare size of array in ecx with counter in edx
jg loopAdd ; if ecx > edx jump to loopAdd and continue
mov numitems, ecx ;Move ecx(# of items in array) to numitems variable
FIDIV numitems ;divide st(0) by value in numitems variable
;After division st(0) should contain the average
pop ebp ; restore caller frame pointer
ret ; content of st(0) is returned
_average ENDP
END
此功能不可重复,因为它有效地使用静态变量numitems
来临时存储 ECX 。通过暂时将值放在堆栈上并执行FIDIV
,可以摆脱此临时静态变量。它的代码消除了.data
部分,并使用当前堆栈指针正下方的4个字节足够长时间来执行FIDIV
,然后简单地丢弃整数值。
.686
.model flat
.code
_average PROC
push ebp ; save the caller frame pointer
mov ebp, esp
mov ebx, [ebp+8] ; address of first element in array
mov ecx, [ebp+12] ; store size of array in ecx
xor edx, edx ; counter for loop
fldz ; set top of FPU stack to zero
loopAdd:
fld dword ptr[ebx+edx*4] ; load next array onto register stack at st(1)
faddp ; add st(0) to st(1) and pop register stack
inc edx ; increment counter
cmp ecx, edx ; compare size of array in ecx with counter in edx
jg loopAdd ; if ecx > edx jump to loopAdd and continue
mov [esp-4], ecx ;Move ecx(# of items in array) to temp location on stack
fidiv dword ptr [esp-4]
;divide st(0) by value in temporary stack location
;After division st(0) should contain the average
pop ebp ; restore caller frame pointer
ret ; content of st(0) is returned
_average ENDP
END
作为替代方案,由于 ECX 已经在内存位置 EBP + 12 的堆栈中传入,因此可以通过删除所有这些行来修改最后一个示例
mov [esp-4], ecx ;Move ecx(# of items in array) to temp location on stack
fidiv dword ptr [esp-4]
;divide st(0) by value in temporary stack location
;After division st(0) should contain the average
用这一行代替:
fidiv dword ptr [ebp+12]
;divide st(0) by SIZE (2nd argument passed on stack)
;After division st(0) should contain the average
答案 1 :(得分:0)
怎么样:
cvtsi2sd xmm0, ecx
fdiv xmm0
看起来太简单......
CVTSI2SD xmm, r/m32 Convert one signed doubleword integer from r/m32 to one double-precision floating-point value in xmm.
FDIV m32fp Divide ST(0) by m32fp and store result in ST(0).