Working with the set of real numbers

Dave Angel davea at davea.name
Wed Mar 5 13:57:49 CET 2014


 Oscar Benjamin <oscar.j.benjamin at gmail.com> Wrote in message:
> On 4 March 2014 23:20, Dave Angel <davea at davea.name> wrote:
>>
>> One problem with complexity claims is that it's easy to miss some
>>  contributing time eaters. I haven't done any measuring on modern
>>  machines nor in python, but I'd assume that multiplies take
>>  *much* longer for large integers, and that divides are much
>>  worse. So counting iterations isn't the whole story.
> 
> Agreed but there's a big difference between log(N) iterations and N iterations!
> 
>> On the assumption that division by 2 is very fast,  and that a
>>  general multiply isn't too bad, you could improve on Newton by
>>  observing that the slope is 2.
>>
>>    err = n - guess * guess
>>     guess += err/2
> 
> I gues you mean like this:
> 
> def sqrt(n):
>     err = guess = 1
>     while err > 1e-10:
>         err = n - guess * guess
>         guess += err/2
>     return guess
> 
> This requires log2(10)*N iterations to get N digits. 

No idea how you came up with that,  but I see an error in my
 stated algorithm,  which does surely penalize it. The slope isn't
 2, but 2x.  So the line should have been
        guess += err/(2*guess)

Now if you stop the loop after 3 iterations (or use some other
 approach to get a low-precision estimate,  then you can calculate
 scale = 1/(2*estimate)

and then for remaining iterations, 
        guess += err *scale

> So the penalty
> for using division would have to be extreme in order for this to
> better. Using Decimal to get many digits we can write that as:
> 
> def sqrt2(n, prec=1000):
>     '''Solve x**2 = y'''
>     eps = D(10) ** -(prec + 5)
>     err = guess = D(1)
>     with localcontext() as ctx:
>         ctx.prec = prec + 10
>         while abs(err) > eps:
>             err = n - guess*guess
>             guess += err/2
>     return guess
> 
> This method works out much slower than Newton with division at 10000
> digits: 40s (based on a single trial) vs 80ms (timeit result).

Well considering you did not special-case the divide by 2, I'm not
 surprised it's slower.

> 
>> Some 37 years ago I microcoded  a math package which included
>>  square root.  All the math was decimal, and there was no hardware
>>  multiply or divide. The algorithm I came up with generated the
>>  answer one digit at a time, with no subsequent rounding needed.
>>  And it took just a little less time than two divides. For that
>>  architecture,  Newton's method would've been too
>>  slow.
> 
> If you're working with a fixed small precision then it might be.
> 
>> Incidentally, the algorithm did no divides, not even by 2. No
>>  multiplies either.  Just repeated subtraction,  sorta like divide
>>  was done.
>>
>> If anyone is curious,  I'll be glad to describe the algorithm;
>>  I've never seen it published, before or since.  I got my
>>  inspiration from a method used in mechanical,  non-motorized,
>>  adding machines.  My father had shown me that approach in the
>>  50's.
> 
> I'm curious.
> 

A later message,  I guess.  I can't write that much on the tablet.


-- 
DaveA




More information about the Python-list mailing list