truncar sacar quitar parte numero fraccionaria float extraer entera decimales como c++ c math bit-manipulation

c++ - sacar - Obtención de la parte fraccionaria de un flotador sin utilizar modf()



parte fraccionaria en c (9)

¿Por qué ir a punto flotante para su dibujo lineal? Usted podría simplemente adherirse a su versión de punto fijo y utilizar una rutina de dibujo de línea basada en punto fijo / entero: Bresenham viene a la mente. Si bien esta versión no tiene alias, sé que hay otras que sí lo son.

Dibujo de líneas de Bresenham

Estoy desarrollando una plataforma sin una biblioteca de matemáticas, por lo que necesito crear mis propias herramientas. Mi forma actual de obtener la fracción es convertir el flotador en punto fijo (multiplicar con (flotar) 0xFFFF, convertir en int), obtener solo la parte inferior (máscara con 0xFFFF) y volver a convertirla en un flotador.

Sin embargo, la imprecisión me está matando. Estoy usando las funciones Frac () e InvFrac () para dibujar una línea con suavizado. Usando modf obtengo una línea perfectamente suave. Con mi propio método, los píxeles comienzan a saltar debido a la pérdida de precisión.

Este es mi código:

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; }

¡Gracias por adelantado!


Como sospechaba, modf no usa aritmética per se , son todos los cambios y máscaras, eche un vistazo here . ¿No puedes usar las mismas ideas en tu plataforma?


Hay un error en tus constantes. Básicamente, está intentando hacer un desplazamiento a la izquierda del número por 16 bits, enmascarar todo menos los bits inferiores, y luego girar a la derecha en 16 bits nuevamente. Cambiar es lo mismo que multiplicar por una potencia de 2, pero no estás usando una potencia de 2; estás usando 0xFFFF, que está desactivado por 1. Reemplazar esto con 0x10000 hará que la fórmula funcione como se esperaba.


No estoy completamente seguro, pero creo que lo que estás haciendo está mal, ya que solo estás considerando la mantisa y olvidaste completamente el exponente.

Debe usar el exponente para cambiar el valor de la mantisa para encontrar la parte entera real.

Para obtener una descripción del mecanismo de almacenamiento de flotadores de 32 bits, eche un vistazo here .


Parece que tal vez quieres esto.

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


Recomendaría echar un vistazo a cómo se implementa modf en los sistemas que usa hoy. Echa un vistazo a la versión de uClibc.

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

(Por razones legales, parece que tiene licencia BSD, pero obviamente querrá volver a verificar)

Algunas de las macros se definen here .


Si entiendo tu pregunta correctamente, solo quieres la parte después del decimal ¿verdad? ¿No lo necesitas realmente en una fracción (numerador entero y denominador)?

Así que tenemos un número, digamos 3.14159 y queremos terminar con solo 0.14159 . Suponiendo que nuestro número se almacena en float f; , Podemos hacer esto:

f = f-(long)f;

Lo cual, si insertamos nuestro número, funciona así:

0.14159 = 3.14159 - 3;

Lo que esto hace es eliminar la porción entera del flotador dejando solo la porción decimal. Cuando conviertes el flotador a un largo, cae la parte decimal. Luego, cuando lo restas de tu flotador original, solo te queda la parte decimal. Necesitamos usar mucho tiempo aquí debido al tamaño del tipo float (8 bytes en la mayoría de los sistemas). Un número entero (solo 4 bytes en muchos sistemas) no es necesariamente lo suficientemente grande como para cubrir el mismo rango de números que un float , pero debe ser un long .


Su método supone que hay 16 bits en la parte fraccionaria (y como señala Mark Ransom, eso significa que debe desplazarse por 16 bits, es decir, multiplicar por 0x1000). Eso podría no ser cierto. El exponente es lo que determina cuántos bits hay en la parte fraccionaria.

Para poner esto en una fórmula, su método funciona calculando (x modf 1.0) como ((x << 16) mod 1<<16) >> 16 , y es ese 16 codificado que debe depender del exponente: el reemplazo exacto Depende de su formato flotante.


Una opción es usar fmod(x, 1) .