Opened 9 years ago

Closed 3 years ago

# 65x penalty in performance for using float instead of RealNumber

Reported by: Owned by: pang burcin major sage-duplicate/invalid/wontfix symbolics float, RealNumber Maarten Derickx N/A

### 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

### comment:1 Changed 9 years ago by pang

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 9 years ago by nbruin

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 7 years ago by jdemeyer

• Milestone changed from sage-5.11 to sage-5.12

### comment:4 Changed 6 years ago by vbraun_spam

• Milestone changed from sage-6.1 to sage-6.2

### comment:5 Changed 6 years ago by vbraun_spam

• Milestone changed from sage-6.2 to sage-6.3

### comment:6 Changed 6 years ago by vbraun_spam

• Milestone changed from sage-6.3 to sage-6.4

### comment:7 Changed 6 years ago by jdemeyer

• Component changed from performance to symbolics
• Owner changed from tbd to burcin

### comment:8 follow-up: ↓ 9 Changed 5 years ago by mmezzarobba

• Milestone changed from sage-6.4 to sage-duplicate/invalid/wontfix
• Status changed from new to needs_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 5 years ago by vdelecroix

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 5 years ago by jdemeyer

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 5 years ago by mmezzarobba

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 5 years ago by vdelecroix

• Status changed from needs_review to needs_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 4 years ago by rws

• Status changed from needs_info to needs_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 `GinacFunction`s.

### comment:14 Changed 3 years ago by mderickx

• Reviewers set to Maarten Derickx
• Status changed from needs_review to positive_review

I agree that the original problem is fixed.

### comment:15 Changed 3 years ago by embray

• Resolution set to wontfix
• Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.