2012-04-13 16 views
8

ARMv5TE用にQt 4.4.3が構築されています。ARMのQtで倍精度からQStringへの変換が正しくない

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

奇妙な出力を得る:私はQStringdoubleを変換しようと、私は適切な文字列を取得するにはどうすればよい

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

を?

答えて

8

これはエンディアンの問題のようですが、プレーンバニラビッグエンディアン対リトルエンディアンの問題ではありません。 ARMは時々、doubleのために通常とは異なるバイト順序を使用します。ジャン・ミシェル・ミューラーによって、ら「浮動小数点演算のハンドブック」:

から... -7.0868766365730135 x 10^-268に最も近い倍精度数は、メモリ内のバイト 11 22 33 44 55 66 77 88の配列によりコードされます(最高 1の低い方から)のx86およびLinux/IA-64プラットフォーム(それらは リトルエンディアンであると言われている)で、ほとんどのPowerPCプラットフォームで88 77 66 55 44 33 22 11によって、(それらはビッグエンディアンであると言われています)。 IA-64、ARM、およびPowerPCのような などのアーキテクチャは、バイエンディアンと言われています。すなわち、 は、 の設定に応じて、リトルエンディアンまたはビッグエンディアンのいずれかになります。

ARMベースのプラットフォームの一部が例外です。伝統的浮動小数点アクセラレータ(FPA)倍精度数は、ビッグエンディアン順に 2つの32ビットワードに分解し、機械の エンディアンに応じて格納されている アーキテクチャを使用している ARMプロセッサすなわちリトルエンディアンであり、これは を意味し、上記の数は配列55 66 77 88 11 22 33 44によってコードされる。 ARMは最近浮動小数点 算術用の新しいアーキテクチャを導入しました。ベクトル浮動小数点(VFP)です。この場合、ワードはプロセッサのネイティブバイトオーダーで に格納されます。

M_PIがどのように見える表現があります、ビッグエンディアンバイト順に見て:

0x400921fb54442d18 

8.6192e+97により近似数が多いように見える表現を持つウィル

0x54442d18400921fb 

よく見ると、2つの32ビットワードは入れ替えられますが、32ビットワード内のバイトオーダーは同じです。つまり、ARMの伝統的なダブルポイント形式は、Qtライブラリを混乱させるようです(またはQtライブラリが誤って構成されています)。

プロセッサが従来の形式を使用していて、QtがVFP形式であることが予想されるかどうか、あるいは逆の場合は分かりません。しかし、それはその2つの状況の1つと考えられます。

この問題を解決する方法も正確にはわかりません。これを正しく処理するために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(""); 

平野リトルエンディアンのマシンが表示されます。

次のスニペットは、少なくともあなたはQtの中で変更する必要があるもの絞り込む役立つ可能性がある、コンパイラが使用しているdoubleのためのどのような形式を教えてくれます。

11 22 33 44 55 66 77 88 

もう少し分析とアップデート:

現時点では、実際のデバッグを行うことができません(現時点で私のワークステーションにアクセスすることさえできません)。http://qt.gitorious.orgで入手可能なQtソースを見てください。

Qtがqlocale.cppのQLocalePrivate::doubleToString()関数を呼び出して、doubleを英数字形式に変換するようです。

QtがQT_QLOCALE_USES_FCVTでコンパイルされている場合、QLocalePrivate::doubleToString()はプラットフォームのfcvt()関数を使用して変換を実行します。 QT_QLOCALE_USES_FCVTではなく、と定義されている場合、QLocalePrivate::doubleToString()は、変換を実行するために_qdtoa()を呼び出して終了します。この関数はdoubleのさまざまなフィールドを直接調べ、doubleが厳密なビッグエンディアン形式またはリトルエンディアン形式(たとえば、getWord0()およびgetWord1()関数を使用してそれぞれdoubleの下位および上位語を取得すると仮定しているように見えます) )。

http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale.cppおよびhttp://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale_tools.cppを参照するか、詳細はファイルのコピーを参照してください。

doubleの従来のARM FPA表現を使用しているプラ​​ットフォーム(全体のシステムがリトルエンディアンであるかどうかにかかわらず、doubleの32ビットの半分がビッグエンディアンの順序で格納されていると仮定します) QT_QLOCALE_USES_FCVTを定義してQtをビルドする必要があります。 Qtをビルドするときは、configureスクリプトに-DQT_QLOCALE_USES_FCVTオプションを渡すだけです。

+0

Qt内で起こっているように思われることについて、私が考えていることと一緒に考えてみましょう。 –

+0

よく研究されています。 +1 –

+0

詳細な対応をありがとうございます!実際問題は '-DQT_QLOCALE_USES_FCVT'オプションがないことでした。再構築後、すべてが正しく機能しました。スニペットを再構築する前に、次の行を印刷しました: '55 66 77 88 11 22 33 44'。 –

4

Qt 4.7.0を使用してx86マシン(Windows XPを実行中)で同じコードを出力すると、適切な出力が得られます。

は、私が問題の原因については、以下の可能性を参照してください。

ARM用にコンパイルするとき多分

  • 何かが間違っていたのQtの新しいバージョンで修正されているいくつかのバグ私は大きな/リトルエンディアン変換の問題であると思われる同様の問題にthis forum postを見つけました。

    これは私がARMで何も経験していないので、この情報を修正する方法はわかりませんが、この情報はとにかく役立ちます。

  • +0

    これはおそらく問題です。間違ったエンディアンや何かのためにコンパイルされたQt。 – Mat

    関連する問題