Numeric クラスについて

23

Click here to load reader

Transcript of Numeric クラスについて

Page 1: Numeric クラスについて

Numeric クラスについて

2012/7/21

Page 2: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

1 自己紹介

Ruby 暦は かれこれもう10年くらい

近況

docomo の Smartphone を中古で買いました。

mini HDMI 端子がすごい。便利♪

家のテレビにつながる

ケーブルが細いから取り回しがラク

Aeon SIM と組合せて、安価に常時接続できてしあわせ

後の勉強会予定

8月4日(土) Making Software 読書会 最終回

今回と同じ会場です

2週間後!

みんな来てください。

Page 3: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Numeric クラスとは

Numeric クラスは「数」を抽象化したクラス

クラス階層

Numeric (親クラス)

Integer (整数を表す)

Fixnum (多くの環境で 31bit で表現できる値)

Bignum (Fixnum で表現できない整数)

Float (浮動小数点数)

Rational (有理数)

Ruby 1.9 以上で組み込みライブラリに

Complex (複素数)

Ruby 1.9 以上で組み込みライブラリに

今回説明する範囲

Integer(Fixnum と Bignum)と Float

※ Rational とか Complex は基本的に対象外

2

Page 4: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

今日の進め方について

体系的に説明することが難しかったので、 クイズ形式にしました。

1トピック、1問で。

簡単なものもあれば、難しいのもあるかも。

ある程度、みなさんで考えてみてください。

3

Page 5: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 問題(1)!

下記のコードの結果は?

選択肢

4

p (1/2)

A: 0 (Fixnum 型) B: 1 (Fixnum 型) C: (1/2) (Rational 型) D: 0.5 (Float 型)

Page 6: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(1)!

答え

解説

Integer# / メソッドは、整数の除算の商を返します。

下記のコードと同じ効果があります。

0.5 や 有理数の 1/2 を得たい場合は下記のコードを実行します。

5

0 (Fixnum 型)

(1.fdiv 2) #=> 0.5

(1.0 / 2) #=> 0.5

(1 / 2.0 ) #=> 0.5

Rational(1) / 2 #=> (1/2)

(1.div 2) #=> 0

Page 7: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ (2)!

【問題】 下記の記述は、正しいか誤っているか?

6

Fixnum や Bignum では新たなメソッドを定義できない

Page 8: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(2)!

答え

解説 たとえば、下記のように 1000 という数字を “1,000円” という文字列 に変換するメソッドを Integer クラスに定義できます。

7

Fixnum、Bignum にも新しいメソッド を定義できます。

class Integer

def tsuuka_hyouji

@re ||= /(¥d)(?=(¥d{3})+(?!¥d))/

self.to_s.gsub(@re, ‘¥1,’) + “円”

end

end

num = 10 ** 20

p num.tsuuka_hyouji

Page 9: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ (3)!

【問題】 下記の記述は、正しいか誤っているか?

8

Fixnum も Bignum も同じ値(num1 == num2)であれば、同じオブジェクト( num1.__id__ == num2.__id__ )である。

Page 10: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(3)!

解説

9

10.object_id == 10.object_id #=> true

(10**10).object_id == (10**10).object_id #=> false

Fixnum は同じ値であれば同じオブジェクトIDとなりますが、 Bignum はたとえ同じ値でも同じオブジェクトID( num1.__id__ == num2.__id__ ) であるとは限りません。

なお、現在の実装では Fixnum のオブジェクトIDは、下記の値になります。 オブジェクトID = ((その Fixnum の値) << 1) | 1 (理由) 内部的にオブジェクトID はポインターであり、ポインターの値は (32bit 処理系では) 必ず 4 の倍数で、奇数にはなりません。Ruby では整数値をコンパクトに表現するため、 ポインターとして使われない奇数を使ったこのような内部表現としています。

Fixnum は値そのものの情報が直接格納されており、メモリの他の場所を参照したりはしていません。 しかし、Bignum を含む多くの Ruby のオブジェクトは実際の情報はメモリの他の場所にあります。Bignum の場合、内部的には計算するたびに新たなオブジェクトが生成されるため、このような挙動になります。

Page 11: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ (4)!

【問題】 下記の記述は、正しいか誤っているか?

10

下記の ① の計算結果は false だが、 ② の計算結果は true となる。 ① 10**200 == 10**200 + 1

② 10**200 == 10**200 + 1.0

Page 12: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(4)!

答え

正しい記述です。

解説

11

下記の ① の計算結果は false だが、 ② の計算結果は true となる。 10**200 == 10**200 + 1

10**200 == 10**200 + 1.0

前提知識を整理します。

• Bignum は任意の整数を正確に扱うが、Float は近似値である。

• Bignum + Fixnum は Bignum であり、Bignum + Float は Float となる

• Bignum と Float を == で比較するときは Bignum を Float に変換したときに同じ値になるかで評価される。

• 浮動小数点の10進数での精度は、Float::DIG 桁(15桁)

これらの前提をもとに考えると、 この場合、10**200 に1だけ異なるような場合は、

Float クラスでは同一の値として内部的に表現されます。

Page 13: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ (5)!

【問題】 下記の記述は、正しいか誤っているか?

12

下記の ① は 3 になるが、 ② は “12” になる。 ①: 1 + “2”

②: “1” + 2

Page 14: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(5)!

答え

誤っています。

解説

13

下記の ① は 3 になるが、 ② は “12” になる。 ①: 1 + “2”

②: “1” + 2

この選択肢の ① と ② の両方とも実際にはエラーとなります。

> 1+”2”

TypeError: String can't be coerced into Fixnum

> “1”+2

TypeError: can't convert Fixnum into String

Page 15: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(5)!

解説

14

class String

def coerce(other)

coerced= case other

when Integer

self.to_i

when

self.to_f

end

return coerced, other

end

end

p(1 + “2”) #=> 3

String#coerce を定義すると、 1 + “2” を 3 にすることができます。

Page 16: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(5)!

解説

15

class Integer

def to_str

to_s

end

end

p(“1” + 2) #=> “12”

Integer#to_str を定義すると、 “1” + 2 を “12” にすることができます。

Page 17: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ (6)!

【問題】 下記の記述は、正しいか誤っているか?

16

下記の ① は エラーになるが、 ② はエラーにならない。 ①: 1/0

②: 1.0/0

Page 18: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(6)!

解説

17

下記の ① は エラーになるが、 ② はエラーにならない。 ①: 1/0

②: 1.0/0

これは正しい記述となっています。

① の場合は ZeroDivisionError となります。

② の場合は+Infinity という浮動小数点数(Float型の値)となります。

irb> 1/0

ZeroDivisionError: divided by 0

from (irb):1:in `/'

from (irb):1

irb> 1.0 /0

=> Infinity

irb> (1.0/0).class

=> Float

Page 19: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(6)!

補足

18

+Infinity は実はいろいろと便利です。特に無限リストと @yhara さん作の

Enumerable#lazy と組合せると面白いことができます。

> gem install enumerable-lazy # ruby 2.0 では標準添付

> irb

irb> require 'enumerable/lazy'

=> true

irb> infinity = 1/0.0

=> Infinity

irb> (1..infinity).lazy.map{|i| i*i}.take(5).to_a

=> [1, 4, 9, 16, 25]

(1..infinity) は 初期値(1) から Object#succ を繰り返し実行し、infinity を超えないオブジェクトを順に生成します。つまり無限に整数を生成します。

このような操作には従来であれば無限長の配列が必要ですが、

Enumerable#lazy によって map などのメソッドを使っているにも関わらず必要な分しか生成しないことにより、有限なメモリ空間で実行可能になります。

Page 20: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ (7)!

【問題】 正しい選択肢を選べ

19

quo, mod = (-2.0).divmod -3 を実行すると、 A: quo は 1、 mod は 1 となる B: quo は 1、 mod は 1.0 となる C: quo は 0、 mod は -2 となる D: quo は 0、 mod は -2.0 となる

Page 21: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

Rubyクイズ 解答、解説(7)!

答え

B

解説

20

Numeric#divmod は、除算の商と剰余を配列で返します。 たとえば、下記のような演算になります。 7.divmod(2) #=> [3, 1]

このとき、商と剰余は下記のようになります。 ・ 商(この場合の 3)は必ず整数

・ 被除数(この場合は 7) も除数(この場合は2)も整数(Integer)であれば、 剰余(この場合の1)も整数(Integer) ・ 被除数か除数のどちらかが Float であれば 剰余も Float ・ 剰余は必ず 正かゼロの値(Numeric)

quo, mod = (-2.0).divmod -3 の場合は quo は 1、 mod は -1.0 となります。

quo, mod = (-2.0).divmod -3

の quo は -1, mod は 1.0

Page 22: Numeric クラスについて

Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」

まとめ

小ネタ的な Numeric クラスにまつわるクイズ集でした

楽しんでもらえたら、うれしいです。

21

Page 23: Numeric クラスについて

22

ご清聴ありがとう

ございました