2014-05-19 6 views
-1

본질적으로해야 할 일은 메인 작업에있는 것을 만드는 것입니다.ASM에서 반올림 기능의 마지막 확장

저는이 임무의 마지막 스트레치에 있습니다. (여기에 오기까지 한 것처럼 오래 걸릴 것입니다.) roundD에 전달 된 roundingMode를 전달하는 방법을 알아내는 데 어려움이 있습니다. 그것은 ASM에서.

또한 내가 말할 수있는 한, 단지 내가 남긴 모든 의견이 있습니다. 그게 옳은가요?

#include <stdio.h> 
#include <stdlib.h> 

#define PRECISION   3 
#define RND_CTL_BIT_SHIFT 10 

// floating point rounding modes: IA-32 Manual, Vol. 1, p. 4-20 
typedef enum { 
    ROUND_NEAREST_EVEN = 0 << RND_CTL_BIT_SHIFT, 
    ROUND_MINUS_INF =  1 << RND_CTL_BIT_SHIFT, 
    ROUND_PLUS_INF =  2 << RND_CTL_BIT_SHIFT, 
    ROUND_TOWARD_ZERO =  3 << RND_CTL_BIT_SHIFT 
} RoundingMode; 

double roundD(double n, RoundingMode roundingMode) 
{ 
// do not change anything above this comment 

    int    oldCW = 0x0000; 
    int    newCW = 0xF3FF; 
    int    mask = 0x0300; 
    int    tempVar = 0x0000; 


    asm(" push %eax       \n" 
     " push %ebx       \n" 
     " fstcw %[oldCWOut]      \n"  //store FPU CW into OldCW 
     " mov  %%eax, %[oldCWOut]    \n"  //store old FPU CW into tempVar 
     " mov  %[tempVarIn], %%eax    \n" 
     " add  %%eax, %[maskIn]    \n"  //isolate rounding bits 
     " add  %%eax, %[roundModeOut]   \n"  //adding rounding modifier 
                  //shift in old bits to tempFPU 
                  //do rounding calculation 
                  //store result into n 
     " fldcw %[oldCWIn]      \n"  //restoring the FPU CW to normal 
     " pop  %ebx       \n" 
     " pop  %eax       \n" 

     : [oldCWOut]  "=m" (oldCW), 
      [newCWOut]  "=m" (newCW), 
      [maskOut]  "=m" (mask), 
      [tempVarOut] "=m" (tempVar), 
      [roundModeOut] "=m" (roundMode) 

     : [oldCWIn]  "m"  (oldCW), 
      [newCWIn]  "m"  (newCW), 
      [maskIn]  "m"  (mask), 
      [tempVarIn]  "m"  (tempVar), 
      [roundModeIn] "m"  (roundMode) 
     :"eax", "ebx" 
    ); 

return n; 

// do not change anything below this comment, except for printing out your name 
} 

int main(int argc, char **argv) 
{ 
    double n = 0.0; 

    if (argc > 1) 
     n = atof(argv[1]); 

    printf("roundD even %.*f = %.*f\n", 
      PRECISION, n, PRECISION, roundD(n, ROUND_NEAREST_EVEN)); 
    printf("roundD down %.*f = %.*f\n", 
      PRECISION, n, PRECISION, roundD(n, ROUND_MINUS_INF)); 
    printf("roundD up %.*f = %.*f\n", 
      PRECISION, n, PRECISION, roundD(n, ROUND_PLUS_INF)); 
    printf("roundD zero %.*f = %.*f\n", 
      PRECISION, n, PRECISION, roundD(n, ROUND_TOWARD_ZERO)); 

    return 0; 
} 
+0

Cygwin에서 GCC를 사용 중입니다. –

+0

AT & T-syntax에서 ** second ** 피연산자가 대상이며 Intel 구문의 첫 번째 피연산자가 아닙니다. – rkhb

답변

0

C는 열거 형이 정수가 아닌 것처럼 가장 할 수도 있지만 단지 정수입니다. 어셈블리에서 직접 roundingMode를 사용할 수없는 경우 정수 로컬 변수를 만들고 roundingMode 매개 변수와 동일하게 설정하십시오.

나는 단지 당신에게 제안으로서 이것을 제공 할뿐입니다. 필자는 이전에 인라인 어셈블리를 사용 해본 적이 없으며 이전에 x86 어셈블리를 사용 해본 적은 한 번도 없었지만 위의 매개 변수를 참조하면됩니다.