reload and work flow suggestions

Oscar Benjamin oscar.j.benjamin at gmail.com
Mon Sep 23 06:40:52 EDT 2013


On 23 September 2013 10:35, rusi <rustompmody at gmail.com> wrote:
>> Then, I launch iPython, which can intellisense launch 3 easily. Then I make
>> whatever changes I need to 1-3 to make a baby step forward, close iPython,
>> and repeat.
>
> Hardly looks very ergonomic to me

I'm not quite sure what's meant by intellisense here but using ipython
with a scratch script works very well for me.

Here's how a typical session works for writing a sqrt_floor() function
that works for all positive integers:

In [1]: import math

In [2]: math.sqrt(16)
Out[2]: 4.0

In [3]: math.sqrt(15)
Out[3]: 3.872983346207417

In [4]: int(math.sqrt(15))
Out[4]: 3

In [5]: x = 10 ** 20 + 1

In [6]: int(math.sqrt(x ** 2)) == x
Out[6]: False

In [7]: edit tmp.py

[At this point vim opens, I do some working on paper and write the
following in vim:

import math

def sqrt_floor(y):
    x = int(y)
    while x ** 2 <= y < (x+1) ** 2:
        x = (x + y // x) // 2
    return x
]

done. Executing edited code...

In [8]: sqrt_floor(100)
Out[8]: 100

In [9]: sqrt_floor(101)
Out[9]: 101

[Okay whoops! that's not what I wanted... Need to invert the condition
in the while loop!]

In [10]: edit tmp.py
 done. Executing edited code...

In [11]: edit tmp.py
 done. Executing edited code...

In [12]: sqrt_floor(101)
Out[12]: 10

In [13]: sqrt_floor(100)
Out[13]: 10

In [14]: x = 10 ** 20 + 1

In [15]: sqrt_floor(x ** 2) == x
Out[15]: True

[Okay that's better]

In [16]: edit tmp.py

[Now I'll test against a load of integers so the file looks like

import math

def sqrt_floor(y):
    x = int(y)
    while not (x ** 2 <= y < (x+1) ** 2):
        x = (x + y // x) // 2
    return x


for y in range(10 ** 6):
    x = sqrt_floor(y)
    assert x ** 2 <= y < (x+1) ** 2
]
done. Executing edited code...

[All tests have passed but it took a little while so let's time this function]

In [17]: timeit sqrt(10 ** 10)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<snip traceback>
NameError: global name 'sqrt' is not defined

In [18]: from math import sqrt

In [19]: timeit sqrt(10 ** 10)
1000000 loops, best of 3: 393 ns per loop

In [20]: timeit sqrt_floor(10 ** 10)
10000 loops, best of 3: 52.4 us per loop

In [21]: edit tmp.py

[Since sqrt is 100x faster we can use it internally to get an initial guess.
Now the file looks like:

import math

def sqrt_floor(y):
    x = int(math.sqrt(y))
    while not (x ** 2 <= y < (x+1) ** 2):
        x = (x + y // x) // 2
    return x


for y in range(10 ** 6):
    x = sqrt_floor(y)
    assert x ** 2 <= y < (x+1) ** 2
]
done. Executing edited code...

In [22]: timeit sqrt_floor(10 ** 10)
100000 loops, best of 3: 4.58 us per loop

[Great. That's 10x faster than before and probably as good as it gets
for speed but this optimisation has problems...]

In [23]: sqrt_floor(10 ** 1000)
---------------------------------------------------------------------------
OverflowError                             Traceback (most recent call last)
<ipython-input-23-378bf805089d> in <module>()
----> 1 sqrt_floor(10 ** 1000)

Q:\tmp.py in sqrt_floor(y)
      2
      3 def sqrt_floor(y):
----> 4     x = int(math.sqrt(y))
      5     while not (x ** 2 <= y < (x+1) ** 2):
      6         x = (x + y // x) // 2

OverflowError: long int too large to convert to float

In [24]: edit tmp.py

[Now the file looks like

import math

def sqrt_floor(y):
    try:
        x = int(math.sqrt(y))
    except OverflowError:
        x = y
    while not (x ** 2 <= y < (x+1) ** 2):
        x = (x + y // x) // 2
    return x


for y in range(10 ** 6):
    x = sqrt_floor(y)
    assert x ** 2 <= y < (x+1) ** 2
]

 done. Executing edited code...
[ This reruns the tests in the file; no AssertionError so all good ]

In [25]: sqrt_floor(10 ** 1000)
Out[25]: 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000L

In [26]: timeit sqrt(10 ** 10)
1000000 loops, best of 3: 381 ns per loop

And now we're basically done. Recheck the proof, think about how to
handle negative numbers, write a docstring and move on.


Oscar



More information about the Python-list mailing list