2010-02-12 2 views
5

컴퓨터 과학 수업에서 어셈블리를 배우기 시작하고 지정된 반올림 모드를 사용하여 부동 소수점 값을 반올림하도록 과제를 할당했습니다. . 나는 이것을 fstcw, fldcwfrndint을 사용하여 구현하려고 시도했습니다. 반올림 제어 비트를 수정하고 숫자를 반올림 한 다음 이전 제어 비트 (할당 요구 사항)를 복원합니다.인라인 어셈블리 (GCC, IA-32)에서 배정도 숫자로 작업하기

현재 뛰어난 문제) 명령 fld %1 내가 2.6207의 값을 가진 함수 수 -1.9427를 (호출하는 경우 (예를 들어, st(0) 부동 소수점 레지스터에 잘못된 값을로드하는 것 때문이다 .. e-29가 레지스터에로드 됨). 이는 gcc의 인라인 asm() 또는 다른 것의 오용으로 인한 것일 수 있지만 그 이유는 확실하지 않습니다.

여기에 내가 가진 무엇 :

double roundD (double n, RoundingMode roundingMode) 
{ 
    // control word storage (2 bytes for previous, 2 for current) 
    char *cw = malloc(4*sizeof(char)); 
    char *cw2 = cw + 2; 

    asm("fstcw %3;" // store control word in cw 
     "mov %3,%4;" // copy control word into cw2 
     "and $0xF3FF,%4;" // zero out rounding control bits 
     "or %2,%4;" // put new mode into rounding control bits 
     "fldcw %5;" // load the modified control word 
     "fld %1;" // load n into st(0) 
     "frndint;" // round n 
     "fstp %0;" // load st(0) back into n 
     "fldcw %3;" // load the old control word from cw 
     : "=m" (n) 
     : "m" (n), "m" (roundingMode), 
      "m" (cw), "r" (cw2), "m" (cw2) // mov requires one argument in a register 
     ); 

    free(cw); 

    return n; 
} 

나는 특히 fld %1 라인과 asm 입력/출력에 관한, 그 코드 뭐가 잘못에 대한 포인터를 감사하겠습니다. (물론 다른 문제를 발견 할 수 있다면 그들에 대해서도 알려 주시기 바랍니다.) 나는 누군가가 나를 위해 숙제를하고 싶지 않다. 올바른 방향으로 나를 가리킨다. 감사!

+0

와우, 그건 아주 불량합니다. 내가 도울 수 있으면 좋겠지 만 나는 못 하겠어! :) –

+0

이 함수의 어셈블리 출력을 표시 할 수 있습니까? 그리고 너무 많은 문제가 아니라면 코드 바이트. –

+0

@ 존 : 조립 될 코드는 놀랄 일이 아닙니다. 그것은 거대한 불투명 (gcc에) asm 블록에 모두있다. :-P 반면, 많은 작은 asm 문장 (내 게시물과 같은)으로 분할하는 것은 gcc가 다른 일을 할 수있는 더 위도를 줄 것입니다. –

답변

2

현재 코드에서 적어도 하나의 문제는 fld와 fstp의 단 정밀도 부동 소수점 버전을 사용한다는 것입니다. fldl 및 fstpl로 대체하면 아마 작동 할 것입니다.

+0

나는 그것을 찾았다. gcc가 AT & T 명령어를 사용하고 l 피연산자를 요구하기 때문에 이것이 올바른 해결책 인 것 같습니다. 따라서 FLDL이 옳습니다. –

+0

+1 예, * l 버전이 작동합니다. 내가 게시 한 스 니펫은 분해 될 때 * l 접미사도 붙습니다. (분명히, 제 경우에는 gcc가 수동으로로드/저장 명령을 코딩하는 대신 제약 조건을 사용하여 모든 노력을 다하도록 선택했습니다.) –

+0

질문의 정신을 유지하려했지만 대답은 훨씬 낫습니다.) – tyranid

2

다음은 내가 가진 것입니다. 테스트를 거치지는 않았지만 잘하면 당신이 일하기에 덜 노골적 일 것입니다. :-) 당신이 당신의 반올림 모드를 달성하기 위해 어셈블리를 사용하는 데 필요하지 않는 경우, 대신 <fenv.h>의 기능을 사용하는 방법에 대한

double 
roundd(double n, short mode) 
{ 
    short cw, newcw; 

    __asm__("fstcw %w0" : "=m" (cw)); 
    newcw = cw & 0xf3ff | mode; 
    __asm__("fldcw %w0" : : "m" (newcw)); 
    __asm__("frndint" : "+t" (n)); 
    __asm__("fldcw %w0" : : "m" (cw)); 
    return n; 
} 

을 생각하지만. :-)

+0

어셈블리를 사용해야합니다. – jtbandes

+0

@jtbandes : Cool. 이 경우 자유롭게 내 버전을 테스트하고 수정해야 할 부분을 알려주십시오. :-) –

+0

'+ t' 제약 조건은 어떻게 작동합니까? 다른 사람들을 찾은 곳의 정보를 찾을 수 없습니다. – jtbandes

0

기호가 변경되면 기호 비트 (가장 중요한 기호 비트)가 올바르지 않다는 의미입니다. 그게 % 1 포인터가 잘못 정렬되었다고 가정 해 봅시다. 1 바이트가 있다면 은 0,1,2로 시작할 수 있지만 2 바이트를 액세스하면 주소는 0,2,4가되어야합니다 ... 그리고 의 두 배인 주소는 짝수 여야합니다 dividable by 8 : 0,8,16

값을로드하는 데 사용하는 주소가 8로 나눌 수 있는지 확인하십시오. 어셈블리에 데이터가 올바르게 정렬되도록 align 키워드가 있습니다.

+1

이 정렬은 x86에서 필요하지는 않지만 성능을 위해서만 권장됩니다. –

관련 문제