2012-04-13 29 views
8

Tengo Qt 4.4.3 construido para ARMv5TE. Trato de convertir un double a un QString:Conversión incorrecta de doble a QString en Qt en ARM

#include <QtCore/QtCore> 
#include <cmath> 

int main(int argc, char** argv) 
{ 
    const double pi = M_PI; 
    qDebug() << "Pi is : " << pi << "\n but pi is : " << QString::number(pi, 'f', 6); 
    printf("printf: %f\n",pi); 

    return 0; 
} 

pero llegar extraña salida:

Pi is : 8.6192e+97 
but pi is : "86191995128153827662389718947289094511677209256133209964237318700300913082475855805240843511529472.0000000000000000" 
printf: 3.141593 

¿Cómo consigo la cadena adecuada?

Respuesta

8

Esto parece ser una especie de problema de endianess, pero no su problema endémico de vagabundo versus little-endian. ARM a veces usa un orden inusual de bytes para double. De "Manual de aritmética de punto flotante", de Jean-Michel Muller, et al .:

... el número de doble precisión que está más cerca -7.0868766365730135 x 10^-268 es codificada por la secuencia de bytes en la memoria 11 22 33 44 55 66 77 88 (desde el más bajo al más alto uno) en plataformas x86 y/IA-64 Linux (que se dice que son ascendente hacia la izquierda) y por 88 77 66 55 44 33 22 11 en la mayoría de las plataformas PowerPC (que se dice que son bigEndian) Se dice que algunas arquitecturas, como como IA-64, ARM y PowerPC, son bi-endian. es decir, pueden ser little-endian o big-endian dependiendo de su configuración .

Existe una excepción: algunas plataformas basadas en ARM. procesadores ARM han utilizado tradicionalmente el acelerador de punto flotante (FPA) arquitectura, donde los números de doble precisión se descomponen en dos palabras de 32 bits en el orden-big endian y se almacenan de acuerdo con la endianess de la máquina , es decir, little-endian en general, lo que significa que el número anterior está codificado por la secuencia 55 66 77 88 11 22 33 44. ARM ha introducido recientemente una nueva arquitectura para coma flotante aritmética: vector punto flotante (VFP), donde las palabras se almacenan en el orden de bytes nativo del procesador.

Cuando se mira en un orden big-endian byte, M_PI tendrá una representación que se parece a:

0x400921fb54442d18 

El gran número aproximado por 8.6192e+97 Wil tiene una representación que se parece a:

0x54442d18400921fb 

Si observa detenidamente, las dos palabras de 32 bits se intercambian, pero el orden de bytes dentro de las palabras de 32 bits es el mismo. Aparentemente, el formato de doble punto "tradicional" de ARM parece confundir la biblioteca de Qt (o la biblioteca de Qt está mal configurada).

No estoy seguro de si el procesador está utilizando el formato tradicional y Qt espera que esté en formato VFP, o si las cosas son al revés. Pero parece ser una de esas dos situaciones.

Tampoco estoy seguro exactamente de cómo solucionar el problema - Supongo que hay alguna opción para compilar Qt para manejar esto correctamente.

el siguiente fragmento de por lo menos le qué formato de double el compilador está utilizando decir, que puede ayudar a reducir lo que debe cambiar en Qt:

unsigned char* b; 
unsigned char* e; 

double x = -7.0868766365730135e-268; 

b = (unsigned char*) &x; 
e = b + sizeof(x); 

for (; b != e; ++b) { 
    printf("%02x ", *b); 
} 

    puts(""); 

Una simple máquina ascendente hacia la izquierda mostrará:

11 22 33 44 55 66 77 88 

actualización con un poco más de análisis:

Por el momento, no puedo realizar ninguna depuración real de esto (ni siquiera tengo acceso a mi estación de trabajo en este momento), pero al mirar la fuente de Qt disponible en http://qt.gitorious.org aquí hay un análisis adicional:

Parece que Qt llama a la función QLocalePrivate::doubleToString() en qlocale.cpp para convertir un double a un formato alfanumérico.

Si se compila Qt con QT_QLOCALE_USES_FCVT definido, entonces QLocalePrivate::doubleToString() utilizará la función fcvt() de la plataforma para realizar la conversión. Si QT_QLOCALE_USES_FCVT es no definido, entonces QLocalePrivate::doubleToString() termina llamando al _qdtoa() para realizar la conversión. Esa función examina los diversos campos del double directamente y parece suponer que el double está en una forma estricta big-endian o little-endian (por ejemplo, usando las funciones getWord0() y getWord1() para obtener la palabra baja y alta del double respectivamente)

Consulte http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale.cpp y http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale_tools.cpp o su propia copia de los archivos para obtener más información.

Suponiendo que su plataforma está utilizando la representación tradicional ARM FPA para double (donde se almacenan las mitades de 32 bits de la double con el fin bigEndian independientemente de si el sistema global es ascendente hacia la izquierda), creo que' Necesitaré construir Qt con el QT_QLOCALE_USES_FCVT definido. Creo que todo lo que tendrá que hacer es pasar la opción -DQT_QLOCALE_USES_FCVT al script de configuración al compilar Qt.

+0

He agregado un poco más sobre lo que parece estar sucediendo dentro de Qt junto con lo que creo que es una posible solución. –

+0

bien investigado. +1 –

+0

¡Gracias por la respuesta detallada! En realidad, el problema fue la falta de opciones '-DQT_QLOCALE_USES_FCVT'. Después de reconstruir todo funcionó correctamente. Antes de reconstruir su fragmento, imprima la siguiente línea: '55 66 77 88 11 22 33 44'. –

4

El mismo código produce la salida adecuada en una máquina x86 (que ejecuta Windows XP) con Qt 4.7.0.

veo las siguientes posibilidades para la fuente del problema:

  • algunos errores que se puede que fija en una nueva versión de Qt
  • Algo salió mal al compilar para ARM

Encontré this forum post en un problema similar que supone que podría ser un problema de conversión big/little-endian.

No puedo decir cómo solucionar esto, ya que no tengo experiencia con ARM, pero quizás esta información te ayude de todos modos.

+0

Ese es probablemente el problema.Qt compilado por la endianidad incorrecta o algo por el estilo. – Mat

Cuestiones relacionadas