🎅 この記事は「【マイスター・ギルド】本物のAdvent Calendar 2022」8日目の記事です。
0. これちょっとおかしくないですか?
なぜか調べてみよう🤔
1. RAM(Random-access memory)
コンピューターが 5 という数字を保存したい場合はどうする?
まずコンピュータは5という値をRAMに保存する。
RAMとは?
見た目はこんな感じだ。
拡大してみると, 0と1を多く保存できるブランクが約100億個ある電子機器だ。
💡 ▼ このブランクを専門用語としてbit。
コンピュータが値を保存するときは, 多くのブランクの中に8個ブランク程度を用意し、受け取ったデータを0と1で表現して値を保存する。
5を保存するときは、5をバイナリに変換して以下のように保存する。
より大きな数を保存したくなったら、ブランクを増やして保存する。
💡 16ブランクは -32768 から 32767 まで保存できる。
もしコンピューターが 5.125 のような小数を保存したい時はどうする?
2. 小数はどうやって?
まず、5.125という数をバイナリに変換する。
💡 5.125 -> 101.001
このように定数部分と小数部分を分けて値を保存する。
💡 しかし、IEEEというところで推奨する方法が別にあり、上記の方法よりはほとんど以下の方法を使用する。
まず余裕に32ブランクぐらいを用意しておく。
最初のブランクに正数か負数かを判別する値を保存する。
正数 -> 0、負数 -> 1
小数点を一番左まで移動させる。
5.125 -> 101.001
= 1.01001 x 2²
小数点の下の部分(mantissa)を一番後ろから23ブランクに書く。
1.01001(mantissa) x 2²
指数部分に127を足した後(bias 127)、バイナリに変換した後、残りの8ブランクに書く。
1.01001 x 2²
2 + 127 -> 10000001
C++のような言語でfloatを使えば、上記のような方法で小数を保存する。
3. 循環小数問題
0.125のような小数は二進法に変換する時、きれいに0.001に変換される。
しかし、0.1のような曖昧な数字は二進法変換時にきれいに落ちず、無限に11001101100、、、パターンが繰り返される。
数字一つを保存できるブランクは最大32ブランク。
世の中には無限の数を保存できるストレージ容量はないので、後ろの部分をカットする。
この時誤差が生じる。
4. この知識無しにコードを組んだら、死ぬかもしれない
湾岸戦争の際, パトリオットという米軍が運用していたミサイル迎撃装備があった。
ところが、ある日突然ミサイル迎撃に失敗し、28人に死傷者が出た。
パトリオットミサイルはミサイル迎撃に必要なプログラムが搭載されているが、
そのプログラムは時間を0.1秒単位で測定した。
問題は、そのプログラムは数字を保存する時に24ブランクしか使っていなかったことだ。
そのため、0.1ような数字を保存するたびに誤差が生じた。
1時間ごとに0.0034秒の誤差が発生し、
ある日、このプログラムを100時間ほど回しておいて
0.34秒の誤差が生じた。
この誤差のせいで飛んでくるミサイルの座標計算に問題が生じ、
1500m/s速力のミサイル迎撃時に500mほど外れることになった ! 🚀💥
5. 教訓
-
お金やコインのように正確な計算が必要な場合は定数で!🪙
5.1ドルなどを5100セントなどと保存したり、四捨五入文法を適切に使う。
-
floatではなくdouble型を使う!
数字1つにつき64マス使用するため誤差が極めて少なくなる。
短所はメモリ容量が2倍必要!
この知識をよく覚えておけば
overflow
not a number
infinity 、、、
などの問題を分かりやすいと思う !