2011-01-18 13 views
6

unsigned shortをchar *に変換する(つまり25を25に変換する)効率的で移植性の高い方法は何でしょうか。unsigned shortをchar *に効率的に変換する*

私は、(std :: string)文字列を取得するなどのことを避けたいと思います。この変換は、迅速かつ頻繁に行われる必要があるため、この場合パフォーマンスは重要です。

私はsprintfを使用するなどのことを検討していましたが、任意のすべてのアイデアをエクスプローラに伝えたいと考えていました。

+3

あなたは '使用してみましたsprintf'/'snprintf'?これを実行したら、コードをプロファイリングして、これがパフォーマンスのホットスポットであると判断しましたか? –

+15

以下にリンクされている記事の一番下の表は、実装の効率と最適性に関する限り、stdlibの実装がどこにあるのかを明確に示しています:http://www.codeproject.com/KB/recipes/Tokenizer.aspx –

答えて

6

まず、正しいことをしてから、それを速くしてください。コードの一部が実行可能でないことが確かに分かる場合にのみ最適化してください。

snprintf()には、あなたが望むことができます。それは可能な限り最速のソリューションですか?どういたしまして。しかし、それは最も簡単なものの1つで、コードを作業状態にすることで十分です。そこから、snprintf()への呼び出しが非常に面倒で最適化が必要な場合は、とし、はより高速なソリューションを探します。

1

私は少なくともsprintfを試してみて、これはC++としてタグ付けされているので、StringStreamを試してみて、実際にそれらをプロファイルします。多くの場合、コンパイラは十分に機能するものを構築するのに十分なほどスマートです。それがボトルネックになることが分かっているときだけ、実際にはより速い方法を見つける必要があります。

2

な多分

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

array[255] = "255"; 

その文字列の配列?あなたは非常に簡単にテーブルのソースコードを生成する小さなプログラムを書くことができ、あなたのプロジェクトでこのファイルを使用します。

編集:私はあなたがあなたが関与していることを望んでいないことを意味するものは得られません。

+0

私は文字列で考える彼らは "std :: string"を意味します。私はそれも混乱していた。 – gravitron

1

はこの試してみてください。

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

最後の 'dest [i] = '\ 0';'? –

+0

@Tony、oops - 良いキャッチ! – Nim

1
私は一緒にここに様々な機能のテストをハッキングし、これは私が思い付いたものです

write_ushort:7.81秒
uShortToStr:8.16秒
変換:6.71s
use_sprintf:49.66s

(Write_ushortは私のバージョンで、これはp指定された文字バッファにフォーマットするためにマイクロ最適化ではなくossible。 use_sprintfは明白なsprintf(buf、 "%d"、x)です。他の2つはここの回答から取っておきます)

これはかなり素晴らしい違いですね。誰がsprintfを使用すると思うでしょうか?ああ、ええ、何回テストした関数を何回繰り返しましたか?

// 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のは私〜5歳のラップトップで、平均して、コンバージョンあたり約0.25マイクロ秒で再び2999回以上を全範囲をした後、符号なしshortの全体の可能な範囲を変換します。

Sprintfはポータブルです。それはあなたの要件にも十分に効率的ですか?


マイバージョン:

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

コンパイル時TMP機能をログに記録、それは私が使用したものですので、新しいものではありませんが、この完全な例を含む:

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

実際に違いはそれほど驚くべきことではありません、sprintfは多種多様な書式指定子を持っています...そのアルゴリズムで考慮する必要がある可能性があります。私はsprintfやboost :: formatのような低速の獣をプロファイルでかなりの割合で使用しているので、最適化する価値はありません。 –

+0

小さな天使はこのポストで皮肉を使わないようにと言ってくれました。私は聞いていない。この機能は約2億回(USHRT_MAX、ここで65,535、* 3,000)実行されるため、大きな違いのように見えます。 @ÖöTiib:プロファイラーを使用せずにOPを示したという結論を再演しました。私はOPのコードをプロファイルするためのアクセス権がないためです。 –

+0

はい、私は解決策も提供しました。なぜなら...知っているからです。あなたが本当の問題を見ないなら皮肉ってはいけません。何らかの理由で、テキストベースのインターフェースとプロトコルが普及しています。もし2つのモジュールがsprintfを使って何百万というunsigned shortsをお互いに話していたら、ボトルネックになるかもしれません。私はもちろん、そのような場合にバイナリインターフェイス/プロトコルに切り替えることを好むだろうが、インタフェースを再考することは、他のいくつかの理由で高価であるかもしれない。 –