2012-04-13 26 views
8

Tôi có Qt 4.4.3 được tạo cho ARMv5TE. Tôi cố gắng để chuyển đổi một double đến một QString:Sai chuyển đổi từ gấp đôi thành QString trong Qt trên 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; 
} 

nhưng nhận được kết quả kỳ lạ:

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

Làm thế nào để tôi có được chuỗi thích hợp?

Trả lời

8

Điều này có vẻ là một vấn đề về cuối cùng, nhưng không phải là vấn đề lớn về nội dung của bạn và vấn đề nhỏ bé. ARM đôi khi sử dụng một thứ tự byte bất thường cho double. Từ "Sổ tay của Floating-Point Arithmetic" của Jean-Michel Muller, et al .:

... số lượng tăng gấp đôi độ chính xác đó là gần nhất với -7.0868766365730135 x 10^-268 được mã hóa bởi một chuỗi các byte 11 22 33 44 55 66 77 88 trong bộ nhớ (từ thấp nhất đến cao nhất một) trên x86 và Linux/IA-64 nền tảng (họ được cho là ít về cuối nhỏ) và bởi 88 77 66 55 44 33 22 11 trên hầu hết các nền tảng PowerPC (họ được cho là lớn về cuối nhỏ). Một số kiến ​​trúc, chẳng hạn như như IA-64, ARM và PowerPC được gọi là bi-endian. tức là, họ có thể hoặc là người nhỏ tuổi hoặc người lớn tuổi tùy thuộc vào cấu hình của họ.

Có một ngoại lệ: một số nền tảng dựa trên ARM. Bộ vi xử lý ARM theo truyền thống đã sử dụng máy gia tốc điểm nổi (FPA) , trong đó các số chính xác kép được phân tách thành hai từ 32 bit theo thứ tự lớn và được lưu trữ theo số cuối cùng của máy , tức là, người nhỏ tuổi nói chung, có nghĩa là rằng số trên được mã hóa theo trình tự 55 66 77 88 11 22 33 44. ARM gần đây đã giới thiệu một kiến ​​trúc mới cho dấu phẩy động số học: vectơ dấu phẩy động (VFP), trong đó các từ được lưu trữ theo thứ tự byte gốc của bộ xử lý.

Khi nhìn theo một thứ tự byte lớn về cuối nhỏ, M_PI sẽ có một đại diện trông giống như:

0x400921fb54442d18 

Số lớn xấp xỉ bằng 8.6192e+97 wil có một đại diện trông giống như:

0x54442d18400921fb 

Nếu bạn nhìn kỹ, hai từ 32 bit được hoán đổi, nhưng thứ tự byte trong các từ 32 bit là giống nhau. Vì vậy, rõ ràng, định dạng điểm kép 'ARM' truyền thống dường như gây nhầm lẫn cho thư viện Qt (hoặc thư viện Qt bị định cấu hình sai).

Tôi không chắc liệu bộ xử lý có đang sử dụng định dạng truyền thống hay không và Qt dự kiến ​​nó sẽ ở định dạng VFP, hoặc nếu mọi thứ theo cách khác. Nhưng nó có vẻ là một trong hai tình huống đó.

Tôi cũng không chắc chắn chính xác cách khắc phục sự cố - tôi đoán có một số tùy chọn để xây dựng Qt để xử lý chính xác.

đoạn sau đây sẽ ít nhất là cho bạn biết định dạng cho double trình biên dịch được sử dụng, có thể giúp bạn thu hẹp những gì cần phải thay đổi trong 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(""); 

Một đồng bằng máy ít về cuối nhỏ sẽ hiển thị:

11 22 33 44 55 66 77 88 

cập nhật với phân tích thêm một chút:

Hiện tại, tôi không thể thực hiện bất kỳ việc gỡ lỗi thực sự nào (tôi thậm chí không có quyền truy cập vào máy trạm của mình), nhưng bằng cách xem nguồn Qt có sẵn trên http://qt.gitorious.org đây là phân tích bổ sung:

Dường như các cuộc gọi Qt đến hàm QLocalePrivate::doubleToString() trong qlocale.cpp để chuyển đổi một số double thành dạng chữ và số.

Nếu Qt được biên dịch với QT_QLOCALE_USES_FCVT được xác định, thì QLocalePrivate::doubleToString() sẽ sử dụng chức năng fcvt() của nền tảng này để thực hiện chuyển đổi. Nếu QT_QLOCALE_USES_FCVTkhông phải được xác định, thì QLocalePrivate::doubleToString() kết thúc bằng cách gọi _qdtoa() để thực hiện chuyển đổi. Hàm đó kiểm tra các trường khác nhau của số double trực tiếp và dường như giả định rằng double ở dạng nghiêm ngặt hoặc nhỏ gọn (ví dụ: sử dụng các hàm getWord0()getWord1() để nhận từ thấp và cao tương ứng của double tương ứng).

Xem http://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale.cpphttp://qt.gitorious.org/qt/qt/blobs/HEAD/src/corelib/tools/qlocale_tools.cpp hoặc bản sao tệp của riêng bạn để biết chi tiết.

Giả sử rằng nền tảng của bạn đang sử dụng biểu diễn FPA ARM truyền thống cho double (trong đó các nửa 32 bit của double được lưu trữ theo thứ tự lớn bất kể hệ thống tổng thể có nhỏ gọn), tôi nghĩ bạn ' sẽ cần phải xây dựng Qt với số QT_QLOCALE_USES_FCVT được xác định. Tôi tin rằng tất cả những gì bạn cần làm là vượt qua tùy chọn -DQT_QLOCALE_USES_FCVT cho kịch bản cấu hình khi xây dựng Qt.

+0

Tôi đã thêm một chút về những gì dường như đang xảy ra bên trong Qt cùng với những gì tôi nghĩ là một giải pháp có thể. –

+0

Được nghiên cứu kỹ. +1 –

+0

Cảm ơn bạn đã trả lời chi tiết! Trên thực tế vấn đề là thiếu các tùy chọn '-DQT_QLOCALE_USES_FCVT'. Sau khi xây dựng lại mọi thứ đã hoạt động chính xác. Trước khi xây dựng lại đoạn trích của bạn, hãy in dòng sau: '55 66 77 88 11 22 33 44'. –

4

Cùng một mã tạo ra đầu ra phù hợp trên máy x86 (chạy Windows XP) với Qt 4.7.0.

tôi thấy các khả năng sau đây để biết nguồn gốc của vấn đề:

  • Một số lỗi mà có thể cố định trong một phiên bản mới hơn của Qt
  • Có lỗi khi biên dịch cho ARM

Tôi tìm thấy this forum post về một vấn đề tương tự mà cho rằng nó có thể là một vấn đề chuyển đổi lớn/nhỏ-endian.

Tôi không thể biết cách khắc phục điều này vì tôi không có kinh nghiệm với ARM nhưng có lẽ thông tin này sẽ giúp bạn.

+0

Đó rất có thể là vấn đề.Qt được biên dịch cho sai lệch về tính xác thực hoặc điều gì đó có hiệu lực. – Mat

Các vấn đề liên quan