2008-10-09 76 views
20

En C++, ¿cuál es la forma genérica de convertir cualquier valor de coma flotante (flotante) a fixed point (int, 16:16 o 24: 8)?Conversión de punto flotante a punto fijo

EDIT: Para aclarar, los valores de punto fijo tienen dos partes: una parte entera y una parte fraccionaria. La parte entera se puede representar mediante un tipo de datos entero con signo o sin signo. La parte fraccionaria se representa mediante un tipo de datos entero de datos sin signo.

Hagamos una analogía con el dinero en aras de la claridad. La parte fraccionaria puede representar centavos, una parte fraccionaria de un dólar. El rango del tipo de datos 'centavos' sería de 0 a 99. Si se utilizara un entero sin signo de 8 bits para matemática de punto fijo, entonces la parte fraccional se dividiría en 256 partes divisibles uniformemente.

Espero que aclare las cosas.

+0

Si está en Visual C++, experimente con el interruptor '/ fp: fast' incluso antes de pensar en refactorizar todo su punto flotante a punto fijo. Este conmutador de modelo de coma flotante permite optimizaciones que pueden permitir que el punto flotante supere fácilmente el punto fijo de velocidad. Definitivamente una característica poco apreciada. –

Respuesta

26

Aquí van:

// A signed fixed-point 16:16 class 
class FixedPoint_16_16 
{ 
    short   intPart; 
    unsigned short fracPart; 

public: 
    FixedPoint_16_16(double d) 
    { 
     *this = d; // calls operator= 
    } 

    FixedPoint_16_16& operator=(double d) 
    { 
     intPart = static_cast<short>(d); 
     fracPart = static_cast<unsigned short> 
        (numeric_limits<unsigned short> + 1.0)*d); 
     return *this; 
    } 

    // Other operators can be defined here 
}; 

EDIT: Aquí hay una clase más general basado en anothercommon manera de lidiar con los números de punto fijo (y que KPexEA señaló):

template <class BaseType, size_t FracDigits> 
class fixed_point 
{ 
    const static BaseType factor = 1 << FracDigits; 

    BaseType data; 

public: 
    fixed_point(double d) 
    { 
     *this = d; // calls operator= 
    } 

    fixed_point& operator=(double d) 
    { 
     data = static_cast<BaseType>(d*factor); 
     return *this; 
    } 

    BaseType raw_data() const 
    { 
     return data; 
    } 

    // Other operators can be defined here 
}; 


fixed_point<int, 8> fp1;   // Will be signed 24:8 (if int is 32-bits) 
fixed_point<unsigned int, 16> fp1; // Will be unsigned 16:16 (if int is 32-bits) 
+3

Se trata más de cómo diseccionar un número de punto flotante en lugar de convertirlo en una representación de punto fijo. – Trap

+1

numeric_limits ** :: ???? ** Creo que falta una parte. – Ant

+3

¿Qué es "DataType" aquí sin embargo? ¿Dónde está eso definido? – dicroce

0

Esto está bien para la conversión de punto flotante a entero, pero el OP también quería fixed point.

Ahora cómo lo harías en C++, no sé (C++ no es algo en lo que pueda pensar fácilmente). Tal vez intente un enfoque de entero escalado, es decir, utilice un entero de 32 o 64 bits y asigne mediante programación los últimos, digamos, 6 dígitos a lo que está en el lado derecho del punto decimal.

18

Un lanzamiento de flotante a entero arrojará la porción fraccional, por lo que si desea mantener esa fracción como punto fijo, simplemente multiplique el flotador antes de lanzarlo. El siguiente código no verificará si hay desbordamiento.

Si desea 16:16

double f = 1.2345; 
int n; 

n=(int)(f*65536); 

si quieres 24: 8

double f = 1.2345; 
int n; 

n=(int)(f*256); 
-4

No hay ninguna construido en apoyo en C++ para los números de punto fijo. Su mejor opción sería escribir una clase contenedora 'FixedInt' que tome dobles y los convierta.

En cuanto a un método genérico para convertir ... la parte int es bastante fácil, simplemente tome la parte entera del valor y guárdela en los bits superiores ... la parte decimal sería algo así como:

for (int i = 1; i <= precision; i++) 
{ 
    if (decimal_part > 1.f/(float)(i + 1) 
    { 
     decimal_part -= 1.f/(float)(i + 1); 
     fixint_value |= (1 << precision - i); 
    } 
} 

aunque esto es probable que contenga errores todavía

6

**** ** Edición: Mi primer comentario se aplica a editar antes de Kevin, pero lo dejaré aquí para la posteridad. ¡Las respuestas cambian tan rápido aquí a veces!

El problema con el enfoque de Kevin es que con el Punto fijo normalmente se empaqueta en un tamaño de palabra garantizado (normalmente, 32bits). Declarar las dos partes por separado te deja al capricho del empaque de la estructura de tu compilador. Sí, podría forzarlo, pero no sirve para nada más que la representación de 16:16.

KPexEA está más cerca de la marca al incluir todo en int, aunque usaría "signed long" para tratar de ser explícito en 32bits. Luego puede usar su enfoque para generar el valor del punto fijo, y el corte de bits extrae las partes componentes nuevamente. Su sugerencia también cubre el caso 24: 8.

(Y todos los demás que sugiere simplemente static_cast ..... ¿qué estabas pensando;?))

1

me dio la respuesta a la persona que escribió la mejor respuesta, pero realmente utilizado un código de preguntas relacionadas que apunta a here.

Utilizaba plantillas y era fácil deshacerse de las dependencias del boost lib.

+0

el enlace está roto (404) –

+0

Sería mejor vincular la pregunta relacionada la próxima vez. Como Iván sobre mí ha dejado claro al comentar, las preguntas siguen siendo relevantes. Esta respuesta ya no proporciona ninguna información. –

Cuestiones relacionadas