Estoy escribiendo un código para un sistema integrado (MSP430) sin soporte de punto flotante de hardware. Desafortunadamente, tendré que trabajar con fracciones en mi código mientras mido el rango, y un sensor de corto alcance con una precisión de 1 m no es un sensor muy bueno.
Puedo hacer todo lo que necesito de las matemáticas en números enteros, pero al final hay dos valores en los que definitivamente necesitaré tener fracciones; alcance y velocidad. El rango será un valor entre 2-500 (cm), mientras que la velocidad no debe ser superior a -10 a 10 (ms^-1). No estoy seguro de cómo representarlos sin valores de coma flotante, si es posible. Lo mejor sería una forma sencilla de redondear las fracciones hacia arriba o hacia abajo.
Algunos código de muestra que tengo:
voltage_difference_new = ((memval3_new - memval4_new)*3.3/4096); donde memval3_new y memval4_new son enteros, pero voltage_difference_new es un valor flotante.
Por favor, hágamelo saber si se necesita más información. O si hay una solución increíblemente fácil.
Más bien ha respondido a su propia pregunta con la declaración:
El rango será un valor entre 2-500 (cm),
Trabaje en centímetros (o incluso milímetros) en lugar de unidades de metro.
Dicho esto, no necesita hardware de punto flotante para hacer matemáticas de punto flotante; el compilador admitirá punto flotante "suave" y generará el código para realizar operaciones de punto flotante; será más lento que el punto flotante de hardware o las operaciones de enteros, pero eso puede no ser un problema en su aplicación.
No obstante, hay muchas razones para evitar el punto flotante incluso con soporte de hardware y no parece que su caso para FP sea particularmente convincente, pero es difícil saberlo sin ver su código y un ejemplo específico. En 32 años de desarrollo de sistemas integrados, rara vez he recurrido a FP, incluso para el procesamiento de señales trigonométricas, logarítmicas, sqrt y digitales.
Un método general es utilizar una presentación de punto fijo . Mi sugerencia anterior de usar centímetros es un ejemplo de punto fijo decimal , pero para una mayor eficiencia debe usar punto fijo binario . Por ejemplo, puede representar la distancia en unidades de 1/1024 metros (dando una precisión de > 1 mm). Debido a que el punto fijo es binario, todo el cambio de escala necesario se puede realizar con turnos en lugar de operaciones más costosas de multiplicación/división.
Por ejemplo, suponga que tiene un sensor de 8 bits que genera una salida lineal de 0 a 255 correspondiente a una distancia real de 0 a 0,5 metros.
#define Q10_SHIFT = 10 ; // 10 bits fractional (1/1024) typedef int q10_t ; #define ONE_METRE = (1 << Q10_SHIFT) #define SENSOR_MAX = 255 #define RANGE_MAX = (ONE_METRE/2) q10_t distance = read_sensor() * RANGE_MAX / SENSOR_MAX ; distance está en representación de punto fijo Q10. Realizar sumas y restas en tales es aritmética normal de enteros, multiplicar y dividir requieren escala:
int q10_add( q10_t a, q10_t b ) { return a + b ; } int q10_sub( q10_t a, q10_t b ) { return a - b ; } int q10_mul( q10_t a, q10_t b ) { return (a * b) >> Q10_SHIFT ; } int q10_div( q10_t a, q10_t b ) { return (a << Q10_SHIFT) / b ; } Por supuesto, es posible que desee poder mezclar tipos y, por ejemplo, multiplicar un q10_t por un int ; proporcionar una biblioteca completa para puntos fijos puede volverse complejo. Personalmente, para eso, uso C ++ donde tiene clases, sobrecarga de funciones y sobrecarga de operadores para admitir un código más natural. Pero a menos que su código tenga una gran cantidad de matemáticas generales de punto fijo, puede ser más simple codificar operaciones específicas de punto fijo ad-hoc.
Para tomar el único ejemplo que ha proporcionado:
double voltage_difference_new = ((memval3_new - memval4_new)*3.3/4096);El punto flotante allí se elimina trivialmente usando milivoltios:
int voltage_difference_new_mv = ((memval3_new - memval4_new) * 3300) /4096 ;El problema entonces quizás se convierta en uno de presentación . Por ejemplo si tiene que presentar o reportar el valor en voltios a un usuario. En ese caso:
int volt_fract = abs(voltage_difference_new_mv % 1000) ; int volt_whole = voltage_difference_new_mv / 1000 ; printf( "%d.%04d", volt_whole, volt_fract ) ;