Performance question: Rational

R

Richard Cole

I've got a ruby program that's running quite slowly. I ran the profiler
to try to find out what's causing the hold up (see the profile output
below) and it looks like Integer#gcd is a culprit. My code is basically
a canvas with a bunch of canvas items and so it does some integer
computation, but somehow integers are getting converted into rationals
and then being simplified which appears to be taking up heaps of time.

Has anyone got any hints on how to keep rationals out of my program? I
want to stick to integers and floats.

regards,

Richard.


-----
% cumulative self self total
time seconds seconds calls ms/call ms/call name
2578.12 33.00 33.00 1 33000.00 33000.00
Profiler__.start_profile
21.87 33.28 0.28 72 3.89 5.97 Integer#gcd
8.59 33.39 0.11 72 1.53 7.78 Rational#reduce
8.59 33.50 0.11 144 0.76 10.28 Rational#/
7.03 33.59 0.09 146 0.62 0.89 Rational#initialize
6.25 33.67 0.08 1191 0.07 0.07 Fixnum#==
3.91 33.72 0.05 661 0.08 0.08 Fixnum#[]
3.13 33.76 0.04 582 0.07 0.07 Kernel.kind_of?
3.13 33.80 0.04 363 0.11 0.11 Fixnum#>>
3.12 33.84 0.04 326 0.12 0.21
Qt::Base#method_missing
3.12 33.88 0.04 188 0.21 0.96 Class#new
3.12 33.92 0.04 72 0.56 13.33 Fixnum#/
2.34 33.95 0.03 6 5.00 16.67
Griff::CanvasMultiText#draw
1.56 33.97 0.02 150 0.13 0.13 Fixnum#*
1.56 33.99 0.02 114 0.18 0.18
Qt::Internal.find_class
1.56 34.01 0.02 38 0.53 1.05 Qt::pen#new
1.56 34.03 0.02 364 0.05 0.05 Kernel.class
1.56 34.05 0.02 18 1.11 2.78 Griff::CanvasLine#draw
1.56 34.07 0.02 146 0.14 1.30 Rational#new!
1.56 34.09 0.02 6 3.33 21.67
Griff::CanvasConceptLabel#draw
1.56 34.11 0.02 72 0.28 8.06 Object#Rational
0.78 34.12 0.01 12 0.83 3.33
Griff::CanvasTextStyle#fashion
0.78 34.13 0.01 80 0.13 0.13 Fixnum#>
0.78 34.14 0.01 36 0.28 26.94 Griff::Rect#center
0.78 34.15 0.01 6 1.67 1.67
Griff::CanvasTextStyle#baseline
0.78 34.16 0.01 6 1.67 5.00 Range#each
0.78 34.17 0.01 218 0.05 0.05 Fixnum#<
0.78 34.18 0.01 6 1.67 1.67 Qt::Enum#initialize
0.78 34.19 0.01 6 1.67 1.67
Griff::CanvasTextStyle#left
0.78 34.20 0.01 38 0.26 0.26 Kernel.callcc
0.78 34.21 0.01 6 1.67 11.67
Griff::CanvasMultiText#drawText
0.78 34.22 0.01 8 1.25 2.50
Griff::CanvasEllipse#draw
0.00 34.22 0.00 2 0.00 0.00 Rational#to_f
0.00 34.22 0.00 38 0.00 0.26
Qt::Internal.try_initialize
0.00 34.22 0.00 6 0.00 0.00
Griff::CanvasTextStyle#margin
0.00 34.22 0.00 6 0.00 3.33 Griff::CanvasRect#draw
0.00 34.22 0.00 104 0.00 0.00 Fixnum#-
0.00 34.22 0.00 6 0.00 0.00 Qt::Integer#initialize
0.00 34.22 0.00 6 0.00 0.00
Griff::CanvasTextStyle#height
0.00 34.22 0.00 1 0.00 0.00 Array#sort
0.00 34.22 0.00 38 0.00 0.00 Kernel.method
0.00 34.22 0.00 118 0.00 0.00 Hash#[]
0.00 34.22 0.00 36 0.00 0.00
Griff::point#initialize
0.00 34.22 0.00 72 0.00 0.00 Fixnum#<<
0.00 34.22 0.00 38 0.00 1.32
Griff::CanvasRectStyle#fashion
0.00 34.22 0.00 42 0.00 0.00 Fixnum#to_f
0.00 34.22 0.00 6 0.00 0.00 Array#[]
0.00 34.22 0.00 94 0.00 0.00 Fixnum#+
0.00 34.22 0.00 6 0.00 0.00
Qt::Internal.get_qenum_type
0.00 34.22 0.00 6 0.00 1.67
Qt::painter#const_missing
0.00 34.22 0.00 2 0.00 0.00 Float#/
0.00 34.22 0.00 1 0.00 1280.00 #toplevel
0.00 34.22 0.00 6 0.00 0.00
Qt::Internal.get_qinteger
0.00 34.22 0.00 4 0.00 12.50 Griff::Layer#draw
0.00 34.22 0.00 2 0.00 0.00 Rational#coerce
0.00 34.22 0.00 38 0.00 0.00 Qt::Base#initialize
0.00 34.22 0.00 144 0.00 0.00 Fixnum#div
0.00 34.22 0.00 144 0.00 0.00 Fixnum#abs
0.00 34.22 0.00 5 0.00 18.00 Array#each
0.00 34.22 0.00 1 0.00 0.00 Hash#keys
0.00 34.22 0.00 38 0.00 0.00 Float#*
0.00 34.22 0.00 6 0.00 1.67
Qt::Internal.create_qenum
0.00 34.22 0.00 92 0.00 0.00 Float#+
 
R

Richard Cole

Brian said:
I've got a ruby program that's running quite slowly. I ran the profiler
to try to find out what's causing the hold up (see the profile output
below) and it looks like Integer#gcd is a culprit. My code is basically
a canvas with a bunch of canvas items and so it does some integer
computation, but somehow integers are getting converted into rationals
and then being simplified which appears to be taking up heaps of time.

Has anyone got any hints on how to keep rationals out of my program? I
want to stick to integers and floats.

regards,

Richard.
[snip profiler output]

well, just remove the line
require 'rational'
from your program.
I wasn't including 'rational'.

I have since discovered that rationals come from the 'mathn' library and
that library is being included by one of the libraries that I'm using. I
also found that x.div(y) produces an integer while x/y produces a
rational, so the answer is to use x.div(y) instead of x/y.

It is kind of freaky to have definition of x/y change dependent on
whether or not a library is included. One library changing the semantics
of the operations defined in another library is side effects on steroids.

irb(main):001:0> 1.div(2)
=> 0
irb(main):002:0> 1/2
=> 0
irb(main):003:0> require 'mathn'
=> true
irb(main):004:0> 1/2
=> 1/2
irb(main):005:0> 1.div(2)
=> 0

So there are three safe combinations (mathn,/), (mathn,div) (none,div)
and one unsafe combination (none,/). It is a pitty that the unsafe
combination is the first one that a nieve programmer would go for. Maybe
this can be cleaned up in the Ruby 2.0?

regards,

Richard.
 
G

gabriele renzi

Richard Cole ha scritto:
It is kind of freaky to have definition of x/y change dependent on
whether or not a library is included. One library changing the semantics
of the operations defined in another library is side effects on steroids.

yes, and we love that :)
The point of using rational (or complex or mathn or whatever) is that
you're slightly changing the language, so for general purpose you don't
need to support the whole world of chances but you can add them when you
really need them.
irb(main):001:0> 1.div(2)
=> 0
irb(main):002:0> 1/2
=> 0
irb(main):003:0> require 'mathn'
=> true
irb(main):004:0> 1/2
=> 1/2
irb(main):005:0> 1.div(2)
=> 0

So there are three safe combinations (mathn,/), (mathn,div) (none,div)
and one unsafe combination (none,/). It is a pitty that the unsafe
combination is the first one that a nieve programmer would go for. Maybe
this can be cleaned up in the Ruby 2.0?

see the rcr "make rational a builtin class"
http://rcrchive.net/rcr/show/260
 
T

Tim Sutherland

Richard Cole wrote: said:
I have since discovered that rationals come from the 'mathn' library and
that library is being included by one of the libraries that I'm using. I
also found that x.div(y) produces an integer while x/y produces a
rational, so the answer is to use x.div(y) instead of x/y.

It is kind of freaky to have definition of x/y change dependent on
whether or not a library is included. One library changing the semantics
of the operations defined in another library is side effects on steroids. [...]
So there are three safe combinations (mathn,/), (mathn,div) (none,div)
and one unsafe combination (none,/). It is a pitty that the unsafe
combination is the first one that a nieve programmer would go for. Maybe
this can be cleaned up in the Ruby 2.0?

Ruby 2.0 will do something with "selector namespaces" that may help here.

See http://www.rubygarden.org/ruby?Rite

The effect would be that the library you're using would be able to use
Rationals in the current way, but your own code would not be affected.
 
T

Tim Sutherland

Richard Cole ha scritto:


yes, and we love that :)
The point of using rational (or complex or mathn or whatever) is that
you're slightly changing the language, so for general purpose you don't
need to support the whole world of chances but you can add them when you
really need them.
[...]

Problem is though, the original poster didn't do require 'rational'. They
just loaded a library that happened to use rational.

What if you want to use two libraries, one of which requires a/b to be
rational, and the other requires a/b to be integer division?

Selector namespaces are exciting :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top