int a = 10;
//ラムダ式のスコープ外の変数を使用するには変数のキャプチャを指定する。
auto func1 = [a]{ //変数aを指定
cout << a << endl;
}
auto func2 = [a]{
a = 5; //コピーしたキャプチャは書き換えられない。
}
auto func3 = [a]()mutable{
a = 5; //mutable属性を指定すれば書き換えることができる。
}
auto func4 = [&a]{
a = 7; //参照キャプチャは書き換えられる。
}
int x = 20,y = 4,z = 98;
auto func5 = [=]{
cout << x << "," << y << "," << z << endl; //複数の変数をキャプチャするには=を使う
}
auto func6 = [&]{
cout << x << "," << y << "," << z << endl; //参照でも同様。
}
auto func7 = [a,x,&y,&z]{
cout << a << "," << x << "," << y << "," << z << endl; //個別に指定することも可能。
}
八進数から十進数、十六進数から十進数への変換は二進数からの変換と要領は同じ。逆も然り。
二進数との対応は八進数の一桁が3ビットに対応、十六進数の一桁が4ビットに対応する。
その他にも8進数や16進数などがある。
8進数は0~7までの数字を使って数値を表す。
16進数は0~9の数字、更にA~Fのアルファベットを使って表す。
二進数では十進数で表現できる小数でも無限小数になることがある。
例えば0.1などは二進数にすると無限小数になる。
0.1 - 0.5 = -0.4 → 0
0.1 - 0.25 = -0.15 → 0
0.1 - 0.125 = -0.025 → 0
0.1 - 0.0625 = 0.0375 → 1
0.0375 - 0.03125 = 0.00625 → 1
0.00625 - 0.015625 = -0.009375 → 0
0.00625 - 0.0078125 = -0.0015625 → 0
0.00625 - 0.00390625 = 0.00234375 → 1
以下、無限に続く。
0.00011001100...
これを単精度で表す。
1.1001100... * 2-4
指数部は
-4 + 127 = 123
二進数に変換
01111011
符号は0
00111101110011001100110011001100...
このままでは入りきらないので値を丸める必要がある。
IEEE754では丸め方が様々あるが、デフォルトでは最近接偶数丸めと言うものである。
0は切り捨て、1は切り上げる。
00111101110011001100110011001100 | 1
↓
00111101110011001100110011001101
倍精度の場合、指数部が11ビット、仮数部が52ビット、バイアス値が1023になる。
それ以外は単精度と同じ。
例として3.375を浮動小数点にすることを考える。表現方法は32ビットの単精度浮動小数点とする。
整数部と少数部の3と0.375に分ける。
3を二進数に変換→11
0.375を二進数に変換→011
(小数点以下の場合は小数第一位から順に2-1、2-2、2-3・・・となる)
0.375 - 0.5 = -0.125 → 0
0.375 - 0.25 = 0.125 → 1
0.125 - 0.125 = 0 → 1
3.375は二進数で11.011となる。
しかし、これは固定小数なので浮動小数点に変換する。
11.011 → 1.1011 * 21
ここで仮数部の一番左の1は無視する。
1011
後は23ビットになるように0で埋める
10110000000000000000000
指数部は1なのでこれに127を足す。
1 + 127 = 128
128を二進数に変換。
10000000
符号は正の値なので0
よってIEEE754の形式にすると
01000000010110000000000000000000
となる。
32ビットの場合
最上位ビットは符号として扱われる。
23ビット目から30ビット目は指数部で8ビット。
0ビット目から22ビット目は仮数部で23ビット。
負号は正の値なら0、負の値なら1。
指数は8ビットで表し、実際の値に127を加えた値にする。これは指数部が負の時にも対応しやすくする為。127をバイアス値と言う。
仮数部は1から始まるように指数部を調整し小数点を移動する。一番左は必ず1なので無視する。
コンピュータ内部で小数を表す方法は色々あるが、主に使われているのはIEEE 754と言う規格である。
IEEE 754は浮動小数点をコンピュータ内部で表すための規格。
コンピュータ内部で小数を表す時に多くの場合、この規格が使われる。
表現するビット数は32ビットと64ビットが一般的。
符号なし整数で負数を表そうとすると当然負数は扱えないので、全て正の整数として扱われる。
例えば符号なし8ビットの場合、-1を表そうとすると1111 1111となるが、最上位ビットは符号として解釈されない為、-1ではなく、255として扱われる。
プログラミングではこうした特性により思わぬバグを生んでしまうことがある。
例えば、
上記のforループは無限ループとなってしまう。
これはiが符号なしである為、負数を扱えない。よってiが0の時に0から1を引いた結果がint型で表せる最大の正の整数になってしまうからである。これでは条件のi >= 0を満たすことができず無限ループとなる。
扱える範囲を超える場合、オーバフローとなる。
8ビットで考えると、
符号付きの場合、-27~27-1までの範囲(-128~127)なので、この符号付き8ビットの数値で128を表そうとすると1000 0000となってしまい、-128として扱われてしまう。
符号なしとして考えた場合、扱える範囲は0~28-1(0~255)である。
256を表そうとすると、1 0000 0000となるが、8ビットまでしか表せないので最上位のビットは切り捨てられ、0000 0000となってしまう。
多くのプログラミング言語において、数値型は表現できる数字の範囲が決まっている。
これは予め何ビットで表現するかを決めてあるからである。
例えばC言語などのint型は処理系によって異なるが、32ビットで表されることが多い。
int型は符号付きの整数(負数を扱える整数)なので-231~231-1までの範囲を扱える。
これは-2,147,483,648から2,147,483,647までの範囲である。
unsigned intは符号なしの整数(負数を扱えない整数)なので0~232-1(0~4,294,967,295)までの範囲になる。
先ほどの-23を二進数表記にするには以下の手順で行う。なお、今回は8ビットで表現するものとする。
-23の絶対値をとる→23
23を二進数に変換→00010111(8ビットで表現する為今回は先頭に0を補間)
00010111をビット反転する(1の補数)→11101000
11101000に1を加算する。(2の補数)→11101001
11101001が-23を二進数で表した結果になる。
負数の表現
十進数では負数は数値の前に-記号を付けて表すが、二進数などの他の進数では通常そのような負数の表し方はしない。
例えば-23を二進数表記にすると、11101001になる。(8ビットで表す場合)
これには決まりがあり、最上位ビットが1ならその数は負数と見做すと言うのがある。
最上位ビットの値を定める必要がある為、予め表現するビット数を決めておく必要がある。
例として1011010を十進数に変換する。
どちら側からでも良いが、取り敢えず右の最下位ビットから見ていく。
20は0なので0。
21は1なので2。
22は0なので2のまま。
23は1なので2に23を足して10。
24は1なので10に24を足して26。
25は0なので26のまま。
26は1なので26に26を足して90。
よって1011010は十進数で90となる。
逆の二進数から十進数に変換する方法。
二進数で表された数値をbとする。
bのnビット目が1であったら2nを加算する。
これを全てのビットが1であるものに対して行う。
2nで加算していった合計の数値が十進数でbを表した数になっている。
方法その2
よって25は二進数で11001となる
例として25を二進数に変換してみる。
方法その1
25 / 2 = 12 ... 1
12 / 2 = 6 ... 0
6 / 2 = 3 ... 0
3 / 2 = 1 ... 1
よって25を二進数にすると、11001になる。
その前にこっちを書いた方が良かった。
二進数の桁の重みは左から20,21,22となっている。
十進数から二進数の変換
十進数から二進数に変換するには次の方法を使う。
方法その1
十進数の数値をdとする。
dを2で割る。この時の商をd1とする。更にその時の余りをm1とする。
d1を更に2で割る。この時の商をd2とする。更にその時の余りをm2とする。
以下、商が0か1になるまで繰り返し。
その後一番最後に出した余り(商が1の場合は最後に算出した商)から最初の余りまでを繋げるとdを二進数表記したものになっている。
方法その2
十進数の数値をdとする。
dをd >= 2nを満たす最大の数(xとする。)で引く。二進数の桁の重みxに1を立てて、dをxで引いた差をd1とする。
nを一つ減らす。
d >= 2nを満たさない場合は、二進数の桁の重みxに0を置いてdをそのままd1とする。
nを一つ減らす。
以下差が0か1になるまで繰り返し。
後は最初から重みxの桁に置いたものを繋げるとdを二進数表記した数になっている。
分かりづら。
二進数は一桁を「ビット」と呼ぶことがある。
1は1ビット、1001は4ビット。
8ビットで1バイトとなる。
以下、十進数と二進数の対応表
ちなみに二進数では桁の重みを考慮した読み方はせず、10は「じゅう」ではなく「いちぜろ」の様に読む。
十進数で昇順に数える時、0,1,2...9と数えるが、9までくるともう使える数字が無いので桁が繰り上がり10になる。
二進数でも同様で0,1と数えてもう使える数字が無いので桁が繰り上がり、10になる。
一般的にコンピュータ内部では二進数が用いられる。
二進数とは0と1のみで数値を表す方法である。
人間が普段扱っているのは十進数で、0から9までの十通りで表している。
表示される順番は環境依存。
リトルエンディアンとビックエンディアンがある。
リトルエンディアン(LE)は下位バイトから順にメモリに書き込む。
ビックエンディアン(BE)は上位バイトから順にメモリに書き込む。
0xfeac9845
LE→45 98 ac fe
BE→fe ac 98 45
int型の値を1バイトずつ切り分ける。
初期化方法
要素アクセスの[]とatの違いは範囲チェックを行うかどうか。
[]は範囲チェックを行わないので、範囲外を見に行った時にバッファオーバランが発生するときがある。
atは範囲チェックを行うので範囲外を見に行くとstd::out_of_range例外が投げられる。
要素を追加・アクセス
std::vectorの定義
std::vectorは可変長配列である。
通常の配列とは異なり、自由に配列の長さを変えることができる。
また、イテレータを扱えたりと色々便利な関数が用意されている。
番外編
Windowsのデスクトップアプリケーション版(C++言語というかほぼC)
std::functionを使ってもラムダ式を代入可能。
キャプチャ
引数を取ることも可能
戻り値を明示
ラムダ式
Go
Swift