views:

633

answers:

4

I'm in need of an algorithm faster than the current normal python long multiplication , I tried to find a decent karatsuba implementation , but I can't.

def main():
    a=long(raw_input())
    if(a<0):
     a=a*-1
     a=((a*(a+1)/2)-1)
     print(-a)
    else:
     a=(a*(a+1))/2
     print(a)
main()

As you see , it's nothing complicated , just a few multiplications but it has to handle numbers with up to 100000 digits under 2.5 sec.

I'd like some snipet of a function or just a link to some implementation of a faster multiplication function , or anything that helps.

Thanks in advance.

+3  A: 

I suggest you get the Sage math tool, which has just about every Python math tool ever made rolled into one package. See if there is a nice fast arbitrary precision math tool in Sage that meets your needs.

steveha
Thanks for the answer , but the problem is that I need some direct implementation , no libraries - that means I need the function to be able to take 2 longs and return a third one in time. I took a look at the Toom-Cook multiplication algorithm , but I can't find an adequate implementation.
Nedim
@Nedim: Ummm no libraries, so if you find an "adequate" implementation of a different algorithm, you are going to hack your version of Python?? How much time do you imagine a call to a library routine would take?
John Machin
Actually I don't know , I just want something like a function inside my main script/program. I don't code often in Python , I did like 10-20 programs so far and mostly short ones to calculate stuff , I mainly code in C/C++ so I don't really know what to expect from python. I used python because of the convenience of bigints.
Nedim
@Nedim: If you don't know, then don't cheese people off by rejecting their suggestions of libraries. "Something like a function inside ..." would need to be written in Python, and you are concerned about the speed of the built-in long multiplication that is written in C???
John Machin
Yes , exactly , but built-in functions are not always the fastest ones , they are mostly better than anything most people would hand code but there's always a better and faster , more efficient solution to every algorithmic problem , and this program was simple and efficient for most cases , but not for mine.Also , a good algorithm will always beat a fast language in terms of speed.And I had to have something guide me to implement my own algo in python in a single source file because it was used for a local grader on my computer.
Nedim
Sorry, your last sentence can best be described as bafflegab. Are you saying that you already have "your own algo in python" which is faster than the built-in long multiplication? What is the "something" which guided you? What is a "local grader"?
John Machin
@Nedim, I love Python, but it is in fact slower than C code. It is simply not possible to write a pure Python function to do an arbitrary-precision multiply, and have that function be faster than a C version of the same function. The built-in arbitrary-precision integer code in Python is probably about as good as you can get already, but there is some chance that an external math module (written in C) might have a function that better suits your needs. I repeat, it is *not possible* for you to write a faster function in pure Python.
steveha
@Nedim, just to be clear: a pure Python function with a good algorithm can beat C code with a bad algorithm. But why do you assume that the built-in arbitrary precision integer math in Python is written with a bad algorithm? And even if there is some other algorithm that would suit your needs better, you will likely be able to find a loadable module, written in C, that implements that algorithm (which is why I referred you to Sage). Unless there is a really amazing algorithm out there, that somehow nobody ever made a C module for Python yet, you will not beat C code with pure Python code.
steveha
+1  A: 

You could have a look at the implementation of the DecInt module (pure Python version is available (Toom-Cook) although the fastest it will probably be when using gmpy).

ChristopheD
Thans , i copied the whole library in my code , tweaked it a bit to reduce the size so it fits in 64 kB and viola it works :D
Nedim
If those algorithms are faster, why aren't they implemented in python?
Georg
@Nedim: "copied the whole library into my code"? "reduce the size so it [what?] fits in 64 kB"? "viola"? You are indeed sui generis :-)
John Machin
+7  A: 

15.9 ms on my slow notebook. It is the print that is slowing you down. Converting to binary numbers to decimal is quite slow, which is a required step of printing it out. If you need to output the number you should try the DecInt ChristopheD mentioned already.

DecInt will be slower doing the multiply but make the print much faster

In [34]: a=2**333000

In [35]: len(str(a))
Out[35]: 100243

In [36]: b=2**333001

In [37]: len(str(b))
Out[37]: 100244

In [38]: timeit c=a*b
10 loops, best of 3: 15.9 ms per loop

Here is an example with a slightly modified version of your code. Note that converting a 100000 digit string to a long already takes ~1sec on this computer

In [1]: def f(a):
   ...:     if(a<0):
   ...:         a=a*-1
   ...:         a=((a*(a+1)/2)-1)
   ...:     else:
   ...:         a=(a*(a+1))/2
   ...:     return a
   ...: 

In [2]: a=3**200000

In [3]: len(str(a))
Out[3]: 95425

In [4]: timeit f(a)
10 loops, best of 3: 417 ms per loop
gnibbler
Do you know any faster way of printing the results to the console ?
Nedim
+1: for actually measuring the performance *before* trying to optimize
J.F. Sebastian
@Nedim: computers speak binary. you can convert binary to and from hexidecimal very simply and quickly ( 4 bits at a time ). There is no shortcut like that for converting to and from decimal, so it is much slower. If you can get away with using hex for the input and output, you don't need any of those slow decimal conversions
gnibbler
Thanks , I know that as I'm not really new to the world of programming I just never used Python before , this is the first time I actively used functions in python.And I'm forced to print it out in decimal.
Nedim
+6  A: 

I'm the author of the DecInt (Decimal Integer) library so I'll make a few comments.

The DecInt library was specifically designed to work with very large integers that needed to be converted to decimal format. The problem with converting to decimal format is that most arbitrary-precision libraries store values in binary. This is fastest and most efficient for utilizing memory but converting from binary to decimal is usually slow. Python's binary to decimal conversion uses an O(n^2) algorithm and gets slow very quickly.

DecInt uses a large decimal radix (usually 10^250) and stores the very large number in blocks of 250 digits. Converting a very large number to decimal format now runs in O(n).

Naive, or grade school, multiplication has a running time of O(n^2). Python uses Karatsuba multiplication which has running time of O(n^1.585). DecInt uses a combination of Karatsuba, Toom-Cook, and Nussbaumer convolution to get a running time of O(n*ln(n)).

Even though DecInt has much higher overhead, the combination of O(n*ln(n)) multiplication and O(n) conversion will eventually be faster than Python's O(n^1.585) multiplication and O(n^2) conversion.

Since most computations don't require every result to be displayed in decimal format, almost every arbitrary-precision library uses binary since that makes the computations easier. DecInt targets a very small niche. For large enough numbers, DecInt will be faster for multiplication and division than native Python. But if you are after pure performance, a library like GMPY will be the fastest.

I'm glad you found DecInt helpful.

casevh