LoginSignup
3
1

More than 5 years have passed since last update.

Cで最速の標準入力および標準出力する関数の調査

Last updated at Posted at 2019-03-08
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char**argv){
  int N=strtol(argv[1],NULL,10),i;
  for(i=0;i<N;i++)printf("abcdefg\n");
  return 0;
}

上記のプログラムでコマンドライン引数として$10000000(=10^7)$を指定し以下のコマンドで入力データを作成しました。

./a.out 10000000 > in.txt

標準入力および標準出力の速度調査用に作成したプログラムは以下となります。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
char str[32],c;
int i,j,mode,N;
int main(int argc,char**argv){
  if(argc==0){
    printf("set mode(1~7)");
    exit(0);
  }
  mode=atoi(argv[1]);
  N=atoi(argv[2]);
  switch(mode){
    case 1:
      for(i=0;i<N;i++){read(STDIN_FILENO,str,8);}
      for(i=0;i<N;i++){write(STDOUT_FILENO,str,8);}
      break;
    case 2:
      for(i=0;i<N;i++){fread(str,8,1,stdin);}
      for(i=0;i<N;i++){fwrite(str,8,1,stdout);}
      break;
    case 3:
      for(i=0;i<N;i++)scanf("%s",str);
      for(i=0;i<N;i++)printf("%s\n",str);
      break;
    case 4:
      for(i=0;i<N;i++)gets(str);
      for(i=0;i<N;i++)puts(str);
      break;
    case 5:
      for(i=0;i<N;i++){j=0;for(;;){c=getchar();if(!(c==' '||c=='\n'||c=='\t'||c=='\r')){str[j++]=c;break;}}for(;;){c=getchar();str[j++]=c;if(c=='\n')break;}}
      for(i=0;i<N;i++){j=-1;for(;;){putchar(str[++j]);if(str[j]=='\n')break;}}
      break;
    case 6:
      for(i=0;i<N;i++){j=0;for(;;){c=getchar_unlocked();if(!(c==' '||c=='\n'||c=='\t'||c=='\r')){str[j++]=c;break;}}for(;;){c=getchar_unlocked();str[j++]=c;if(c=='\n')break;}}
      for(i=0;i<N;i++){j=-1;for(;;){putchar_unlocked(str[++j]);if(str[j]=='\n')break;}}
      break;
    case 7:
      for(i=0;i<N;i++){j=0;for(;;){c=getc_unlocked(stdin);if(!(c==' '||c=='\n'||c=='\t'||c=='\r')){str[j++]=c;break;}}for(;;){c=getc_unlocked(stdin);str[j++]=c;if(c=='\n')break;}}
      for(i=0;i<N;i++){j=-1;for(;;){putc_unlocked(str[++j],stdout);if(str[j]=='\n')break;}}
      break;
  }
  return 0;
}

実行時間の調査は以下のようなコマンドで行いました。./a.outの1つ目の引数がモードで、2つ目の引数が行数です。

$time ./a.out 1 10000000 < in.txt > out.txt

各ケースで10回実験行い、実験結果はこのようになりました(単位は秒です)。

回数 ケース1 ケース2 ケース3 ケース4 ケース5 ケース6 ケース7
1 0.168 0.148 0.744 0.115 5.216 0.157 0.093
2 0.191 0.149 0.752 0.097 5.197 0.164 0.088
3 0.168 0.156 0.815 0.097 5.153 0.142 0.092
4 0.198 0.152 0.749 0.095 5.329 0.139 0.094
5 0.168 0.146 0.758 0.099 5.45 0.136 0.107
6 0.167 0.143 0.792 0.115 5.426 0.136 0.122
7 0.167 0.142 0.767 0.097 5.352 0.156 0.091
8 0.168 0.171 0.751 0.094 5.393 0.15 0.094
9 0.212 0.145 0.774 0.097 5.227 0.134 0.093
10 0.17 0.148 0.761 0.095 5.282 0.135 0.105
平均 0.1777 0.15 0.7663 0.1001 5.3025 0.1449 0.0979

まとめるとこのようになりました。

順位 ケース 関数名 平均実行時間 標準不確かさ 結果
1 7 getc_unlocked,putc_unlocked 0.0979s 0.003288 $0.0979\pm0.003288s$
2 4 gets,puts 0.1001s 0.002523 $0.1001\pm0.002523s$
3 6 getchar_unlocked,putchar_unlocked 0.1449s 0.003462 $0.1449\pm0.003462s$
4 2 fread,fwrite 0.15s 0.002675 $0.15\pm0.002675s$
5 1 read,write 0.1777s 0.005196 $0.1777\pm0.005196s$
6 3 scanf,printf 0.7663s 0.007011 $0.7663\pm0.007011s$
7 5 getchar,putchar 5.3025s 0.032564 $5.3025\pm0.032564s$

getc_unlocked,putc_unlocked最速でした。
なお、標準不確かさ$\Delta\overline{x}$は以下の数式で算出しました。

\begin{aligned}
\Delta\overline{x} = \sqrt{\frac{\sum_{i=1}^{N}(x_i-\overline{x})^2}{N(N-1)}}
\end{aligned}
3
1
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1