このページは https://speakerdeck.com/mrkn/float-is-legacy の内容を掲載しています。

掲載を希望されないスライド著者の方は、こちらよりご連絡下さい。

約5年前 (2011/10/01)にアップロードinテクノロジー

My presentation in RubyConf 2011.

You can see the description at http://rubyconf.org/presentatio...

My presentation in RubyConf 2011.

You can see the description at http://rubyconf.org/presentations/33

You can get the implementation proposed this presentation from https://github.com/mrkn/ruby/tree/decimal_rational_implementation

- Float is Legacy

Kenta Murata

RubyConf 2011

Monday, October 10, 11

1 - Kenta Murata

@mrkn

CRuby committer

bigdecimal maintainer

OS X platform maintainer

Interested in number system

http://www.flickr.com/photos/recompile_net/5951998279/

Monday, October 10, 11

2 - Kenta Murata

@mrkn

CRuby committer

bigdecimal maintainer

OS X platform maintainer

Interested in number system

Ruby Sapporo

http://www.flickr.com/photos/recompile_net/5951998279/

Monday, October 10, 11

4 - The RubyKaigi is finished.

Monday, October 10, 11

7 - Regional RubyKaigi is continue.

Monday, October 10, 11

8 - Sapporo RubyKaigi 04

in the next summer.

Monday, October 10, 11

9 - Official information

will be coming soon.

Monday, October 10, 11

10 - Float is Legacy

Kenta Murata

RubyConf 2011

Monday, October 10, 11

12 - Summary

Float requires us the advanced knowledge

Most rubyists don’t need Float

Rational is enough for us

Literal of decimal fraction interpreted as Rational

makes us more happy

Monday, October 10, 11

13 - Float class

Monday, October 10, 11

14 - What is Float class?

A wrapper for C double.

Boxing a value of double.

Need to allocate an object to generate a new

Float.

Monday, October 10, 11

15 - Do you know C double?

Floating point number with double precision.

No concrete representation is specified.

Most current platforms employ IEEE754.

It is IEEE754 binary64 on these platforms.

There are platforms employing other spec.

Monday, October 10, 11

16 - CRuby and JIS Ruby

Not requiring IEEE754.

Monday, October 10, 11

17 - Floating point numbers

Monday, October 10, 11

18 - The origin

NA = +6.022 141 79 ⇥ 1023 (±0.000 000 0030 ⇥ 1023) [1/mol]

h = +6.626 069 57 ⇥ 10 34 (±0.000 000 0029 ⇥ 10 34) [J s]

Monday, October 10, 11

19 - The origin

NA = +6.022 141 79 ⇥ 1023 (±0.000 000 0030 ⇥ 1023) [1/mol]

h = +6.626 069 57 ⇥ 10 34 (±0.000 000 0029 ⇥ 10 34) [J s]

sign

Monday, October 10, 11

19 - The origin

NA = +6.022 141 79 ⇥ 1023 (±0.000 000 0030 ⇥ 1023) [1/mol]

h = +6.626 069 57 ⇥ 10 34 (±0.000 000 0029 ⇥ 10 34) [J s]

fraction part

sign

Monday, October 10, 11

19 - The origin

NA = +6.022 141 79 ⇥ 1023 (±0.000 000 0030 ⇥ 1023) [1/mol]

h = +6.626 069 57 ⇥ 10 34 (±0.000 000 0029 ⇥ 10 34) [J s]

exponent part

fraction part

sign

Monday, October 10, 11

19 - The origin

NA = +6.022 141 79 ⇥ 1023 (±0.000 000 0030 ⇥ 1023) [1/mol]

h = +6.626 069 57 ⇥ 10 34 (±0.000 000 0029 ⇥ 10 34) [J s]

exponent part: emin e q emax

fraction part: 0 f Bn 1

sign: s 2 {0, 1}

Monday, October 10, 11

20 - Floating point numbers

Numbers can be identified by (s, e, f ).

Represent approximation of real numbers.

Float types can be described by B, N, q, emin, and emax.

B is the base number of the exponent part.

N is the number of digits in the fraction part.

q is the bias for the exponent part.

emax and emin specify the limit of the exponent part.

Monday, October 10, 11

21 - f

(s, e, f ) = ( 1)s ⇥

⇥ Be q

BN

Monday, October 10, 11

22 - e.g. IEEE754 binary64

B = 2

The maximum positive:

1.797 693 134 862 315 7 ×10+308

N = 53

q = 1,023

The minimum nonzero positive:

2.225 073 858 507 201 4 ×10–308

emin = –1,022

emax = +1,023

Monday, October 10, 11

23 - f

(s, e, f ) = ( 1)s ⇥

⇥ Be q

BN

Monday, October 10, 11

24 - e.g. IEEE754 decimal64

B = 10

The maximum positive:

9.999 999 999 999 999 ×10+384

N = 16

q = 398

The minimum nonzero positive:

0.000 000 000 000 001 ×10–383

emin = –383

emax = +384

Monday, October 10, 11

25 - e.g. IBM’s double precision

B = 16

The maximum positive:

7.237 005 577 332 262 11 ×10+75

N = 56

q = 64

The minimum nonzero positive:

5.397 605 346 934 027 89 ×10–79

emin = –64

emax = +63

Monday, October 10, 11

26 - Floating point numbers

Numbers can be identified by (s, e, f ).

Represent approximation of real numbers.

Float types can be described by B, N, q, emin, and emax.

B is the base number of the exponent part.

N is the number of digits in the fraction part.

q is the bias for the exponent part.

emax and emin specify the limit of the exponent part.

Monday, October 10, 11

27 - Every float is approximation

Monday, October 10, 11

28 - Every float is approximation

–1

0

3/2

Monday, October 10, 11

28 - Every float is approximation

–1

0

3/2

{

{

{

–1.0

0.0

1.5

Monday, October 10, 11

28 - Every float is approximation

–1

0

3/2

{

{

{

–1.0

0.0

1.5

Monday, October 10, 11

28 - Every float is approximation

–1

0

3/2

{

{

{

–1.0

0.0

1.5

Monday, October 10, 11

28 - Every float is approximation

We should think:

There are no numbers represented exactly.

Floating point numbers always include errors.

Magnitude of errors depend on B, N, and e.

Monday, October 10, 11

29 - Why including errors?

Unavoidable issue from place-value notation

with finite digits rounding.

Very few values can be specified exactly.

We shouldn’t expect that a given value is exact.

Monday, October 10, 11

30 - How many decimal fractions

can be exactly represented in

the form of binary fraction?

Monday, October 10, 11

31 - Monday, October 10, 11

32 - Decimal form:

(1234)

(0.1234)

10

10 =

104

Monday, October 10, 11

32 - Decimal form:

(1234)

(0.1234)

10

10 =

104

Binary form:

(10111)

(0.10111)

2

2 =

25

Monday, October 10, 11

32 - Decimal form:

(1234)

(d

(0.1234)

10

1d2 · · · dm)10

10 =

0.d

104

1d2 · · · dm =

10m

Binary form:

(10111)

(b

(0.10111)

2

1b2 · · · bn)2

2 =

0.b

25

1b2 · · · bn =

2n

Monday, October 10, 11

32 - Decimal form:

(1234)

(d

(0.1234)

10

1d2 · · · dm)10

10 =

0.d

104

1d2 · · · dm =

10m

Binary form:

(10111)

(b

(0.10111)

2

1b2 · · · bn)2

2 =

0.b

25

1b2 · · · bn =

2n

Monday, October 10, 11

32 - (d1d2 · · · dm)10

(d

C 5m

C

=

1d2 · · · dm)10 =

=

10m

2m 5m

2m 5m

2m

Monday, October 10, 11

33 - 1.0

The ratio of inexact numbers

0.5

The ratio of exact numbers

0.0

0

5

10

15

20

25

30

The number of decimal digits

Monday, October 10, 11

34 - 1.0

The ratio of inexact numbers

0.5

The ratio of exact numbers

0.0

0

5

10

15 17

20

25

30

The number of decimal digits

Monday, October 10, 11

34 - 1.0

The ratio of inexact numbers

0.5

binary64

IEEE754

The ratio of exact numbers

0.0

0

5

10

15 17

20

25

30

The number of decimal digits

Monday, October 10, 11

34 - Decimal in Binary

A N-digit decimal notation is exactly represented in

binary notation only if its numerator divisible by 5N.

The ratio of N-digit decimal fractions exactly

represented as binary fraction is 1 / 5N.

In IEEE754 binary64, almost all numbers are inexact.

Monday, October 10, 11

35 - Floating-point arithmetics

add, sub, mul, div, sqrt, ...

These operations work with errors.

Please read detail description:

“What Every Computer Scientist Should Know

About Floating-Point Arithmetic”

Monday, October 10, 11

36 - Decimal fraction of Ruby

Monday, October 10, 11

37 - What’s the problem?

Ruby interprets literals of decimal fraction as Float

The following three numbers are Float, so they

have errors.

1.0

1.2

0.42e+12

Monday, October 10, 11

38 - The issues from Float

There are many issues about Float reported to

redmine.ruby-lang.org

They are caused by that Ruby interpretes the

literals of decimal fraction as Float, I think.

Do you know these issues?

Monday, October 10, 11

39 - Demonstration

Monday, October 10, 11

41 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4,

12.700000000000001]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.599999999999994, 73.8, 92.0,

110.19999999999999, 128.39999999999998]

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 8

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

42 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8,

The 10.1,

last 11.4,

value of the array should

be equal to the end of the range

12.700000000000001]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.599999999999994, 73.8, 92.0,

110.19999999999999, 128.39999999999998]

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 8

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

43 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

Some elements include errors

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4,

12.700000000000001]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.599999999999994, 73.8, 92.0,

110.19999999999999, 128.39999999999998]

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 8

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

44 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4,

12.700000000000001]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.599999999999994, 73.8, 92.0,

110.19999999999999, 128.39999999999998]

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 8

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

The array size is one larger than

=> [1, (96/5), (187/5), (278/5),

the corr (369/5),

ect size (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

45 - Range#step with Float

The first case

The last value of the array is not equal to the end of

the range.

The second case

Some elements include errors.

The array size is one larger than the right size.

Monday, October 10, 11

46 - Rational with decimal notation

Introducing one flag into a Rational object.

The flag represents a Rational seems which

fraction or decimal.

If the flag is true, a Rational is converted decimal

string by to_s.

Monday, October 10, 11

47 - Literal for Rational with decimal notation

Simple change for parser.

Interpreting literal of decimal fraction without exponent

as Rational with decimal notation.

Literal of decimal fraction with exponent stays on Float.

Monday, October 10, 11

48 - Demonstration

using the patched Ruby

https://github.com/mrkn/ruby/tree/decimal_rational_implementation

Monday, October 10, 11

49 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]

>> (1.0 .. 12.7).step(1.3).map(&:class)

=> [Rational, Rational, Rational, Rational, Rational, Rational,

Rational, Rational, Rational, Rational]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.6, 73.8, 92.0, 110.2]

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 7

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

50 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]

>> (1.0 .. 12.7).step(1.3).map(&:class)

=> [Rational, Rational, Rational, Rational, Rational, Rational,

Rational, Rational, Rational, Rational]

>> (1.0 ... 128.4).step(18.2).to_a

The last value of the array is equal

=> [1.0, 19.2, 37.4, 55.6,

to 73.8,

the

92.0,

end of 110.2]

the range.

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 7

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

51 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]

>> (1.0 .. 12.7).step(1.3).map(&:class)

=> [Rational, Rational, Rational, Rational, Rational, Rational,

Rational, Rational, Rational, Rational]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.6, 73.8, 92.0, 110.2]

>> (1.0 ... 128.4).step(18.2).to_a.size

All elements in the array is Rational

=> 7

rather than Float.

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

52 - $ ruby -v

ruby 1.9.4dev (2011-09-28 trunk 33354) [x86_64-darwin10.8.0]

$ irb --simple-prompt

>> (1.0 .. 12.7).step(1.3).to_a

=> [1.0, 2.3, 3.6, 4.9, 6.2, 7.5, 8.8, 10.1, 11.4, 12.7]

>> (1.0 .. 12.7).step(1.3).map(&:class)

=> [Rational, Rational, Rational, Rational, Rational, Rational,

Rational, Rational, Rational, Rational]

>> (1.0 ... 128.4).step(18.2).to_a

=> [1.0, 19.2, 37.4, 55.6, 73.8, 92.0, 110.2]

>> (1.0 ... 128.4).step(18.2).to_a.size

=> 7

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a

The result array size is correct.

=> [1, (96/5), (187/5), (278/5), (369/5), (92/1), (551/5)]

>> (1 ... 1284.quo(10)).step(182.quo(10)).to_a.size

=> 7

Monday, October 10, 11

53 - Benchmarking

Comparing Float, Rational, and C double.

Experimental environment:

MacBook Pro 15in (Mid 2010)

Core i7 2.66 GHz

Ruby 1.9.4dev (r33300) with gcc-4.2 -O3

C with llvm-gcc -O0

Monday, October 10, 11

54 - Benchmarking codes

Ruby code

https://gist.github.com/1253088

C code

https://gist.github.com/1253090

Monday, October 10, 11

55 - Based on ruby-1.9.4dev (r33300)

3 [s]

2.16

2.17

2.25 [s]

1.78

1.5 [s]

0.73

0.70

0.75 [s]

0.37

0.00777

0.00670

0.00770

0 [s]

1M additions

1M subtractions

1M multiplications

Float

Rational

C double

Monday, October 10, 11

56 - Based on ruby-1.9.4dev (r33300)

0.01 [s]

0.37

2.16

0.73

2.17

0.70

1.78

0.00777

0.00770

0.008 [s]

0.00670

0.005 [s]

0.003 [s]

0 [s]

1M additions

1M subtractions

1M multiplications

Float

Rational

C double

Monday, October 10, 11

57 - Benchmarking summary

Rational is 2-5 times slower than Float.

Float is 2-digit order slower than C double.

C is amazingly fast.

Monday, October 10, 11

58 - If you said Rational is slow,

Float isn’t as fast as your expect.

Monday, October 10, 11

59 - Rational vs Float

Monday, October 10, 11

60 - Rational vs Float

Monday, October 10, 11

61 - Rational vs Float

Exact computation is required by domains such

as finance.

Float is required by scientific computation.

Monday, October 10, 11

61 - Rational vs Float

Exact computation is required by domains such

as finance.

Float is required by scientific computation.

Other aspects indepenend of whether Rational or

Float.

Monday, October 10, 11

61 - Conclusion

Float is difficult, troublesome, and not human

oriented.

Rational is easy to understand, and human

oriented.

It makes us more happy that Ruby interprets

literal of decimal fraction as Rational.

Monday, October 10, 11

62 - Float is Legacy

Monday, October 10, 11

63