第1章の演習


演習の環境について

C++環境の準備にしたがって,手元でC++プログラムを作成,実行できる環境を準備する.

ソースのダウンロード

今後の演習では,ホームフォルダの下にmis2というフォルダを作って, そこで作業することを前提として資料を作成している.macを使う場合は
mkdir ~/mis2
を実行する. http://opendatastructures.orgのc++ edition, c++ sources ( C++ sources(講義独自版) ) からダウンロードしたファイルをホームフォルダの下のmis2に置く.ods.cpp.tgzというファイルができた時は,
cd ~/mis2
tar zxvf ods-cpp.tgz
ods-cpp.tarというファイルができた時は,
cd ~/mis2
tar xvf ods-cpp.tar
を実行するとcppというフォルダができる.

演習(C++プログラムの速度計測)

以下の関数fは整数(int)を要素にするvectorにn回要素を追加(push_back)してn回要素を削除する何もしない関数(何もしないが,コンパイラの最適化で削除されることはないように工夫して いる)である.
void f(std::vector<int> &v, int n){
  for (int i = 0; i < n; i++) v.push_back(i);
  for (int i = 0; i < n; i++) v.pop_back();
}
さまざまな,nを与えた時の実行時間を測るためのプログラム vector_speed.cppをコンパイル実行してみる. これは配布プログラムに含まれている.最初の指示に従うとホームフォルダの下のmis2の下のcppというフォルダに含まれているはずである.
 
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>

uint64_t cputime(){
  unsigned int ax,dx;
  asm volatile("rdtsc\nmovl %%eax,%0\nmovl %%edx,%1":"=g"(ax),"=g"(dx): :"eax","edx");
  return (uint64_t(dx)<<32)+uint64_t(ax);
}

void f(std::vector<int> &v, int n){
  for (int i = 0; i < n; i++) v.push_back(i);
  for (int i = 0; i < n; i++) v.pop_back();
}

int main(int ac, char **ag){
  int n = 1000;
  if (ac > 1) n = atoi(ag[1]);
  std::vector<int> v;
  clock_t clk1 = clock();
  uint64_t cpu1 = cputime();
  f(v, n);
  uint64_t cpu2 = cputime();
  clock_t clk2 = clock();
  std::cout << "cycle : " << cpu2 - cpu1 << std::endl;
  std::cout << "clock : " << clk2 - clk1 << std::endl;
  std::cout << "sec   : " << (double)(clk2 - clk1)/CLOCKS_PER_SEC << std::endl;
}

g++ -O2 -o vector_speed vector_speed.cpp
を実行し,「コンパイル」する.「-O2」は最適化のオプションで,速度計測を目的とする場合は,こ の程度の最適化レベルを用いる.コンパイルに成功したら,
./vector_speed 100000
を実行すると
cycle : 2296824
clock : 658
sec   : 0.000658
のように,表示される.なお,プログラム中で,時間を計らなくても,
time ./vector_speed 100000
のようにしても,
real	0m0.011s
user	0m0.001s
sys	0m0.002s
のように表示されるが,計測の精度は落ちるし,プログラムの一部のみを計測することはできない. プログラムの説明をする.

自習問題

  1. 上のプログラムを自分の環境で実行してみて,fに与えるnの値をどう変化させるかによって,実行時間がどう変わるかを考えて見て下さい.
  2. 自分の環境で実行してみて,clockとcycleの関係から,CPUの速度が何GHzなのかを1秒あたりの実行サイクル数で推計してみてください.
  3. vectorに変えて,list, dequeを使うプログラムに書き換えてみて(プログラム中に出現する3つの"vector"を"list"あるいは"deque"に置き換える),同様に実行時間を計測してみてください.

[投票]Priority QueueがあればFIFO, LIFO を実装できるか?

  1. 両方実装できる
  2. FIFOは実装できるがLIFOは実装できない
  3. LIFOは実装できるがFIFOは実装できない
  4. 両方実装できない

[投票]queueの中でスタック(stack)と呼ばれるのは?

  1. FIFO (first-in-first-out) queue
  2. Priority queue
  3. LIFO (last-in-first-out) queue

[投票]次の中でUSet でなくSSet を使う必要があるのは?

  1. 0から263-1までの数の集合について,ある数が集合の要素に含まれるかどうかを調べる.
  2. 0から263-1までの数の集合について,最小の数を求める.
  3. 0から263-1までの数の集合について,要素数を求める.

[投票]以下のうち正しいのは?

  1. O(2n2) ⊆ O(n2)
  2. O(1.01n) ⊆ O(n100)
  3. O(n2.001) ⊆ O(n2 log n)
  4. O(n2 log2 n) ⊆ O(n2 log n)

[投票]次の関数 f(n)について最も適切なO-記法で表わせ

f(n) = 2 * n3 + 3 * n2 * log n
  1. O(n2)
  2. O(n2 log n)
  3. O(n3)
  4. O(n3 + n2 log n)
  5. O(n3 log n)

[投票]次の関数 f(n, m)について最も適切なO-記法で表わせ

f(n,m) = 2 * n2 log m + 2 * m + 3 * m log n
  1. O(n2)
  2. O(n2 log m)
  3. O(n2 log m + m)
  4. O(n2 log m + m + m log n)
  5. O(n2 log m + m log n)

[投票]確率変数X, Y に対してE[X * Y] = E[X] * E[Y] は成り立つ?

  1. 成り立つ
  2. 成り立たない
  3. 一般には成り立たないが X, Y が独立なら成り立つ

[投票]次の環境のうちw-bit RAMのw=64と仮定するのが適当なものを選べ(正解複数)

  1. iMac端末のWindows環境
  2. iMac端末のMac環境
  3. iPhone SE
  4. 任天堂Switch
  5. Apple Watch