web-dev-qa-db-ja.com

C ++プログラムでscanf()を使用すると、cinを使用するよりも高速ですか?

これが本当かどうかはわかりませんが、サイトを提供している問題の1つでFAQを読んでいると、何かを見つけました。

入出力方法を確認してください。 C++では、cinとcoutの使用は遅すぎます。これらを使用すると、適切な量の入力または出力の問題を解決できないことが保証されます。代わりにprintfとscanfを使用してください。

誰かがこれを明確にできますか? C++プログラムではcin >> somethingを使用するよりも速くscanf()を実際に使用していますか?はいの場合、それはC++プログラムで使用することをお勧めしますか?私はただC++を学んでいますが、それはC特有だと思いました...

109
zeroDivisible

簡単なケースの簡単なテストを次に示します。標準入力とXORすべての数字から数字のリストを読み取るプログラム。

iostreamバージョン:

_#include <iostream>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  while (std::cin >> x)
    parity ^= x;
  std::cout << parity << std::endl;

  return 0;
}
_

scanfバージョン:

_#include <stdio.h>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  while (1 == scanf("%d", &x))
    parity ^= x;
  printf("%d\n", parity);

  return 0;
}
_

結果

3番目のプログラムを使用して、33,280,276個の乱数を含むテキストファイルを生成しました。実行時間は次のとおりです。

_iostream version:  24.3 seconds
scanf version:      6.4 seconds
_

コンパイラの最適化設定を変更しても、結果はまったく変わらないようでした。

したがって、実際には速度の違いがあります。


EDIT:User clyfish 以下に指摘 速度の違いは、主にiostream I/O関数がC I/O関数との同期を維持しているためです。 std::ios::sync_with_stdio(false);への呼び出しでこれをオフにできます:

_#include <iostream>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  std::ios::sync_with_stdio(false);

  while (std::cin >> x)
    parity ^= x;
  std::cout << parity << std::endl;

  return 0;
}
_

新しい結果:

_iostream version:                       21.9 seconds
scanf version:                           6.8 seconds
iostream with sync_with_stdio(false):    5.5 seconds
_

C++ iostreamが勝ちます!この内部同期/フラッシュは、通常iostream i/oを遅くするものであることがわかります。 stdioとiostreamを混在させていない場合は、オフにすることができ、iostreamが最速になります。

コード: https://Gist.github.com/3845568

197
nibot

http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma

cin/coutのパフォーマンスは、基盤となるCライブラリとの同期を維持する必要があるため、遅くなる可能性があります。これは、C IOとC++ IOを使用する場合に必要です。

ただし、C++ IOのみを使用する場合は、IO操作の前に次の行を使用します。

std::ios::sync_with_stdio(false);

詳細については、対応する libstdc ++ docs をご覧ください。

61
clyfish

おそらくscanfはストリームを使用するよりもいくらか高速です。ストリームは多くのタイプセーフティを提供し、実行時にフォーマット文字列を解析する必要はありませんが、通常、過剰なメモリ割り当てを必要としないという利点があります(これはコンパイラとランタイムに依存します)。そうは言っても、パフォーマンスが唯一の最終目標であり、クリティカルパスにいる場合を除き、より安全な(より遅い)メソッドを優先する必要があります。

ハーブサッターによる非常においしい記事がここにあります。「 マナーファームのストリングフォーマッター 」は、sscanflexical_castおよびどのようなものがそれらをゆっくりまたは迅速に実行させていたのか。これは、CスタイルIOとC++スタイルの間のパフォーマンスに影響を与えるようなものにおそらく似ています。フォーマッタとの主な違いは、タイプセーフティとメモリ数です。割り当て。

42

私は夜、UVa Onlineの問題(Factovisors、非常に興味深い問題、チェックしてみてください)に取り組んでいます。

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=35&page=show_problem&problem=108

送信時にTLE(制限時間を超過)を取得していました。これらの問題解決オンラインジャッジサイトでは、ソリューションの評価に使用される可能性のある数千のテストケースを処理するために、約2〜3秒の時間制限があります。このような計算量の多い問題では、マイクロ秒ごとにカウントされます。

提案されたアルゴリズムを使用していました(サイトのディスカッションフォーラムで読みました)が、まだTLEを取得していました。

「cin >> n >> m」を「scanf( "%d%d"、&n、&m)」に変更し、いくつかの小さな「couts」を「printfs」に変更すると、TLEが「Accepted」に変わりました。

それで、はい、特に制限時間が短い場合、それは大きな違いを生むことができます。

16
Bogatyr

パフォーマンスと文字列フォーマットの両方に関心がある場合は、 Matthew WilsonのFastFormat ライブラリをご覧ください。

編集-そのライブラリのaccu出版物へのリンク: http://accu.org/index.php/journals/1539

6
xtofl

はい、iostreamはcstdioよりも低速です。
はい、C++で開発している場合は、おそらくcstdioを使用しないでください。
とはいえ、フォーマット、タイプセーフティ、何とか、何とか、何とかを気にしない場合は、scanfよりも高速なI/O取得方法があります...

たとえば、これはSTDINから数値を取得するカスタムルーチンです。

inline int get_number()
{
    int c;        
    int n = 0;

    while ((c = getchar_unlocked()) >= '0' && c <= '9')
    {
        // n = 10 * n + (c - '0');
        n = (n << 3) + ( n << 1 ) + c - '0';
    }
    return n;
}
2
pedro.lupin

FILE *をC++ streambufと​​して実装し、fprintfをランタイム形式パーサーとして実装するstdio実装( libio )があります。 IOstreamはランタイム形式の解析を必要としません。それはすべてコンパイル時に行われます。そのため、バックエンドが共有されているため、実行時にiostreamが高速になると期待するのは合理的です。

2
MSalters

問題は、cinscanf()呼び出しの上に抽象化レイヤーを提供するため、多くのオーバーヘッドが伴うことです。 cinが必要なため、C++ソフトウェアを作成している場合は、cinよりもscanf()を使用しないでください。パフォーマンスが必要な場合、おそらくC++でI/Oを記述することはないでしょう。

1
dreamlax

一般的に使用されるステートメントcinおよびcoutは、C++のscanfおよびprintfよりも遅いように見えますが、実際にはより高速です!

問題は、C++では、cincoutを使用するときは常に、scanfcinをプログラムで使用すると、両者は互いに同期して動作します。この同期プロセスには時間がかかります。したがって、cinおよびcoutは遅くなるように見えます。

ただし、同期プロセスが発生しないように設定されている場合、cinscanfよりも高速です。

同期プロセスをスキップするには、プログラムのmain()の先頭に次のコードスニペットを含めます。

std::ios::sync_with_stdio(false);

詳細については、 このサイト をご覧ください。

0
#include <stdio.h>
#include <unistd.h>

#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

static int scanuint(unsigned int* x)
{
  char c;
  *x = 0;

  do
  {
      c = getchar_unlocked();
      if (unlikely(c==EOF)) return 1;
  } while(c<'0' || c>'9');

  do
  {
      //*x = (*x<<3)+(*x<<1) + c - '0';
      *x = 10 * (*x) + c - '0';
      c = getchar_unlocked();
      if (unlikely(c==EOF)) return 1;
  } while ((c>='0' && c<='9'));

  return 0;
}

int main(int argc, char **argv) {

  int parity = 0;
  unsigned int x;

  while (1 != (scanuint(&x))) {
    parity ^= x;
  }
  parity ^=x;
  printf("%d\n", parity);

  return 0;
}

ファイルの最後にバグがありますが、このCコードは高速のC++バージョンよりも劇的に高速です。

paradox@scorpion 3845568-78602a3f95902f3f3ac63b6beecaa9719e28a6d6 ▶ make test        
time ./xor-c < Rand.txt
360589110

real    0m11,336s
user    0m11,157s
sys 0m0,179s
time ./xor2-c < Rand.txt
360589110

real    0m2,104s
user    0m1,959s
sys 0m0,144s
time ./xor-cpp < Rand.txt
360589110

real    0m29,948s
user    0m29,809s
sys 0m0,140s
time ./xor-cpp-noflush < Rand.txt
360589110

real    0m7,604s
user    0m7,480s
sys 0m0,123s

元のC++は30秒かかり、Cコードは2秒かかりました。

0
hexec