2011-01-18 13 views
6

Điều gì sẽ là một cách hiệu quả, di động để chuyển đổi một chữ ký ngắn thành ký tự * (tức là chuyển đổi 25 thành '25').Hiệu quả chuyển đổi một chữ ký ngắn thành một ký tự *

Tôi muốn tránh những thứ như nhận chuỗi (std :: string) liên quan. Hiệu suất là quan trọng trong trường hợp này kể từ khi chuyển đổi này sẽ cần phải xảy ra một cách nhanh chóng và thường xuyên.

Tôi đã xem xét những thứ như sử dụng sprintf nhưng muốn khám phá bất kỳ và tất cả ý tưởng.

+3

Các bạn đã thử sử dụng ' sprintf'/'snprintf'? Đã làm như vậy, có bạn đã lược tả mã và xác định rằng đây là điểm phát sóng hiệu suất không? –

+15

Các bảng ở dưới cùng của bài viết được liên kết dưới đây minh họa rõ ràng nơi triển khai stdlib cư trú ở mức độ hiệu quả và tối ưu của việc triển khai có liên quan: http://www.codeproject.com/KB/recipes/Tokenizer.aspx –

Trả lời

6

Trước hết, hãy làm đúng, sau đó thực hiện nhanh - chỉ tối ưu hóa nếu bạn có thể thấy chắc chắn rằng một đoạn mã không hoạt động.

snprintf() vào bộ đệm sẽ thực hiện những gì bạn muốn. Đây có phải là giải pháp nhanh nhất có thể không? Không có gì. Nhưng nó là một trong những đơn giản nhất, và nó sẽ đủ để có được mã của bạn thành một trạng thái làm việc. Từ đó, nếu bạn thấy rằng những cuộc gọi đó đến snprintf() quá tốn kém đến mức chúng cần phải được tối ưu hóa, thì chỉ sau đó tìm ra giải pháp nhanh hơn.

1

Tôi sẽ nói ít nhất là thử chạy nước rút và vì bạn đã gắn thẻ này là C++, hãy thử StringStream và thực sự lập hồ sơ cho họ. Trong nhiều trường hợp trình biên dịch đủ thông minh để xây dựng một cái gì đó hoạt động khá tốt. Chỉ khi bạn biết nó sẽ là một nút cổ chai, bạn cần phải thực sự tìm thấy một cách nhanh hơn.

2

Một mảng các chuỗi như vậy

array[25] = "25"; 
array[26] = "26"; 

array[255] = "255"; 

có lẽ? Bạn có thể viết một chương trình nhỏ để tạo mã nguồn bảng cho bạn khá dễ dàng, và sau đó sử dụng tệp này trong dự án của bạn.

Chỉnh sửa: Tôi không hiểu ý bạn là gì bởi bạn không muốn liên kết chuỗi địa lý.

+0

Tôi nghĩ bằng dây họ có nghĩa là "std :: string" s. Tôi cũng bối rối vì điều đó. – gravitron

1

thử điều này:

int convert(unsigned short val, char* dest) 
{ 
    int i = 0; 
    if (val > 10000) 
    { 
    dest[i++] = (val/10000) | 0x30; 
    val %= 10000; 
    } 
    if (val > 1000) 
    { 
    dest[i++] = (val/1000) | 0x30; 
    val %= 1000; 
    } 
    if (val > 100) 
    { 
    dest[i++] = (val/100) | 0x30; 
    val %= 100; 
    } 
    if (val > 10) 
    { 
    dest[i++] = (val/10) | 0x30; 
    val %= 10; 
    } 
    dest[i++] = (val) | 0x30; 
    dest[i] = 0; 
    return i; 
} 
+1

có lẽ là 'cuối cùng [i] = '\ 0';'? –

+0

@Tony, oops - tốt bắt! – Nim

1

tôi bị tấn cùng một thử nghiệm các chức năng khác nhau ở đây, và đây là những gì tôi đã đưa ra:

write_ushort: 7,81 s
uShortToStr: 8,16 s
convert : 6.71 s
use_sprintf: 49.66 s

(Write_ushort là phiên bản của tôi, mà tôi đã cố gắng viết rõ ràng là p có thể, thay vì vi tối ưu hóa, để định dạng thành một bộ đệm ký tự đã cho; use_sprintf là sprintf rõ ràng (buf, "% d", x) và không có gì khác; hai câu còn lại được lấy từ các câu trả lời khác ở đây.)

Đây là một sự khác biệt khá tuyệt vời giữa chúng, phải không? Ai có thể nghĩ rằng để sử dụng sprintf phải đối mặt với gần như một thứ tự của sự khác biệt độ lớn? Ồ, vâng, tôi đã lặp lại từng chức năng thử nghiệm bao nhiêu lần?

// Taken directly from my hacked up test, but should be clear. 
// Compiled with gcc 4.4.3 and -O2. This test is interesting, but not authoritative. 
int main() { 
    using namespace std; 
    char buf[100]; 

#define G2(NAME,STMT) \ 
    { \ 
    clock_t begin = clock(); \ 
    for (int count = 0; count < 3000; ++count) { \ 
     for (unsigned x = 0; x <= USHRT_MAX; ++x) { \ 
     NAME(x, buf, sizeof buf); \ 
     } \ 
    } \ 
    clock_t end = clock(); \ 
    STMT \ 
    } 
#define G(NAME) G2(NAME,) G2(NAME,cout << #NAME ": " << double(end - begin)/CLOCKS_PER_SEC << " s\n";) 
    G(write_ushort) 
    G(uShortToStr) 
    G(convert) 
    G(use_sprintf) 
#undef G 
#undef G2 

    return 0; 
} 

sprintf chuyển đổi các toàn bộ phạm vi có thể của quần short unsigned, sau đó đã làm toàn bộ phạm vi lại hơn 2.999 lần vào khoảng 0,25 ms cho mỗi chuyển đổi, trung bình, trên máy tính xách tay ~ 5 tuổi của tôi.

Sprintf là di động; nó cũng đủ hiệu quả cho các yêu cầu của bạn?


phiên bản của tôi:

// Returns number of non-null bytes written, or would be written. 
// If ret is null, does not write anything; otherwise retlen is the length of 
// ret, and must include space for the number plus a terminating null. 
int write_ushort(unsigned short x, char *ret, int retlen) { 
    assert(!ret || retlen >= 1); 

    char s[uint_width_10<USHRT_MAX>::value]; // easy implementation agnosticism 
    char *n = s; 
    if (x == 0) { 
    *n++ = '0'; 
    } 
    else while (x != 0) { 
    *n++ = '0' + x % 10; 
    x /= 10; 
    } 

    int const digits = n - s; 
    if (ret) { 
    // not needed by checking retlen and only writing to available space 
    //assert(retlen >= digits + 1); 

    while (--retlen && n != s) { 
     *ret++ = *--n; 
    } 
    *ret = '\0'; 
    } 
    return digits; 
} 

Compile-time log chức năng TMP là không có gì mới, nhưng trong đó có ví dụ hoàn chỉnh này bởi vì đó là những gì tôi đã sử dụng:

template<unsigned N> 
struct uint_width_10_nonzero { 
    enum { value = uint_width_10_nonzero<N/10>::value + 1 }; 
}; 
template<> 
struct uint_width_10_nonzero<0> { 
    enum { value = 0 }; 
}; 
template<unsigned N> 
struct uint_width_10 { 
    enum { value = uint_width_10_nonzero<N>::value }; 
}; 
template<> 
struct uint_width_10<0> { 
    enum { value = 1 }; 
}; 
+0

Trên thực tế sự khác biệt không phải là tuyệt vời, sprintf có nhiều định dạng specifiers ... có thể tồn tại của người mà nó đã đưa vào tài khoản trong thuật toán của nó. Tôi chưa bao giờ thấy sprintf hoặc thậm chí một số con thú chậm hơn như tăng :: định dạng lấy phần trăm đáng kể thời gian chạy trong hồ sơ như vậy trên hầu hết các trường hợp nó không phải là giá trị tối ưu hóa. –

+0

Một thiên thần nhỏ bảo tôi đừng sử dụng mỉa mai trong bài đăng này và ai đó sẽ bình luận về nó. Tôi không nghe. Nó chỉ xuất hiện như một sự khác biệt rất lớn bởi vì các chức năng được thực hiện gần 200 triệu lần (USHRT_MAX, ở đây 65,535, * 3,000). @ ÖöTiib: Bạn đã giữ lại kết luận rằng tôi đã trình bày OP mà không sử dụng một trình lược tả, vì tôi không có quyền truy cập vào mã của OP để cấu hình nó. –

+0

Có, nhưng tôi cũng cung cấp giải pháp, bởi vì ... ai biết được. Không thể châm biếm nếu bạn không thấy vấn đề thực sự. Đối với một số lý do giao diện dựa trên văn bản và giao thức được phổ biến và nếu hai mô-đun nói chuyện với nhau bằng cách sử dụng sprintf rất nhiều để nói với hàng triệu quần short unsigned với nhau thì nó có thể trở thành chai cổ. Tất nhiên tôi muốn chuyển sang giao diện/giao thức nhị phân trên trường hợp này nhưng các giao diện xem xét lại có thể tốn kém/không có câu hỏi vì một số lý do khác. –