2017-02-02 4 views
1

클래스 할당 작업 중 비트 처리를 사용하여 부동 소수점으로 캐스팅하려고합니다 (|/| & &. 또한, while). 내 코드는 대부분의 값에서 작동하지만 일부 값은 내가 찾고있는 결과를 생성하지 않습니다.비트 조작을 사용하여 부동 소수점 형을 사용하여 부동 소수점 형을 사용하는 부동 소수점 숫자로 변환

예를 들어 x가 0x807fffff이면 0xceff0001이 표시되지만 올바른 결과는 0xceff0000이어야합니다. 내 가수와 반올림으로 뭔가를 놓친 것 같아요,하지만 그것을 확실히 고정시킬 수는 없습니다. 나는 SO뿐만 아니라 일부 다른 스레드 검토 한 converting-int-to-floathow-to-manually

unsigned dl22(int x) { 


    int tmin = 0x1 << 31; 
    int tmax = ~tmin; 

    unsigned signBit = 0; 
    unsigned exponent; 
    unsigned mantissa; 
    int bias = 127; 

    if (x == 0) { 
     return 0; 
    } 

    if (x == tmin) { 
     return 0xcf << 24; 
    } 

    if (x < 0) { 
     signBit = x & tmin; 
     x = (~x + 1); 
    } 


    exponent = bias + 31; 

    while ((x & tmin) == 0) { 
     exponent--; 
     x <<= 1; 
    } 

    exponent <<= 23; 
    int mantissaMask = ~(tmin >> 8); 
    mantissa = (x >> 8) & mantissaMask; 

    return (signBit | exponent | mantissa); 
} 

EDIT/UPDATE 가능한 솔루션을 찾을 - 당신의 코드 예제에 나를 위해 예상되는 출력을 생성

+0

"비트 연산 만 사용"이라는 이상한 정의가 있습니다. 관계형 연산과 산술 연산도 코드에서 볼 수 있습니다. (그리고 단순하고 복합적인 대입 연산도 있지만, 할당을 배제하려는 것은 아닙니다.) –

+0

관계형 비교기와 정수 및 부호없는 곱셈은 허용되지만 형변환은 허용되지 않습니다 (if/while 루프 사용 가능) –

+1

참고 :'0x1 << 31'은 작동하지 않을지라도 정의되지 않은 동작입니다. – chux

답변

0

아래 참조 당신이 제시했습니다. 그러나 주석에서 논의했듯이 C의 관점에서 보면 tmin의 계산뿐만 아니라 동일한 이유로 지수를 계산하는 루프에서 정의되지 않은 동작을 나타냅니다. 이 코드가 환경에 따라 다른 결과를 생성하는 범위는 정의되지 않은 동작 또는 사용중인 C 구현에 대해 [unsigned] int 크기에 대한 가정으로부터 따릅니다. 우리가 (안전하지) 가정하면

그럼에도 불구하고, 왼쪽 피연산자에 운영 같은 비트 패턴으로 unsigned int으로 재 해석 한 것처럼 int의의 이동

  1. 작동하고, 그 결과 비트 패턴으로 재 해석 intintunsigned int가 최소한 너비가 32 비트라는 것을
  2. ,

다음 코드는 올바른 것 같습니다, 모듈로 반올림. 입력 int의 절대 값이 24 개 이상의 중요한 이진수를 보유하는 경우에는

그러나 일부 정밀도 변환 손실 될 것이다 (즉, 적어도 2 24이다). 이 경우 올바른 결과는 구현하려는 FP 반올림 모드에 따라 달라집니다. 잘못 반올림 된 결과는 마지막 위치에서 1 단위만큼 떨어져 있습니다. 영향을 미치는 결과의 수는 반올림 모드에 따라 다릅니다.

여분의 비트를 잘라내거나 이동하는 것만으로 제로 모드쪽으로 반올림됩니다. 이는 표준 반올림 모드 중 하나이지만 기본값은 아닙니다. 기본 반올림 모드는 가장 가까운 표현 가능한 숫자로 반올림되며, 최하위 비트 0 (짝수로 반올림 됨)을 갖는 결과를 위해 결속이 해결됩니다. 또한 세 가지 표준 모드가 있습니다. 0으로 반올림하는 것 이외의 다른 모드를 구현하려면, 스케일링 한 후 그리고 그들을 이동하기 전에 significand의 8 개의 최하위 비트를 포착해야합니다. 선택한 반올림 모드에 따라 다른 세부 정보와 함께 올바른 반올림을 적용하는 방법이 결정됩니다.

32 비트 2의 보수 중 절반은 제로 모드로 변환 할 때 다른 모드로 변환 할 때와 다르게 반올림됩니다. 숫자가 불일치하는 항목은 반올림 모드를 고려해야합니다.

+0

나는 이것이 바로 그 지점에 이르렀다 고 생각한다. 다시 모든 안내에 감사한다! {float u2f (unsigned u) { union { unsigned u;}이 코드를 포함하는 것을 잊었다는 것을 깨닫는다. float f; } a; a.u = u; 돌아 가기 a.f; }' –

0

내가 원래 내가 U2F 조합 문을 모방하기 위해 노력하고 있음을 언급하지 않았다 : 나는 후 다음으로 바꾸어 반올림 문제를 관리 할 수 ​​있었다 포스트 ieee-754-bit-manipulation-rounding-error에서 제공하는 지침에

float u2f(unsigned u) { 
    union { 
    unsigned u; 
    float f; 
    } a; 
    a.u = u; 
    return a.f; 
} 

덕분에 내 while 진술. 이로 인해 발생하는 반올림이 명확 해졌습니다.

lsb = (x >> 8) & 1; 
roundBit = (x >> 7) & 1; 
stickyBitFlag = !!(x & 0x7F); 

exponent <<= 23; 

int mantissaMask = ~(tmin >> 8); 
mantissa = (x >> 8); 
mantissa &= mantissaMask; 

roundBit = (roundBit & stickyBitFlag) | (roundBit & lsb); 

return (signBit | exponent | mantissa) + roundBit;