(Helluva Boss)
英語から翻訳
I.M.Pグループ、TETOの可能性あり!?
⯆⚉⯆
~テテテト~
「私を『かわいい』なんて言うな、私はギャングスタだ!」
(何らかのプロキシと併用することをおすすめします。JLMMが動くかは分かりませんし、自分で試すのが面倒なので)
シナリオ1:
ルーナ、ミリー、モクシーが警察から逃げている。
シナリオ2:
あなたはもう1か月I.M.Pで働いている。今日は全員で会議がある。
シナリオ3:
あなたは病気だ。ルーナがあなたの面倒を見ている。(ほのぼの系を想定)
シナリオ4:
あなたとミリーは地上での任務中だ。
シナリオ5:
あらら...
シナリオ6:
大きな喧嘩があった。ルーナを慰めに行こう。
シナリオ7:
あなたとルーナはふざけ合っている。
シナリオ8:
ルーナ、ミリー、モクシー、ブリッツォが新しいヘルハウンドを養子に迎えたがっている。それがあなたさ、双子ちゃん。(ヘルハウンドPOV)
シナリオ9:
自分のシナリオを入力してください。
タグ:
コンピューターは意味不明だ。箱に金属を放り込めば、ほら。一体ここで何が起きているんだ?君のPCの中には中央処理装置、つまりCPUがある。それは基本的に、トランジスタと呼ばれる何十億もの顕微鏡サイズのスイッチが載ったシリコンの一片にすぎない。電気の流れ方によって、それらはオンかオフになり、電球のように、私たちに1と0という2つの状態を与えてくれる。このスイッチの1つの値をビットと呼ぶ。1ビット単体では大したことはできないが、それらを組み合わせれば...8ビットのまとまりをバイトと呼び、0と1の256通りの組み合わせを持つことができる。おめでとう!これで二進法と呼ばれる体系で数えることで情報を保存できるようになった。各ビットは2の累乗を表し、1はその累乗が含まれること、0は含まれないことを意味する。だからこの数は1×64、1×4、1×1で、合計すると69になる。これはいいが、人間にとっては16進法の方がさらに優れている。よくこの0xで表され、単に二進法より読みやすい形式だ。4つの二進ビットは0から15までの任意の値を取れる。16進法は0から9とAからFを使ってそれらの値を表すので、4ビットのまとまりを1つの16進数の桁に置き換えられる。よし、これで数を保存できるようになったので、あとはコンピューターに実際に、ええと、何かさせればいい。トランジスタを使えば論理ゲートが作れ、それは論理命題を内包する電子回路だ。2つのスイッチが付いた電球のようなもので、特定の条件下でのみ、たとえばAとBがオンのときだけ光ると考えればいい。論理ゲートを巧みに組み合わせることで、二進法での数学的演算を形式化した体系であるブール代数に従って計算を行う回路を構築できる。しかし、コンピューターは0と1を理解するとはいえ、人間にとってはあまり役に立たない。そこで、ASCIIのような文字エンコーディングを使い、各文字に二進数を割り当てられる。キーボードで何かを入力すると、それがこの二進コードに変換され、コンピューターはそれを見るやいなや、ああそうか、これは大文字のAだな、と言って画面に貼り付ける。これらの機器がどう組み合わさるかは、Windows、Linux、MacなどのOSカーネルが処理し、それはコンピューターのハードウェアとアプリケーションの間に位置して、たとえばデバイスドライバなどで、それらすべてがどう協調して動くかを管理する。入力デバイスを使えばボタン一つでコンピューターに指示を与えられるが、最も低いレベルでは、コンピューターは機械語の命令しか理解しない。それはCPUに何をすべきか、どのデータを使うべきかを伝える二進コードだ。これらの命令に従うことにかけては、CPUは一種の天才だが、記憶力は痴呆の金魚並みだ。どんな命令でも処理できるが、データを保存できないので、ランダムアクセスメモリ、つまりRAMがあって初めて本当に役に立つ。グリッドのようなもので、各箱が1バイトの情報、つまりデータか命令を保持でき、CPUが4つのステップでアクセスできるようアドレスを持つと考えればいい。メモリからフェッチし、命令とデータをデコードし、最後に実行して結果を保存する。これが1マシンサイクルだ。プログラムは基本的に命令とメモリのリストにすぎないので、実行するにはCPUがマシンサイクルで一つずつ、完了するまで実行する。ああそうだ、これがものすごく速く起きること、言ったっけ?現代のCPUは毎秒何十億ものサイクルをこなせ、それらはクロックジェネレーターによって調整・同期される。このクロックの速度はギガヘルツで測られ、人々はしばしば性能向上のためにCPUをオーバークロックする。それはいいことだが、PCが炎上するかもしれない。さらに狂っているのは、CPUには複数のコアがあり、それらがすべて異なる命令を並列に、つまり同時に実行できることだ。各コアは複数のスレッドに分割することもでき、それによって各コアが複数の命令を並行して、つまりそれらをものすごく速く切り替えながら処理できる。よし、それはクールだが、そもそもコンピューターに指示を与える手段がなければ、どれだけ強力でも意味がない。機械語を手で入力するのはおそらく気が狂うだろうが、幸運にもそうする必要はない。カーネルはシェルに包まれており、シェルはカーネルをユーザーに公開するだけのプログラムで、テキスト入力によるコマンドラインインターフェースで簡単な指示を可能にする。しかしコンピューターに何か役立つことをさせる最良の方法はプログラミング言語で、それは抽象化を用いるので、これの代わりにこういうコードが書け、それが君のために機械語に変換される。Pythonのようないくつかの言語はインタープリターを使い、ソースコードを直接1行ずつ実行しようとする。CやGoのような他の言語はコンパイラーを使い、プログラム全体を機械語に変換してからCPUが実行できるファイルに入れる。さて、プログラミング言語ごとに構文は異なるが、ほとんどすべてが持つ基本的なツールがいくつかある。データを使う最も基本的な方法は変数で、値に名前を割り当て、それを再利用・変更できる。値に応じて、変数は異なるデータ型を持てる。テキストには、単一の文字と複数文字の文字列がある。数値には、負なら符号付きにもできる整数と、小数値用の浮動小数点数がある。浮動小数点と呼ばれるのは、小数点が動き回って精度と範囲をトレードオフできるからだ。これが可能なのは科学表記法を使うからだ。ある数かける、小数点をどこに置くかを示す累乗で、まさに内部での見た目そのものだ。実際の数は二進小数で保存される。3分の1のようないくつかの分数は、二進法では無限和でしか近似できない。しかしメモリは無限ではないので、どこかで打ち切る必要があり、それが丸め誤差を生み、時にかなり奇妙な計算を引き起こす。これでは足りなければ、longとdoubleは2倍のメモリを使ってintとfloatの範囲を2倍にする。Pythonのようないくつかの言語は変数の型を自動で判断するが、Cのような言語では変数の型を明示的に宣言しなければならない。変数の値はメモリ内のあるアドレスに保存される。ポインタは値が別の変数のメモリアドレスである変数で、このアンパサンドで表される。だから実際、ポインタとはあるメモリのかたまりが別のメモリのかたまりを指しているだけだ。メモリアドレスはただの数なので、それを足し引きしてメモリの個々のバイトを移動できる。これをポインタ演算と呼ぶ。Cのようないくつかの低レベル言語では、メモリが不要になったら手動で割り当てて解放しなければならない。これはすべてヒープで行われ、ヒープはプログラムの要求に応じて動的に伸び縮みできるメモリの一部で、より多くの制御を可能にするが、コードを完全に壊すのも信じられないほど簡単にする。存在しないメモリに触れたり触れなかったりすると、セグメンテーションフォールトとして知られるものになる。また、もう使われていないメモリのかたまりがあって、解放し忘れたり、もうアクセスする手段がなくなったりすると、そのメモリはもはや使えない。これはメモリリークと呼ばれ、プログラムを遅くし、最終的にはクラッシュさせる可能性がある。この混乱を避けるため、Pythonのような高水準言語にはメモリを管理してくれるガベージコレクターが組み込まれている。データ型によって使用するメモリ量は異なる。整数はたいてい4バイトのメモリ、単一の文字はたいてい1バイトのメモリで、文字列は文字列の終わりを示すヌル文字を伴う複数の文字バイトにすぎない。このように複数の項目を連続したメモリのかたまりに保存するのが配列の考え方だ。より一般的には、同じデータ型を持つ項目のリストで、各項目はたいてい0から始まる数値インデックスを持つ。項目はメモリ上で隣り合っているので、最初の項目のアドレスを知ることで、ポインタ演算を使って配列内の任意の項目に素早くインデックスできる。配列はいわゆるデータ構造で、扱いやすくするためにデータを整理する方法にすぎない。配列からの値の取得は驚くほど速いが、配列のサイズは作成時に固定されることが多く、いっぱいになると何も追加できず、全部使わなければ無駄なメモリになるので、より柔軟な選択肢が連結リストだ。値と次のノードへのポインタを含むノードを使い、それによってメモリ上で離れ離れにできる。また、任意のノードを追加・削除できるので動的に伸び縮みし、ポインタを並べ替えるだけで順序を変えられる。これは素晴らしいが、最後のノードにアクセスするにはその前のすべてをたどるしかないので実用的でないこともある。それでも配列も連結リストも、キューやスタックを作れるので役に立つ。スタックは後入れ先出しの原則に従い、パンケーキの山から取るようなものだ。実用的には、常に最後に追加された項目を指すポインタを想像すればよく、ポップで最後の項目を取り除き、ポインタを一つ戻す。キューは先入れ先出しの原則に従い、2つのポインタを使う。1つは最初に追加された項目、もう1つは最後の項目だ。新しい項目は最後のポインタの後ろに追加され、ポインタが更新され、デキューは最初のポインタから始まる。もう一つ役に立つデータ構造がハッシュマップで、キーと値のペアの集まりにすぎない。配列のような働きをするが、ハッシュ関数を使ってキーを取り、インデックスに割り当て、そこに値を保存する。しかし時に、2つの異なるキーが同じインデックスにマッピングされることがあり、これは衝突と呼ばれる。これに対処する方法はいくつかあるが、1つはその配列の位置に連結リストを作ることで、その値の検索が少し遅くなるが、それでもハッシュマップは信じられないほど役に立つ。なぜならすべての値を指すキーを定義でき、配列に基づいているので取得が驚くほど速いからだ。多くの問題で、異なるデータ点間の関係をデータ構造として表すことが非常に役立つ。連結リストのノードを取り、任意のノードが任意の他のノードを指せるようにすると、グラフが得られる。ノードはエッジで結ばれ、有向、無向にでき、重みを運ぶこともでき、距離やコストなど任意の指標を表せる。グラフはネットワーク内のグループを分析したり、2点間の最短経路を見つけたりするのに役立つ。たとえばGoogleマップのように。グラフを探索する主な方法は2つある。幅優先探索は1つのノードから始めて、対象ノードを初めて見つけるまで層ごとに外へ進む。深さ優先探索はすべての経路を完全に探索し、行き止まりに達したら、別の経路を持つ最後のノードまで戻り、同じように続けて対象ノードを見つけるまで進む。任意の2つのノードがちょうど1つの経路で結ばれたグラフは木と呼ばれ、階層を表す。たとえばコンピューターのファイルシステムだ。木は根から始まり、葉ノードで終わる部分木に枝分かれする。親ノードは任意の数の子ノードを持てるが、多くの場合二分木が最も役に立つ。たとえば、任意のノードの左側のすべての値がそれより小さく、右側のすべての値がそれより大きい二分木は二分探索木と呼ばれ、特定の値を見つけるのが超高速になる。対象の値を見つけたいなら、根から始めればいい。対象がそのノードより小さければ左へ、大きければ右へ進み、対象を見つけるまでこれを繰り返す。今使ったのは非常に単純なアルゴリズムで、問題を段階的に解く一連の指示にすぎない。アルゴリズムを書く最も単純な方法は関数の形だ。入力を受け取り、それで何かをし、出力を返す。変数と同じように、名前で関数を呼び、異なる引数を渡せる。関数を呼ぶと、その関数呼び出しはコールスタックにプッシュされる。コールスタックはコード実行に使われる短期記憶で、名前が示す通りスタックデータ構造に基づいており、後入れ先出しだ。アルゴリズムを実装するには、しばしば2つの値を比較する必要があり、大なりや等しいなどの演算子や、and、or、notなどの論理式でそれができる。このような式は単純で、真か偽になり、これがブールデータ型の取りうる値で、条件文を書けるようにする。ある条件が真ならこれをし、そうでなければあれをする。ブール値はコードの特定部分をループするのにも使える。1つの方法はwhileループだ。この条件が真の間、このコードが実行される。もう1つの方法はforループで、配列のようなデータ構造内のすべての要素を反復できるが、開始値を設定し、各反復後にそれを増やし、条件で上限を設定することで特定の回数だけループすることもできる。関数は自分自身を呼ぶこともでき、これは再帰として知られる。これは問題をより小さな同一の問題に分解できるときに役立つ。たとえば5の階乗を計算するのは、5かける4の階乗にすぎず、それは4かける...しかし既定では、再帰関数は永遠に自分自身を呼び続けるだけだ。つまり、スタックメモリが超過してスタックオーバーフローになるまで、より多くの関数呼び出しをコールスタックにプッシュし続ける。それは最適ではない。これを止めるには、いつ止めるかを定義する基底条件を再帰関数に追加しなければならない。そうして初めて、PCをクラッシュさせずに関数呼び出しが実行される。再帰はクールだが、時間的にも空間的にもかなり高くつくことがある。そこで、必要な計算量を最小限にするために、過去の結果をキャッシュに保存し、再び出てきたときにコンピューターがゼロから再計算しなくて済むようにできる。これはメモ化と呼ばれる。性能と言えば、アルゴリズムがどれだけ優れているかを判断するには、時間計算量と空間計算量、つまり実行にどれだけ時間や空間が必要かを見ればいい。これはビッグO記法で測られ、入力サイズの増加とアルゴリズム実行に必要な操作数の関係を表す。たとえば配列内のすべての数に1を足すのはO()だ。配列が大きくなるにつれて操作数が線形に増えるからだ。重要なのは正確な操作数ではなく、入力サイズが無限大に向かうときの傾向だ。ほら、nの階乗のようなものは、どんな線形関数よりもはるかに速く増える。だから時間計算量が何らかの線形関係である限り、O()に簡略化され、他のグループにも同じことが言える。アルゴリズムを書くとき、常に異なるアプローチがある。総当たりのアプローチは、リスト内の対象を見つけるまで単にすべての項目をチェックすることだ。しかしプログラムを庭のカタツムリより速く動かしたいなら、分割統治のようなより洗練されたアプローチが必要だ。たとえば二分探索では、中央の要素を繰り返しチェックして対象がどちら側にあるかを見て、その半分で見つけるまで探索を続ける。また、コードを書く一般的なアプローチもあり、それらはプログラミングパラダイムと呼ばれる。宣言型プログラミングはコードが何をするかを記述するが、コンピューターが正確にどうすべきかは記述しない。一方、命令型プログラミングはコンピューターが詳細な指示で結果をどう達成すべきかを明示的に記述する。命令型プログラミングの拡張がオブジェクト指向プログラミングで、クラスをオブジェクトの設計図として定義できる。オブジェクトはプロパティという形のデータとメソッドという形の振る舞いからなる単一の単位だ。クラスをコーディングするには、まずプロパティを変数として、メソッドを関数として定義する。クラスにプロパティとメソッドをカプセル化した後、オブジェクトをインスタンス化し、ドット記法でそのプロパティとメソッドを扱える。クラスはコードを整理して再利用するのを容易にする。なぜならスーパークラスのプロパティと振る舞いを継承するサブクラスを定義できるが、それらを拡張・オーバーライドもできるからだ。たとえばゴム製のアヒルのサブクラスは、クワッという代わりにキュッと実装するかもしれない。結果として、ゴム製のアヒルはアヒルクラスのオブジェクトとして扱えるが、クワッが呼ばれたときは違う振る舞いをする。これがポリモーフィズムの概念だ。しかし問題によっては、これらの伝統的なパラダイムのどれも機能しない。これらの画像のどれがミツバチかをコンピューターに認識させたいとしよう。問題は、ミツバチがどんな見た目かをコードで記述できないことだ。ここで機械学習の出番だ。つまり、そのタスクを行うよう明示的にプログラムせずにコンピューターにタスクのやり方を教えることだ。まず大量のデータが必要で、それを訓練データとテストデータに分けられる。次に、時間とともにパラメータを変えられるアルゴリズムを選ぶ。たとえばニューラルネットワークでは重みを更新して異なる結果を達成できる。このアルゴリズムに大量の訓練データを流し込むことでモデルを構築でき、その精度をテストデータで確認できる。完全に正しくなければ、モデルは出力を本来あるべきものと比較し、その差を誤差関数に捉え、差を最小化するようパラメータを微調整することで時間とともに改善できる。しかしどれだけ未来的で、最先端で、驚くほど速く、最適化されていても、書いたアプリケーションを実際に人に使ってもらいたいなら、インターネットについて知っておくべきだろう。それは世界中のコンピューターがワイヤーでつながれたネットワークだ。文字通り、インターネットは海底を走る太いケーブルの束と、あなたを目的地につなぐインターネットサービスプロバイダーのような施設にすぎない。これらのコンピューターはインターネットプロトコルスイートで通信する。ネットワーク上のすべてのコンピューターは一意のIPアドレスを持ち、2台のコンピューターは伝送制御プロトコルでデータを転送できる。それはメッセージをたくさんのパケットに分割し、ワイヤーのネットワークを通して送り、受信側がメッセージを元に戻す。インターネット接続が悪いと、パケット損失を経験したことがあるかもしれない。それはこれらのパケットの一部が途中で失われることだ。インターネットがハードウェアなら、ウェブはソフトウェアで、ブラウザで使える。ウェブ上のすべてのページはURLを持つ。それをブラウザに入力すると、ドメイン名システムでこのウェブサイトをホストするサーバーのIPアドレスを調べる。それはドメイン名を実際のサーバーのIPアドレスにマッピングする辞書のようなものだ。TCP経由で接続した後、クライアントと呼ばれるブラウザはハイパーテキスト転送プロトコルを使ってサーバーにHTTPリクエストを送り、サーバーは理想的にはウェブページの内容を含む応答を返す。実際のウェブサイトはたいてい3つの部分からなる。HTMLファイルはウェブサイトのすべての内容を含み、基本的にはテキスト、リンク、ボタンなどの要素の集まりにすぎない。CSSファイルは見た目を制御し、ウェブサイトを素敵に見せる。しかし見栄えのいいボタンを押しても何も起きなければウェブサイトは役に立たないので、JavaScriptのような言語が機能を追加する。しかし時に物事はうまくいかない。すべてのHTTP応答には応答コードが付き、応答の状態に関する情報を運ぶ。たとえば200はOKを意味し、4で始まるものはエラーで、最も有名なのは404、ページが見つかりませんだ。HTTPリクエストは異なるメソッドを運べる。たとえばget、post、put、deleteで、情報の取得、追加、更新、削除だ。これらはしばしばアプリケーションプログラミングインターフェースで使われ、それは2つのアプリケーションをつなぎ、互いにやり取りできるようにする。たとえばデータベースにデータを保存・取得する。最も一般的な種類のデータベースはリレーショナルデータベースで、テーブルを使ってデータを保存する。テーブルの列は異なる属性を含み、行は個々のデータ点を表す。また、各テーブルには主キーと呼ばれる一意の属性がある。外部キーは別のテーブルの主キーで、2つの間の関係を確立する。この場合、各本は著者につながっている。SQLのような言語で、これらのテーブルのデータを扱う文を書ける。タイトルがHで始まるすべての本のタイトルと著者を調べられるが、そのためには著者のテーブルと本のテーブルを一致するキーで結合し、異なるテーブルの2つの属性を1つにまとめる必要があり、これがこの出力を与える。これらの文は役に立つが、注意しないと1行のコードでデータベース全体を削除してしまうかもしれない。でも心配しないで、そんなことは今まで起きたことがない。すべてのログインページの背後にはユーザー名とパスワードのデータベースがある。ユーザーがログインしようとすると、しばしばSQLクエリを使ってユーザー入力がデータベースのエントリと一致するか確認する。それはいい。しかし悪意ある者はこんなものを入力するかもしれない。それは文字列を途中で終了させ、残りをコメントアウトすることでクエリを変える。つまりこのユーザー名がデータベースに存在する限り、アクセスが許可される。これはSQLインジェクション攻撃と呼ばれ、ハッカーが本来行くべきでない場所に行く最も簡単な方法の1つだ。これらの概念を聞くのは1つのことだが、本当に学ぶには実際にそれらが動くのを見て自分で使わなければならない。まさにそれがBrilliantでできることで、数学やデータサイエンスからプログラミングやAIまで、何千ものインタラクティブなレッスンがある。ビジュアルレッスンとインタラクティブな問題で知識を定着させ、楽しいだけでなく直感的な問題解決スキルを養い、何時間もの講義を見るよりも6倍効果的であることが証明されている。新しいスキルを学ぶ時間を作るのは難しいかもしれないが、Brilliantはそれをとても簡単にしてくれる。1日ほんの数分で、どんなデバイスからでも、どこでも、いつでも、一口サイズのレッスンで貴重な知識をゼロから築ける。データサイエンスの基礎からSpotifyの実際のデータセットの分析まで、あっという間に進められ、数学の基礎やPythonのプログラミングコースで補い、現代で最も需要の高いスキルセットの1つを築ける。最高なのは?brilliant.orgスラッシュwackyscienceにアクセスすれば、Brilliantが提供するすべてを丸30日間無料で試せる。年間プレミアム購読も20%オフになる。この動画をスポンサーしてくれたBrilliantに感謝する。
作成済み 1月30日
更新済み 8月9日
公開済み 1月30日