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

```cpp
#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
```

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

```c
#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}$は以下の数式で算出しました。

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