More Related Content Similar to Numeric クラスについて (20) More from Tomoya Kawanishi (20) Numeric クラスについて 2. 自己紹介 1
Ruby 暦は かれこれもう10年くらい
近況
docomo の Smartphone を中古で買いました。
mini HDMI 端子がすごい。便利♪
家のテレビにつながる
ケーブルが細いから取り回しがラク
Aeon SIM と組合せて、安価に常時接続できてしあわせ
後の勉強会予定
8月4日(土) Making Software 読書会 最終回
今回と同じ会場です
2週間後!
みんな来てください。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
3. Numeric クラスとは 2
Numeric クラスは「数」を抽象化したクラス
クラス階層
Numeric (親クラス)
Integer (整数を表す)
Fixnum (多くの環境で 31bit で表現できる値)
Bignum (Fixnum で表現できない整数)
Float (浮動小数点数)
Rational (有理数)
Ruby 1.9 以上で組み込みライブラリに
Complex (複素数)
Ruby 1.9 以上で組み込みライブラリに
今回説明する範囲
Integer(Fixnum と Bignum)と Float
※ Rational とか Complex は基本的に対象外
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
4. 今日の進め方について 3
体系的に説明することが難しかったので、
クイズ形式にしました。
1トピック、1問で。
簡単なものもあれば、難しいのもあるかも。
ある程度、みなさんで考えてみてください。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
5. Rubyクイズ 問題(1)! 4
下記のコードの結果は?
p (1/2)
選択肢
A: 0 (Fixnum 型)
B: 1 (Fixnum 型)
C: (1/2) (Rational 型)
D: 0.5 (Float 型)
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
6. Rubyクイズ 解答、解説(1)! 5
答え
0 (Fixnum 型)
解説
Integer# / メソッドは、整数の除算の商を返します。
下記のコードと同じ効果があります。
(1.div 2) #=> 0
0.5 や 有理数の 1/2 を得たい場合は下記のコードを実行します
。
(1.fdiv 2) #=> 0.5
(1.0 / 2) #=> 0.5
(1 / 2.0 ) #=> 0.5
Rational(1) / 2 #=> (1/2)
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
7. Rubyクイズ (2)! 6
【問題】
下記の記述は、正しいか誤っているか?
Fixnum や Bignum では新たなメソッドを定義できない
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
8. Rubyクイズ 解答、解説(2)! 7
答え
Fixnum、Bignum にも新しいメソッド
を定義できます。
解説
たとえば、下記のように 1000 という数字を “1,000円” という文字列
に変換するメソッドを Integer クラスに定義できます。
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
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
9. Rubyクイズ (3)! 8
【問題】
下記の記述は、正しいか誤っているか?
Fixnum も Bignum も同じ値(num1 == num2)であれば、同
じオブジェクト( num1.__id__ == num2.__id__ )である。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
10. Rubyクイズ 解答、解説(3)! 9
解説
Fixnum は同じ値であれば同じオブジェクトIDとなりますが、
Bignum はたとえ同じ値でも同じオブジェクトID( num1.__id__ ==
num2.__id__ ) であるとは限りません。
10.object_id == 10.object_id #=> true
(10**10).object_id == (10**10).object_id #=> false
Fixnum は値そのものの情報が直接格納されており、メモリの他の場所を参照し
たりはしていません。
しかし、Bignum を含む多くの Ruby のオブジェクトは実際の情報はメモリの他
の場所にあります。Bignum の場合、内部的には計算するたびに新たなオブジェ
クトが生成されるため、このような挙動になります。
なお、現在の実装では Fixnum のオブジェクトIDは、下記の値になります。
オブジェクトID = ((その Fixnum の値) << 1) | 1
(理由)
内部的にオブジェクトID はポインターであり、ポインターの値は (32bit 処理系では)
必ず 4 の倍数で、奇数にはなりません。Ruby では整数値をコンパクトに表現するため、
ポインターとして使われない奇数を使ったこのような内部表現としています。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
11. Rubyクイズ (4)! 10
【問題】
下記の記述は、正しいか誤っているか?
下記の ① の計算結果は false だが、
② の計算結果は true となる。
① 10**200 == 10**200 + 1
② 10**200 == 10**200 + 1.0
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
12. 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 クラスでは同一の値として内部的に表現されます。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
13. Rubyクイズ (5)! 12
【問題】
下記の記述は、正しいか誤っているか?
下記の ① は 3 になるが、 ② は “12” になる。
①: 1 + “2”
②: “1” + 2
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
14. 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
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
15. Rubyクイズ 解答、解説(5)! 14
解説
String#coerce を定義すると、 1 + “2” を 3 にすることができます。
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
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
16. Rubyクイズ 解答、解説(5)! 15
解説
Integer#to_str を定義すると、 “1” + 2 を “12” にすることができます。
class Integer
def to_str
to_s
end
end
p(“1” + 2) #=> “12”
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
17. Rubyクイズ (6)! 16
【問題】
下記の記述は、正しいか誤っているか?
下記の ① は エラーになるが、 ② はエラーにならない。
①: 1/0
②: 1.0/0
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
18. 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
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
19. 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 などのメソッドを使っているにも関わらず必要な
分しか生成しないことにより、有限なメモリ空間で実行可能になります。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
20. 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 となる
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
21. Rubyクイズ 解答、解説(7)! 20
答え
B quo, mod = (-2.0).divmod -3
の quo は -1, mod は 1.0
解説
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 となります。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」
22. まとめ 21
小ネタ的な Numeric クラスにまつわるクイズ集でした
楽しんでもらえたら、うれしいです。
Ruby/Rails勉強会@関西 第55回 「Numeric クラスについて」