今更理解する浮動小数点
自分なりのまとめです。間違いがありましたらすみません。
コンピュータでの数の表現の仕方
コンピュータのハードウェア(基盤のようなものを想像してみてください)はICで構成されておりこのICは電圧のONとOFFのどちらかの状態しか持つことが出来ません。
そのためこのICの集まりで何かを表現するためにはONとOFFの集まりで表現するしかありません。そこでONを数字の1、OFFを数字の0としてみなしてこの並びでデータを表現することにします。
そのような0と1の並びをどのように解釈するかで表現したいものが決まります。
101100101.....のようなデータを画像と解釈するか動画と解釈するかゲームと解釈するかそれともただの数として解釈するかは自由です。
ただ、解釈した結果があなたの望むものであれば良いのです。そしてコンピュータが数を扱う際にはこの0と1の並びをただの数として解釈します。
2進数
数ですから数えられなければいけません。しかも、0と1しか使えません。
では、りんごを数えましょう。
まずりんごが何もない状態を想像してください。これを0と1だけで表現しなければいけません。
ではりんごが何もない状態を0と表現することに勝手に決めましょう。
次にさっきの空の状態からりんごを1つ追加しました。さてこれを数えましょう。
この状態を1と表現することに勝手に決めました。
ここからさらにりんごを1つ追加しました。これを数えたいです。
では、これを2と表現しま。。。おっと人間っぽくなってしまいました。
先にお話したようにコンピュータは0と1しか使えないんでしたね。
では、0と1だけでどのように今の状態を表現しましょうか。もう0という表現を使ってしまいました。1という表現もです。
うーん、困りました。どうやら今のままではここまでしか数えられないようです。どうしましょう?
そこで思いつきました。もうひと桁増やして表現しよう。
先ほどまではひと桁でしたが増やすと使える表現が00や01や10や11と増えました。
これでもう一度最初から数えてみましょう。
空の状態を00とする。そこから1つ追加したものを01、そこからさらに1つ追加したものを10、さらに追加したものを11とします。
さっきより数えられる範囲が広がりました。このように桁を増やせばどんどん数えられる範囲が広がります。
このように数を表現する方法が2進数です。0と1しか使わない。0と1は電圧のONとOFFに対応させることができます。そのためこの表現の仕方はコンピュータにとってとても扱いやすいのです。
2進数での負の数
2進数で負の数はどのように表現するのかというといくつか方法があります。
代表的なのでいうと符号をつけるという先頭1桁目が1なら負で0なら正の数とみなすという方法や2の補数という方法など。。。
ここでは負の数も表す方法があるんだなという理解で良いです。
2進数での四則演算
すみません。大切だとは思いますが省略します。調べればすぐに出てくると思いますので。。。
ここでは2進数でも足し算もかけ算も出来るんだとご理解頂ければと思います。
2進数での小数表現
まず10進数で普通に考えてみましょう。1から0.1を得るにはどうすれば良いでしょうか?1×とやれば得られますね。
この時1の桁が右に1個ずれてますね。10個で桁が増えるのが10進数ですから10倍すると桁が左にずれ、すると桁が右にずれます。
同じように2進数で考えて2進数の1の桁を右に1個ずらすには1×とすると1の桁が右にずれて0.1となります。
これらから10進数での0.1は10個集まると桁が上がりますので10進数では0.1です。2進数での0.1は2個集まると桁があがりますので10進数に直すと0.5になります。
このように0.1という同じ見た目でもそれが10進数での表現か2進数での表現かで実際に意味する数が変わります。
では、2進数での0.11を10進数に直した場合の数はいくらでしょうか?これは2進数での0.1と2進数での0.01の組み合わせです。
先ほどのことから2進数での0.1は10進数での0.5でした。では2進数での0.01は10進数ではいくらでしょうか?2進数の0.01を2個集めると桁があがって2進数での0.1になるのです。
つまり 2進数での0.1は10進数での0.5なので10進数での計算に直すと0.5 = 2 × ? です。?は0.25です。つまり2進数の0.01を10進数に直すと0.25です。
このことから2進数での0.11を10進数に直すと0.5+0.25=0.75であることが分かります。
さて、10進数の0.5を2進数で表すと0.1と表せることは分かりました。しかし0.1という表現をそのままコンピュータで使うことは出来ません。はじめに言った通りコンピュータは0と1の並びでしか表現できません。小数点(.)なんてありませんから。ではどのようにコンピュータで表すのでしょうか?
固定小数点表記
小数を表す一つのやり方は小数点の位置を決めておく方法で固定小数点表記と呼ばれます。
例えば、先頭から1桁を整数部分、次の2桁目を小数部分と決めておきます。つまり小数点(.)は1桁目と2桁目の間だと分かります。すると01という0と1だけの表現を0.1であると判断できます。
ただこの方法は精度に問題があります。10進数で表すと例えば、先頭から5桁を整数部分、次の5桁目を小数部分と決めていた場合に3.14159265という小数は0埋めされ00003.141592となってしまい精度が失われてしまいます。そのためあまり精度がいらない数値計算では用いられるという感じでしょうか。
浮動小数点表記
浮動小数点表記の考え方は小数を整数部分が1桁(ただし0ではない)になるように小数点を移動し、x.yyyyy... × 2 ^zという形式で表そうというものです。その時にどうやってこの表現を0と1だけで表そうかと考えた時に3つの部分に分けて表記しようとなりました。
3つとは、符号部、小数部(仮数部とも言います)、指数部です。
符号部というのは2進数での負の数のところで述べた符号をつけるというものです。先頭1桁を0なら正の数、1なら負の数とみなします。つまり浮動小数点表記は負の小数も扱えます。
小数部というのは先ほどの2進数の0.11では浮動小数点の考え方では1.1×2^-1となるので小数部は1です。
指数部はこの場合は2^-1なので-1ですね。
固定小数点表記とは違い小数点の位置は指数部によって後から決まります。
IEEE 754 浮動小数点規格
符号部、小数部、指数部という3つの部分に分けて表現するのは分かったのですが、その3つの部分の並び順は?それぞれの部分は何ビット(0か1の一桁のことを1ビットと言います)になるの?と疑問に思うのですがそれを決めた規格の1つで広く普及しているのがIEEE 754 浮動小数点規格です。単精度浮動小数点規格と倍精度浮動小数点規格の2つの形式が定められています。
ここでは2進数の0.011を単精度浮動小数点規格で表現してみたいと思います。
単精度浮動小数点規格は小数を32ビットで表現します。つまり0か1のどちらかが32個並びます。
符号に先頭1ビット、次の8ビットが指数、次の23ビットが小数部です。
まず正の小数なので先頭1ビットは0ですね。
指数部は少し複雑で「-2」なので「-2」にバイアスの「127」を加算します。指数部にバイアスを加算することで、負の数を含む表現が正の数だけで表現できます。
(-2)+127 = 125 この125を2進数で表して01111101になります。
0.011を正規化すると1.1×2^-2です。小数部には小数点以下の値が入ります。小数第1位から順に「上位ビット→下位ビット」の順で並べるだけです。足りない部分は0で埋めます。
よって以下の画像のようになります。
00111110110000000000000000000000

このような形式で2進数の0.011、10進数に直すと0.375という小数は画像のような0と1の並びで表現されます。
倍精度浮動小数点規格は32ビットではなく64ビットで表します。
commandパターン
クラスのメソッド呼び出しとその具体的な振る舞いを分離することを目的とする。
class AttackSordCommand def do attacker = AttackerSord.new attacker.attack end end
class DefenderShieldCommand def do defender = DeffenderShield .new defender.defence end end
class Yusha def initialize(attack_command, defence_command) @attack_command = attack_command @defence_command = defence_command end def kogeki @attack_command.do end def bogyo @defence_command.do end end
勇者クラスは攻撃した際にどんなことが起こるのか知りません。
その具体的なことはAttackCommandが知っています。
防御した際も同様です。
剣で攻撃だったのが槍で攻撃に代わっても勇者クラスは変更しなくてすみます。
今まで
yusha = Yusha.new(AttackSordCommand.new, DefenderShieldCommand)
だったのが
槍コマンドクラスが追加されて
class AttackSpearCommand def do attacker = AttackerSpear.new attacker.attack end end
以下のように勇者クラスの生成方法が変わるだけです。
yusha = Yusha.new(AttackSpearCommand.new, DefenderShieldCommand)
stateパターン
状態を表すクラス
例えば活性状態(Activate)、非活性状態(Deactivate)があるとする。
その時の振る舞いをそのクラスに実装する
class Activate def get_color "yellow" end def change_state(is_avtive) return self if is_active Deactive.new end end
class Deactivate def get_color "grey" end def change_state(is_avtive) return self if !is_active Active.new end end
class Button def initialize @is_avtive = true @state = Deactivate.new end def color @state.get_color end def click @state = @state.change_state(!@is_active) end end
Ruby オブジェクト指向 メモ
オブジェクト指向で意識すること
- インスタンス変数はアクセサメソッドで提供するようにする。
- クラスの中で他のクラスをnewするのは出来るだけ避ける。
- 依存関係の逆転
インスタンス変数はアクセサメソッドで提供するようにする。
class Human def initialize(name) @name = name end def name @name end end hoge = Human.new('tarou') puts hoge.name
上のようにアクセサで提供する。いろんな場所でhuman.nameと使われているときに例えばnameメソッドだけ変更 すればよくて済む。rubyならattr_reader使えばよい。
クラスの中で他のクラスをnewするのは出来るだけ避ける。
あるオブジェクトの中でnewするとそのクラスと強い結合が生まれてしまう。 出来ることなら依存オブジェクトの注入(DI)をする。これをすることで注入されたオブジェクトが何であるかには依存しなくなり、注入されたオブジェクトのインターフェースにのみ依存するようになる。ただ、色々理由でDI出来ないこともよくある。その場合は以下のように出来るだけ隔離し依存を明らかにしておく。
class Gear def initialize(chainring, cog, rim, tire) @chainring = chainring @cog = cog @rim = rim @tire = tire end def gear_inches ratio*wheel.diameter end def wheel @wheel ||= Wheel.new(rim, tire) end end
ここからさらにgear_inchesメソッドが複雑化した場合は
def gear_inches #ここがかなり複雑化する ratio*diameter end def diameter @wheel.diameter end
このように外部メッセージを隔離し、依存を明らかにしておく。 この変更により外部メッセージである@wheel.diameterに依存していたgear_inchesは 自身のメソッドであるdiameterに依存するようになり、外部への依存を取り除けた。 仮にwheelクラスがdiameterメソッドの名前を変更したりした場合でも副作用はこのシンプルな ラッパーメソッドだけで済む。この副作用を駆逐するために最初から問題を避ける依存関係逆転というテクがある。
依存関係の逆転
class Gear attr_reader :chainring, :cog def initialize(chainring, cog) @chainring = chainring @cog = cog end def gear_inches(diameter) ratio*diameter end def ratio chainring / cog.to_f end end class Weel attr_reader :rim, :tire, :gear def initialize(rim, tire, chainring, cog) @rim = rim @tire = tire @gear = Gear.new(chainring, cog) end def diameter rim + (tire*2) end def gear_inches gear.gear_inches(diameter) end end
このように依存関係を逆転させる際はより安定したクラスに依存するようにする。 抽象的なクラスまたは、他とあまり結合していないクラスに依存させる。
デメテルの法則
必ずしも守る必要はない。 クラス間の結合を減らすテクニック。 たくさんドットでつなげるとその通り道のクラス全てと結合して再利用が難しいクラスになってしまう。
class LawOfDemeterExample def initialize @another_class = AnotherClass.new end #自身が直接アクセスできるメソッドはOK def sample_method_following_demeter(obj) my_method#オブジェクトO自身のメソッドは呼び出すことができる data1 = @another_class.get_data#呼び出し用のメソッドまたは属性として同じクラス内で宣言されたオブジェクトのメソッドは呼び出すことができる data2 = obj.get_data#メソッド「sample_method_following_demeter」の引数のメソッドは呼び出すことができる end def my_method end end class AnotherClass def get_data end end O = LawOfDemeterExample.new
メソッドsample_method_following_demeterをもつクラスLawOfDemeterExampleのインスタンスをOとすると オブジェクト指向プログラミングにデメテルの法則を適用すると、次のように解釈できる。
- オブジェクトO自身のメソッドは呼び出すことができる
- メソッド「sample_method_following_demeter」の引数のメソッドは呼び出すことができる
- メソッド「sample_method_following_demeter」の内部で生成/初期化したオブジェクトのメソッドは呼び出すことができる
- 呼び出し用のメソッドまたは属性として同じクラス内で宣言されたオブジェクトのメソッドは呼び出すことができる
- オブジェクトOがアクセスできるメソッド「sample_method_following_demeter」のスコープにある全域オブジェクトのメソッドは呼び出すことができる
JSで意識すること メモ ES6
JSで意識すること
自分用のJS扱うときに意識することメモ
- 参照のコピーとthis
- list2
- list3
- JSで意識すること
- 参照のコピーとthis
- 見出し1-1
- 見出し1-2
- 見出し1-3
- 非同期Promiseチェーン
- 見出し2-1
- 見出し3
- 見出し3-1
- 参考リンク
- 関連リンク
- 参照のコピーとthis
rubyでデザインパターン strategyパターン
strategy(戦略)パターン
戦略を切り替えるパターンです。
処理を他のクラスに委譲することを前提とし、クライアント(この例ではsorterです。)が自由にそのクラスを切り替えることが出来ます。
strategyとtemplate methodパターンの違いはこんな説明がわかりやすかったです。
Strategyの方は,全く異なるアルゴリズムごっそり差し替えるためのパターン。
一方でTemplate Methodの方は"template method"の名の通り,アルゴリズムの実行ステップを手順として規定しておいて,各ステップ内の処理をサブクラスに実装させている. Template methodは将来の実装のためのガイドとも言える。 なお実行ステップを記述するtemplate methodは当然overrideされないようにしておく.
また、継承使ったらtemplate_methodで委譲したらstrategyパターンみたいな解説もあるのでちょっと曖昧。
class SortStrategy def sort(dataset) end end class BubbleSortStrategy < SortStrategy def sort(dataset) puts "バブルソートを実行" dataset end end class QuickSortStrategy < SortStrategy def sort(dataset) puts "クイックソートを実行" dataset end end class Sorter attr_reader :sorter def initialize(sorter) @sorter = sorter end def sort(dataset) @sorter.sort(dataset) end end dataset = [1,4,5,6,6,7] sorter = Sorter.new(BubbleSortStrategy.new) sorter.sort(dataset) sorter = Sorter.new(QuickSortStrategy.new) sorter.sort(dataset)
rubyでデザインパターン builderパターン
砂糖水を作る(
ビルダ (Builder) | Ruby デザインパターン | 酒と涙とRubyとRailsと
)
こちらの写生です。
操作と手順を分離するパターンです。
factoryパターンとの大きな違いは、factoryパターンは作成が1ステップでできる場合に使うのに対し、builderパターンは作成に複数のステップを踏む場合に使う点。
class SugarWater attr_accessor :water, :sugar def initialize(water, sugar) @water = water @sugar = sugar end end class SugarWaterBuilder def initialize @sugar_water = SugarWater.new(0,0) end def add_sugar(sugar_amount) @sugar_water.sugar += sugar_amount end def add_water(water_amount) @sugar_water.water += water_amount end def result @sugar_water end end class Director def initialize(builder) @builder = builder end def cook @builder.add_water(150) @builder.add_sugar(90) @builder.add_water(300) @builder.add_sugar(35) end end builder = SugarWaterBuilder.new director = Director.new(builder) director.cook p builder.result ####################別の例##################### class Burger attr_reader :size, :cheese, :lettuce, :tomato, :pepperoni def initialize(builder) @size = builder.size @cheese = builder.cheese @lettuce = builder.lettuce @tomato = builder.tomato end end class BurgerBuilder attr_reader :size, :cheese, :lettuce, :tomato, :pepperoni def initialize(size) @size = size end def addPepperoni @pepperoni = true end def addLettuce @lettuce = true end def addCheese @cheese = true end def addTomato @tomato = true end def build Burger.new(self) end end burgar = BurgerBuilder.new(14) burgar.addTomato burgar.addCheese tomato_cheese_burgar = burgar.build p tomato_cheese_burgar