2011-04-02 15 views
7

¿Cómo puedo imprimir (es decir, hacia la salida estándar) un flotador en C sin haber que ser promovido a un doble cuando se pasa a printf?Impresión de un flotador en C evitando al mismo tiempo la promoción de parámetros variadic duplicar

El tema aquí es que las funciones variadic en C promover todas parámetro flotador-doble, que incurre en dos conversiones innecesarias. Por ejemplo, si se activa la -Wdouble-promoción en GCC y compilar

float f = 0.f; 
printf("%f", f); 

obtendrá

warning: implicit conversion from 'float' to 'double' when passing argument to function 

que tienen relativamente poca potencia de procesamiento para jugar con (a 72 MHz ARM Cortex-M3), y estoy definitivamente obstaculizando la salida ASCII de datos de punto flotante. Como la arquitectura carece de una FPU de hardware para empezar, tener que convertir entre precisión simple y doble no ayuda.

¿Hay alguna forma de imprimir un flotador de manera más eficiente en C recta?

+1

Si alguien viene a través de esto, acabé base64'ing mis datos, y se decodifica/formateado/todo bastante impresa en un host también machine.I consideró Boost :: Karma, pero eso habría requerido C++ y había muchas posibilidades de que no me salve ningún tamaño de código. –

Respuesta

7

Evitar la promoción no te salvará nada, ya que el interior double (o más probablemente long double) aritmética printf llevará a cabo va a consumir al menos 1000 veces mayor cantidad de tiempo. La impresión precisa de valores de punto flotante es no es fácil.

Sin embargo, si a usted no le importa la precisión, y solo necesita imprimir valores aproximados rápidamente, puede enrollar su propio bucle para hacer la impresión. Siempre que sus valores no sean demasiado grandes para caber en un tipo entero, primero convierta e imprima la parte no fraccionaria como un entero, luego reste eso y bucle multiplicándolo por 10 y quitando la parte entera para imprimir la parte fraccionaria un dígito a la vez (búfer en una cadena para un mejor rendimiento).

O usted podría hacer algo como:

printf("%d.%.6d", (int)x, (int)((x-(int)x)*1000000)); 
+0

Me di cuenta de que la mayoría de los flotadores que necesitaba para imprimir estaban en el rango de [0, 1], así que pude escalarlos y convertirlos en enteros para imprimirlos. Esto mejoró mucho el rendimiento. –

5

Desafortunadamente, printf no tiene soporte para la entrega del flotador simple: s.

Esto significa que tendría que escribir su propia función de impresión. Si no necesita todo el poder expresivo de printf, puede convertir fácilmente su valor de coma flotante en una parte integral y una parte que represente un número de decimales, e imprimir ambos usando números enteros.

Si, por otro lado, simplemente desea deshacerse de la advertencia, puede convertir explícitamente el float en double.

2

Creo que eso no importa - printf ya es una cosa tan desagradable que consume tiempo, que esa conversión no debería importar. El tiempo de conversión de float a double debería ser mucho menor que la conversión de cualquier número a ascii (debería/podría perfilar su código para obtener una respuesta definitiva). La única solución restante sería escribir una rutina de salida personalizada propia que convierta float-> ascii y luego use puts (o similar).

+0

No estoy de acuerdo. La parte más cara de las conversiones de punto de fuga a ascii son las divisiones por 10. Y esas son más rápidas si se trabaja en flotación y no en doble. –

+0

@edgar: Por supuesto, hay operaciones de puntos flotantes que cuestan más que el doble que los flotadores. Pero la implementación de div por 10 depende de la implementación de la lib. También puedes trabajar en los bits de mantisa con operaciones enteras para obtener los dígitos. Eso depende en gran medida de la libc utilizada (que para la integración generalmente no es una implementación completa). Es por eso que dije que necesita un perfil para una respuesta definitiva. Y la única forma de evitarlo es escribir su propia función. – flolo

0
  • Primera aproximación: Use ftoa en lugar de printf. Perfil.

  • Para una mayor flexibilidad de salida, entraría en el código fuente del stdlib de su compilador, tal vez alguna derivada de gcc, busque la implementación de printf y copie el código correspondiente para conversión doble> ascii. Reescríbalo para flotar -> ascii.

  • A continuación, cambie manualmente uno o dos sitios de llamada pormenorizados a su nueva versión (no variada) y perfílla.

  • Si resuelve su problema, podría pensar en reescribir su propio printf, basado en la versión de stdlib, por el cual en lugar de flotar, pase float *. Eso debería deshacerse de la promoción automática.

Cuestiones relacionadas