46
詳解! Decimal 筑波大学情報科学類科目等履修生・Tsukuba.rb 斎藤ただし

詳解! Decimal

Embed Size (px)

Citation preview

Page 1: 詳解! Decimal

詳解! Decimal

筑波大学情報科学類科目等履修生・Tsukuba.rb

斎藤ただし

Page 2: 詳解! Decimal

群馬  栃木  茨城

非常に軽い自己紹介

←ぎだがんどぅ→

1 2なう!

Page 3: 詳解! Decimal

感慨深い

Page 4: 詳解! Decimal

多倍長十進小数演算ライブラリ

Decimal

Page 5: 詳解! Decimal

decimal.rubyforge.org

Decimalとは何か?● 斎藤が書き起こしたプロダクト● 多倍長十進小数演算ライブラリ

● ふつうの小数を好きな長さだけ計算できる● 組み込みのFloatを補う

● Ruby標準添付ライブラリBigDecimalの後継を目指す● シンプル・高速・使いやすい・正確

Page 6: 詳解! Decimal

decimal.rubyforge.org

Floatは不正確! (1/2)

● 超FAQ x = 0.0 10.times { x += 0.1 } x == 1.0 #=> false!?

● 何度「バグ報告」されてるか分からない● 例えば

http://redmine.ruby-lang.org/issues/show/4394● “Learn floating point numbers. What Every

Computer Scientist Should Know About Floating-Point Arithmetic ...” by @nalsh

Page 7: 詳解! Decimal

decimal.rubyforge.org

Floatは不正確! (2/2)

● 10進小数が有限桁の2進小数で表現できる条件 by @mrkn● http://d.hatena.ne.jp/mrkn/20110223

● n 桁の10進小数は、それを10m倍して5nの倍数にできるような自然数m≧nが存在するとき、有限桁の2進小数で表現できる

● 0.1は、0.1 * 10 = 1 が 51 の倍数ではないので有限桁の2進小数で表現できない

● → 十進小数演算ライブラリの存在意義

Page 8: 詳解! Decimal

decimal.rubyforge.org

Decimalとは何でないか?● 無限の長さの小数を計算

● 「1 / 3」の結果は正確に保持できない● 桁数が有限なのはFloatと一緒、あくまでも「可能な限りの(任意の)長さ」

● BigDecimalができない事ができる画期的なもの● あくまでより良い再発明

Page 9: 詳解! Decimal

decimal.rubyforge.org

ちょっと俺の身の上話を聞いてくださいよ

っていうか何でそんなことやってるの?

Page 10: 詳解! Decimal

decimal.rubyforge.org

π

Page 11: 詳解! Decimal

decimal.rubyforge.org

小学生

● 5年生の授業参観日、算数● 円周率 π に出会う (人生初の無理数)

● 先生「…という風に、ずっとに続いていきます。」

● 俺「全部調べた事もないのに、なんで分かるの?」

● 先生「大きくなったら、スウガクを勉強してください。」

Page 12: 詳解! Decimal

decimal.rubyforge.org

「大きくなったら、スウガクを勉強してください。」

Page 13: 詳解! Decimal

decimal.rubyforge.org

根に持ってしまった。

Page 14: 詳解! Decimal

decimal.rubyforge.org

中学生● C言語に出会う● 当然 π を計算!

● ……あれ?

● 何百桁も計算してるはずなのに出てこない● ていうか途中から間違ってるし

● C言語の小数は「固定長」だった!

● 代わりに「多倍長整数」に出会う● 手元で実装したり

Page 15: 詳解! Decimal

decimal.rubyforge.org

高校生

● 多倍長「整数」の計算に必要な数式を組み立てては崩し

● 「いくらでも長い整数」が扱えれば「いくらでも長い小数」も扱えるんじゃ?

● AO入試で逆質問● 先生「んなの簡単」● 俺「???」

● Rubyに出会う (Ruby本の出る出る詐欺未遂事件)

Page 16: 詳解! Decimal

decimal.rubyforge.org

大学生

● Rubyにちょっかいを出し始める● 1.8リリース、標準添付ライブラリ拡大路線● BigDecimalが飛び込んできた!!!

● ソースを読んだり、数式で悩んだり● ようやく「いくらでも長い小数」を計算できる原理を理解

Page 17: 詳解! Decimal

decimal.rubyforge.org

BigDecimalのAPIにちょっかい

● 2003年、1.8.0リリースの直前● 前身のBigFloatとは違う性質● なのに代わり映えしないAPI(メソッド群)

● Numeric全般も気にしないオレオレAPI

● →だいぶ変えてもらいました● →まだ不満● →ほぼそのまま現在に至る(1.9.2)

Page 18: 詳解! Decimal

decimal.rubyforge.org

身の上をまとめると

● π を計算したかった● BigDecimalには不満があった● →なら新しく作っちゃえばいいじゃない● = Decimal !

● Decimal::Math.pi(n) #=> 小数点以下n桁のπ!

Page 19: 詳解! Decimal

decimal.rubyforge.org

Decimal設計上の工夫

Page 20: 詳解! Decimal

decimal.rubyforge.org

設計上の工夫

● APIは最小限に● 既存クラスとの親和性を高く● 厳密さを保つ

Page 21: 詳解! Decimal

decimal.rubyforge.org

APIは最小限に

● オレオレAPIはいらない● クラスメソッド5個、インスタンスメソッド13個減

● 「多倍長」「十進」を生かすものは残す● d = Decimal(“1.23”)

d.round(1, :up) #=> Decimal(1.3)

● 必要になったら後から入れる● 後から「消す」のは大変だよね

Page 22: 詳解! Decimal

decimal.rubyforge.org

既存クラスとの親和性を高く● Rubyの数なんだからNumeric

● 「小数」なんだから「だいたいFloat」● Float・他のNumericのメソッドと同じ名前では同じ動作

● Floatを返すMath.functionもDecimal::Math.functionとして実装● sinとかsqrtとかlogとか● Floatと違い、何桁でも計算できます

Page 23: 詳解! Decimal

decimal.rubyforge.org

厳密さを保つ

● BigDecimalはFloatとの「自然な」演算が有効● BigDecimal(“1.23”) + 0.1 #=> 通っちゃう…不正確!

● Decimalはプログラマが精度を明示しない限り厳密さを保つ

● Floatとの演算を軒並みエラーに● 不正確さを明示● どうしても一緒にしたいときはDecimal#to_fしてください

Page 24: 詳解! Decimal

decimal.rubyforge.org

Decimal実装上の工夫

Page 25: 詳解! Decimal

decimal.rubyforge.org

実装上の工夫

● コード再利用● 省メモリ

Page 26: 詳解! Decimal

decimal.rubyforge.org

その前に「多倍長十進小数」の

内部構造の復習

Page 27: 詳解! Decimal

decimal.rubyforge.org

RubyKaigi2009…

Page 28: 詳解! Decimal

そもそも

Page 29: 詳解! Decimal

小数は整数の組で表せる

Page 30: 詳解! Decimal

3.14

Page 31: 詳解! Decimal

(314, 2)

Page 32: 詳解! Decimal

「314」の「下から2桁目」

に小数点

Page 33: 詳解! Decimal

3.14

Page 34: 詳解! Decimal

もっと長い小数でも

Page 35: 詳解! Decimal

3.14159265358979

Page 36: 詳解! Decimal

(314159265358979, 14)

Page 37: 詳解! Decimal

(大きい整数, 小さい整数)

Page 38: 詳解! Decimal

小数の計算≒

整数の計算

Page 39: 詳解! Decimal

decimal.rubyforge.org

復習終わり

Page 40: 詳解! Decimal

decimal.rubyforge.org

実装上の工夫

● コード再利用● 省メモリ

Page 41: 詳解! Decimal

decimal.rubyforge.org

コード再利用 (1/2)● BigDecimalは「大きい整数」を自前で実装● それってBignumでよくない?

● →やったらあっさりできた● C API: rb_big_plus(), rb_big_mul(), …

● 135,334 バイト (BigDecimal)vs 59,706 バイト (Decimal)● 55%以上の小型化

● しかも速いし (e.g. 1.9.1 → 1.9.2)

Page 42: 詳解! Decimal

decimal.rubyforge.org

コード再利用 (2/2)

● つまり● 実装のコンパクト化● 高速化

● 同時に達成!● B-)

Page 43: 詳解! Decimal

decimal.rubyforge.org

省メモリ (1/2)

● BigDecimal インスタンス本体

typedef struct { VALUE obj; U_LONG MaxPrec; U_LONG Prec; S_INT exponent; short sign; short flag; U_LONG frac[1];} Real;

← いらない

Page 44: 詳解! Decimal

decimal.rubyforge.org

省メモリ (2/2)

● 我がDecimal インスタンス本体

● スッキリ!

typedef struct { VALUE inum; long scale;} Decimal;

Page 45: 詳解! Decimal

decimal.rubyforge.org

という感じで● いろいろがんばりました● Ruby Summer of Codeに採択&完走、賞金$5000!

● /(^o^)\

Page 46: 詳解! Decimal

decimal.rubyforge.org

まとめ

● Decimalはふつうの小数をふつうに計算するためのライブラリです

● 既存のBigDecimalよりおいしいです (^p^

● 使ってやってください m(_ _)m