programing

modf()를 사용하지 않고 플로트의 분수 부분 가져오기

powerit 2023. 9. 25. 23:08
반응형

modf()를 사용하지 않고 플로트의 분수 부분 가져오기

저는 수학 도서관이 없는 플랫폼을 위해 개발 중이기 때문에 저만의 도구를 만들어야 합니다.나의 현재 분수를 얻는 방법은 플로트를 고정 지점으로 변환하고 (플로트)0xFFFF, 캐스트를 int로 곱하여), 하단 부분만 얻고 (0xFFFF로 마스크) 다시 플로트로 변환하는 것입니다.

하지만 그 부정확함 때문에 죽을 것 같아요.저는 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;
}

미리 감사드립니다!

당신의 질문을 제대로 이해했다면 소수점 뒤에 있는 부분만 원하십니까?실제로 분수(정수와 분모)로 필요한 것은 없습니까?

그래서 번호가 좀 있어요, 예를 들어보세요.3.14159그리고 우리는 마지막으로 단지0.14159. 우리의 번호가 저장되어 있다고 가정할 때float f;, 우리는 할 수 있습니다.

f = f-(long)f;

번호를 입력하면 다음과 같이 작동합니다.

0.14159 = 3.14159 - 3;

이렇게 하면 소수 부분만 남기고 플로트의 정수 부분을 제거할 수 있습니다.플로트를 롱으로 변환하면 십진법 부분이 떨어집니다.그러면 원래 부동액에서 그것을 빼면 소수점만 남게 됩니다.여기는 크기 때문에 긴 시간을 써야 합니다.float입력합니다(대부분의 시스템에서 8바이트).정수(많은 시스템에서 4바이트만 해당)는 a와 같은 범위의 숫자를 포함할 만큼 충분히 크지 않습니다.float, 그러나.long그래야 한다.

내가 예상했던 대로,modf산술적으로 계산할 필요는 없습니다. 모두 교대와 마스크입니다. 여기를 보세요.플랫폼에서 동일한 아이디어를 사용할 수는 없습니까?

저는 오늘날 당신이 사용하는 시스템에서 modf가 어떻게 구현되는지 살펴보는 것을 추천합니다.uClibc의 버전을 확인해보세요.

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

(법적인 이유로 BSD 허가를 받은 것으로 보이지만, 분명 다시 확인해보시길 바랍니다.)

매크로 중 일부는 여기에 정의되어 있습니다.

상수에 버그가 있습니다.기본적으로 숫자를 16비트씩 왼쪽으로 이동시키고, 하위 비트를 제외한 모든 것을 가리고, 다시 16비트씩 오른쪽으로 이동하려고 합니다.시프트는 2의 거듭제곱을 곱하는 것과 동일하지만 2의 거듭제곱을 사용하는 것이 아닙니다. 즉, 0xFFFF를 사용하는 것이며, 이 값은 1만큼 떨어집니다.이를 0x10000으로 대체하면 공식이 의도한 대로 작동합니다.

확실하지는 않지만, 당신은 가수만 생각하고 지수를 완전히 잊어버리기 때문에 당신이 하는 일이 잘못되었다고 생각합니다.

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

32비트 플로트의 저장 메커니즘에 대한 설명은 여기를 참조하십시오.

왜 선 그리기를 위해 부동 소수점에 가십니까?당신은 그저 당신의 고정점 버전을 고수하고 대신 정수/고정점 기반의 선 그리기 루틴을 사용할 수 있습니다 - 브레센햄을 떠올립니다.이 버전은 별칭은 아니지만 다른 버전도 있는 것으로 알고 있습니다.

브레센햄의 선 그리기

당신이 이걸 원하는 것 같네요.

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

당신의 방법은 부분 부분에 16비트가 있다고 가정하는 것입니다. (그리고 Mark Ransom이 언급한 것처럼, 당신은 16비트만큼 이동해야 한다는 것을 의미합니다. 즉, 0x1000을 곱하는 것입니다.)그건 사실이 아닐 수도 있습니다.지수는 분수 부분의 비트 수를 결정합니다.

이것을 공식으로 표현하자면, 당신의 방법은 다음을 계산함으로써 효과가 있습니다.(x modf 1.0)~하듯이((x << 16) mod 1<<16) >> 16된 16입니다. 는 플로트 달라집니다. 입니다 16 정확한 대체는 플로트 형식에 따라 달라집니다.

double frac(double val)
{
    return val - trunc(val);
}

// frac(1.0) = 1.0 - 1.0 = 0.0 correct
// frac(-1.0) = -1.0 - -1.0 = 0.0 correct
// frac(1.4) = 1.4 - 1.0 = 0.4 correct
// frac(-1.4) = -1.4 - -1.0 = -0.4 correct

단순하며 -ve 및 +ve에 적합합니다.

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

언급URL : https://stackoverflow.com/questions/2594913/getting-the-fractional-part-of-a-float-without-using-modf

반응형