2010-04-07 3 views
17

저는 수학 라이브러리가없는 플랫폼을 개발 중이므로 직접 도구를 만들어야합니다. 분수를 얻는 현재의 방법은 부동 소수점을 고정 소수점으로 변환하고 (float) 0xFFFF로 곱하고 int로 캐스트 한 다음 하위 부분 만 가져옵니다 (0xFFFF가있는 마스크). 다시 float로 변환합니다.modf()를 사용하지 않고 float의 소수 부분 얻기

그러나 부정확하게 나를 죽이고 있습니다. 내 Frac() 및 InvFrac() 함수를 사용하여 앤티 앨리어싱 된 선을 그립니다. modf을 사용하면 완벽하게 부드러운 선을 얻습니다. 내 자신의 방법으로 픽셀 정밀도 손실로 인해 주위를 시작 뛰어. 사전에

const float fp_amount = (float)(0xFFFF); 
const float fp_amount_inv = 1.f/fp_amount; 

inline float Frac(float a_X) 
{ 
    return ((int)(a_X * fp_amount) & 0xFFFF) * fp_amount_inv; 
} 

inline float Frac(float a_X) 
{ 
    return (0xFFFF - (int)(a_X * fp_amount) & 0xFFFF) * fp_amount_inv; 
} 

감사 :

이 내 코드입니다!

+2

fp_amount가 0xFFFF가 아닌 0x10000일까요? –

+1

거룩한 쓰레기. 그것을 받아 들일 수 있도록 대답 해주세요! 방금 내 전체 정확도 문제를 해결했습니다! – knight666

답변

35

귀하의 질문을 정확하게 이해한다면, 바로 소수점 이하의 부분을 원하십니까? 실제로 분수 (정수 분자와 분모)가 필요하지 않습니까?

숫자가 있으므로 3.14159라고 말하면서 단지 0.14159으로 끝나기를 원합니다. 우리의 수는 float f;에 저장되어 있다고 가정하면, 우리는이 작업을 수행 할 수 있습니다

f = f-(long)f; 

어느, 우리는 우리의 번호를 삽입 할 경우, 다음과 같이 작동이 무엇

0.14159 = 3.14159 - 3; 

은의 정수 부분을 제거하다 소수 부분 만 떠 다니는 부동 소수점 형. float를 long으로 변환하면 소수 부분이 삭제됩니다. 그런 다음 원래 플로트에서 그 값을 빼면 으로 소수부의 만 남게됩니다. float 유형의 크기 (대부분의 시스템에서 8 바이트)로 인해 여기를 오래 사용해야합니다. 정수 (많은 시스템에서 4 바이트 만)는 float과 동일한 숫자 범위를 포함 할만큼 충분히 클 필요는 없지만 long이어야합니다.

+4

if ... then ... else ... 이것처럼 자주 사용되는 수학 함수에서? 내 캐시, 울다! – knight666

+7

'f'가 음수 일 때 이것은 잘못된 것입니다. (두 개의 음수를 더합니다.)'if'는 전혀 필요 없습니다 :'f = f - (int) f'. 'f'가 음수이면 0으로 반올림 한 음의 정수를 뺍니다. – jamesdlin

+5

또한 float의 정수 부분이 int에 들어 맞다고 가정합니다. – jamesdlin

4

오늘 사용하는 시스템에서 modf가 어떻게 구현되는지 살펴 보시기 바랍니다. uClibc의 버전을 확인하십시오.

http://git.uclibc.org/uClibc/tree/libm/s_modf.c

는 (법적인 이유를 들어, 라이센스 BSD 것으로 나타납니다,하지만 당신은 분명히 확인을 두 배로 싶어) 매크로의 일부는 here을 정의

.

+0

왜 모든 비트 이동이 속도 이득의 많은 부분입니까? 또는 내 작은 int 변환 트릭 내가 놓친 몇 가지 문제가 있습니까? –

+1

@Daniel Bingham : 아마도 후자 일 것입니다. 플로트는 사용중인 플랫폼에서 생각하는 방식으로 인코딩되지 않을 수 있으므로 마스크가 꺼져있을 수 있습니다. @sharth : 귀하의 링크는 일부 매크로에 의존하고 있으며, 매크로를 찾는 데 어려움을 겪고 있습니다. 행운을 시험하고 EXTRACT_WORDS, INSERT_WORDS 및 GET_HIGH_WORD에 대한 정의를 찾을 수 있습니까? – Randolpho

+0

플로팅 Int는 문제가 없습니다. int에 float는 매우 느립니다. – knight666

7

내가 의심으로 modf 사용하지 않는 산술 자체 -이 모든 변화와 마스크,보고 here을 가지고있어. 플랫폼에서 동일한 아이디어를 사용할 수 있습니까?

+0

링크가 깨졌습니다. 업데이트를 시도해주세요. –

+0

구출 방법 기계 : https://web.archive.org/web/20121030234640/http://www.raspberryginger.com/jbailey/minix/html/modf_8c-source.html – Kaganar

2

나는 확신 할 수는 없지만, 당신이 가수를 고려하고 지수를 완전히 잊고 있기 때문에 당신이하는 일이 잘못되었다고 생각합니다.

실제 정수 부분을 찾으려면 지수를 사용하여 가수의 값을 이동해야합니다.

32 비트 부동 소수점의 저장 메커니즘에 대한 설명은 here을 참조하십시오.

0

당신의 방법은 분수 부분에 16 비트가 있다고 가정하고 있습니다 (그리고 마크 랜섬 노트로, 즉 16 비트 씩 이동해야 함, 즉 0x1000을 곱해야 함을 의미합니다). 그건 사실이 아닐 수도 있습니다. 지수는 분수 부분에 몇 비트가 있는지를 결정합니다.

수식에 넣으려면 (x modf 1.0)((x << 16) mod 1<<16) >> 16으로 계산하면됩니다. 지수는 지수에 따라 달라 지므로 하드 코드 된 16입니다. 정확한 교체는 플로트 형식에 따라 다릅니다.

4

상수에 버그가 있습니다. 기본적으로 숫자의 왼쪽 시프트를 16 비트 씩 시도하고, 아래쪽 비트 만 제외하고 16 비트 씩 다시 시프트합니다. 이동은 2의 거듭 제곱과 같지만 2의 거듭 제곱을 사용하지 않고 0xFFFF를 사용합니다.이 값은 1이 아닙니다.이 값을 0x10000으로 바꾸면 수식이 의도 한대로 작동합니다.

1

왜 선 그리기를 위해 부동 소수점으로 이동해야합니까? 당신은 당신의 고정 소수점 버전을 고수하고 정수/고정 소수점 기반의 선 그리기 루틴을 대신 사용할 수 있습니다 - Bresenham이 마음에 듭니다. 이 버전에는 별칭이 없지만 다른 버전이 있다는 것을 알고 있습니다. 어쩌면 당신이 원하는 것처럼

Bresenham's line drawing

+0

안티 알리아싱을 의미합니까? –

+0

앤티 앨리어스 라인의 경우 [Wu Lines] (https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm)을 참조하십시오. – Bim

1

보인다.

float f = something; 
float fractionalPart = f - floor(f); 
+0

음수에는 사용할 수 없습니다. –

+0

'floor' 또한 캐스트보다 느립니다. – aledalgrande

0

하나의 옵션은 fmod(x, 1)을 사용하는 것입니다.

관련 문제