Opened 12 years ago

Closed 5 years ago

#11332 closed defect (wontfix)

65x penalty in performance for using float instead of RealNumber

Reported by: Pablo Angulo Owned by: Burcin Erocal
Priority: major Milestone: sage-duplicate/invalid/wontfix
Component: symbolics Keywords: float, RealNumber
Cc: Merged in:
Authors: Reviewers: Maarten Derickx
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description

The function random() returns a "float", but 1.0*random() is a "RealNumber?". The following code:

%time
#1
N=5000
x=random()
for c in xrange(N):
    kk = exp(x)

takes 5.24 seconds, while

%time
#1
N=5000
x=random()*1.0
for c in xrange(N):
    kk = exp(x)

takes 0.08

Change History (15)

comment:1 Changed 12 years ago by Pablo Angulo

It's a bit worse:

x=random()
timeit('exp(x)')

125 loops, best of 3: 7.88 ms per loop

while

x=random()*1.0
timeit('exp(x)')

625 loops, best of 3: 48.3 µs per loop

so the ratio is rather around 150x.

comment:2 Changed 12 years ago by Nils Bruin

note that "float" is the standard python float type, whereas RealNumber? is a preferred type for sage. Furthermore, "exp" is a general sage function that can do all kinds of "exponentiation" (symbolic, numeric etc.), and that incurs overhead. Apparently a particularly bad one for "float" types. Setting the base line:

sage: x=random()
sage: y=RealNumber(x)
sage: z=RDF(x)
sage: timeit('exp(x)')
625 loops, best of 3: 1.15 ms per loop
sage: timeit('exp(y)')
625 loops, best of 3: 10.3 µs per loop
sage: timeit('exp(z)')
625 loops, best of 3: 3.52 µs per loop

Using python's own "exp" is the fastest:

sage: timeit('math.exp(x)')
625 loops, best of 3: 373 ns per loop

You can shave off some time from the RealNumber? one too by calling a method specific for it. It's slower, but RealNumber? has much more functionality (also multiprecision)

sage: timeit('y.exp()')
625 loops, best of 3: 6.28 µs per loop

RDF is supposed to be Sage's version of "double precision floats" and is indeed comparable:

sage: timeit('z.exp()')
625 loops, best of 3: 704 ns per loop

If you don't mind a float, math.exp seems to receive a fairly efficiently coerced float from either RealNumber? or RDF

sage: timeit('math.exp(y)')
625 loops, best of 3: 510 ns per loop
sage: timeit('math.exp(z)')
625 loops, best of 3: 419 ns per loop

It would be nice if the generic "exp" would find a bit faster codepaths for some of these types, but I wouldn't consider the current behaviour a "defect".

comment:3 Changed 9 years ago by Jeroen Demeyer

Milestone: sage-5.11sage-5.12

comment:4 Changed 9 years ago by For batch modifications

Milestone: sage-6.1sage-6.2

comment:5 Changed 9 years ago by For batch modifications

Milestone: sage-6.2sage-6.3

comment:6 Changed 8 years ago by For batch modifications

Milestone: sage-6.3sage-6.4

comment:7 Changed 8 years ago by Jeroen Demeyer

Component: performancesymbolics
Owner: changed from tbd to Burcin Erocal

comment:8 Changed 8 years ago by Marc Mezzarobba

Milestone: sage-6.4sage-duplicate/invalid/wontfix
Status: newneeds_review

Fixed?

sage: sage: x=random()
sage: sage: y=RealNumber(x)
sage: sage: z=RDF(x)
sage: sage: timeit('exp(x)')
625 loops, best of 3: 17.7 µs per loop
sage: sage: timeit('exp(y)')
625 loops, best of 3: 5.9 µs per loop
sage: sage: timeit('exp(z)')
625 loops, best of 3: 2.29 µs per loop

comment:9 in reply to:  8 Changed 8 years ago by Vincent Delecroix

Replying to mmezzarobba:

Fixed?

sage: sage: x=random()
sage: sage: y=RealNumber(x)
sage: sage: z=RDF(x)
sage: sage: timeit('exp(x)')
625 loops, best of 3: 17.7 µs per loop
sage: sage: timeit('exp(y)')
625 loops, best of 3: 5.9 µs per loop
sage: sage: timeit('exp(z)')
625 loops, best of 3: 2.29 µs per loop

Half

sage: x = random()
sage: timeit('exp(x)', number=50000)
50000 loops, best of 3: 8.15 µs per loop
sage: from math import exp as math_exp
sage: timeit('math_exp(x)', number=50000)
50000 loops, best of 3: 290 ns per loop

just 30x slower. Better than the 65x that was reported for the difference between float and RR.

comment:10 Changed 8 years ago by Jeroen Demeyer

92x on my system:

sage: timeit('exp(x)', number=100000, repeat=10)
100000 loops, best of 10: 8.55 µs per loop
sage: timeit('math_exp(x)', number=100000, repeat=10)
100000 loops, best of 10: 92.1 ns per loop

comment:11 Changed 8 years ago by Marc Mezzarobba

Wait, what exactly are we trying to measure? I thought this ticket was about the overhead of exp() (I mean sage.functions.log.exp) for some argument types. If we allow ourselves to call the “right” function or method for each type, then both RDF(x).exp() and math.exp(x) are fast when applicable.

comment:12 Changed 8 years ago by Vincent Delecroix

Status: needs_reviewneeds_info

Agreed that it is not exactly the same issue... but still there is a problem for exp being very slow. So we can either open a new ticket for that slightly similar issue or precise the issue here.

comment:13 Changed 6 years ago by Ralf Stephan

Status: needs_infoneeds_review

I think there was progress from https://github.com/pynac/pynac/issues/108

I don't think you can get better than a few µs for symbolic exp(), there is too much overhead from symbolic/function.pyx even for GinacFunctions.

comment:14 Changed 5 years ago by Maarten Derickx

Reviewers: Maarten Derickx
Status: needs_reviewpositive_review

I agree that the original problem is fixed.

comment:15 Changed 5 years ago by Erik Bray

Resolution: wontfix
Status: positive_reviewclosed
Note: See TracTickets for help on using tickets.