2017-01-18 6 views
2

부동 소수점을 Q31 고정 소수점으로 변환해야하며, Q31은 1 부호 비트를 의미하고 정수 부분은 0 비트이고 소수 부분은 31 비트로 변환해야합니다. 즉, Q31은 [-1,0.9999] 범위의 숫자 만 나타낼 수 있습니다.매핑 [-1, + 1]은 Q31 고정 소수점으로 부동합니다.

정의에

은 고정 소수점 플로트 변환 할 때, 2ˇN 의한 승산은, 난이 코드와 혼동있어 31

그러나,이 경우, N은 소수 부분의 크기이고, 수행 잘 보이지 않지만 작동합니다 :

#define q31_float_to_int(x) ((int) ((float)(x)*(float)0x7FFFFFFF)) 

잘 작동하는 것 같습니다. 예 :

int a = q31_float_to_int(0.5f); 

Hex: 0x40000000입니다.

왜 여기에서의 승산은 2ˇ31 - 1 일 뿐이며 2ˇ31이 아닌가?

+1

'(플로트) 0x7FFFFFFF'는'2147483648.00000'은 http : //ideone.com/mawlXx. 'unsigned'로 캐스팅 한 후에도 값이 유지됩니다. http://ideone.com/7WMeRE – mch

+0

Hmm ?? 어떻게 0x7FFFFFFF가 2147483648이 아닌 2147483647로 끝나는가 ?? – Danijel

+3

2147483647은 'float'로 표현할 수 없기 때문에 2147483648 인 가장 가까운 대표 번호를 취합니다. – mch

답변

1

위의 코드는 부동 소수점을 고정 소수점으로 변환하는 좋은 해결책이 아닙니다. 나는 입력이 1.0 인 경우 오버 플로우를 피하기 위해 코드를 작성한 사람이 0x7FFFFFFF의 축척 계수를 사용했다고 추측합니다. 올바른 배율 인수는 2^31이고 2^31 - 1이 아닙니다. float (정밀도 24 비트)을 Q1.31 (정밀도 31 비트)으로 변환 할 때도 정밀도 문제가 있음에 유의하십시오. 승산하기 전에 입력 데이터 포화 고려 : 위의 코드 [-1.0, 1.0)의 범위 input 클램프한다

const float Q31_MAX_F = 0x0.FFFFFFp0F; 
const float Q31_MIN_F = -1.0F; 
float clamped = fmaxf(fminf(input, Q31_MAX_F), Q31_MIN_F); 

. Q31_MAX_F 상수는 24 비트의 정밀도를 고려할 때 약 1 - (2^-24)이고 Q31_MIN_F-1입니다. 그럼 당신은 2^31에 의해 clamped를 곱하거나 더 나은, scalbnf, 또는 ldexpf 사용

int result = (int) scalbnf(clamped, 31); 

을 그리고 당신은 반올림하려는 경우 :

int result = (int) roundf(scalbnf(clamped, 31))); 
+0

1에서 왜 가장 큰 'float'이 아닌'0x7FFFFF00.p-31F; '를 사용해야합니까? '(0x7FFFFF80.p-31F;)'더 나은, 이식성 :'Q31_MAX_F = nextafterf (1.0,0.0); Q31_MIN_F = -1.0f;' – chux

+0

_round_에 'int32_t result = (int32_t) lround (scalbnf (clamped, 31));' – chux

+0

고마워. 귀하의 의견에 따라 업데이트되었습니다. –