6

unsigned short を char* に変換する (つまり、25 を '25' に変換する) 効率的で移植可能な方法は何でしょうか。

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

私は sprintf の使用などを検討していましたが、ありとあらゆるアイデアを探求したいと考えています。

4

5 に答える 5

6

まず、適切に実行し、次に迅速に実行します。コードの一部がパフォーマンスに優れていないことが確実にわかる場合にのみ最適化してください。

snprintf()バッファに入れると、あなたが望むことができます。それは可能な限り最速のソリューションですか?全くない。しかし、これは最も単純なものの 1 つであり、コードを動作状態にするのに十分です。そこから、これらの への呼び出しsnprintf()が非常に手間がかかり、最適化する必要があることがわかった場合は、そのときだけ、より高速なソリューションを探します。

于 2011-01-18T21:26:32.977 に答える
2

これを試して:

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;
}
于 2011-01-18T22:48:15.343 に答える
2

次のような文字列の配列

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

array[255] = "255";

多分?テーブルのソース コードを簡単に生成する小さなプログラムを作成し、プロジェクトでこのファイルを使用することができます。

編集:文字列を巻き込みたくないという意味がわかりません。

于 2011-01-18T21:34:24.780 に答える
1

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

于 2011-01-18T21:29:04.943 に答える
1

ここでさまざまな機能のテストをハックしました。これが私が思いついたものです。

write_ushort: 7.81 秒
uShortToStr: 8.16 秒
convert: 6.71 秒
use_sprintf: 49.66 秒

(Write_ushort は、特定の文字バッファーにフォーマットするために、マイクロ最適化ではなく、できるだけ明確に記述しようとした私のバージョンです; 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は unsigned short の可能な範囲全体を変換し、5 年ほど前の私のラップトップで、変換あたり平均約 0.25 µs でさらに 2,999 回、範囲全体を変換しました。

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 };
};
于 2011-01-19T04:03:39.257 に答える