2

I am using python3 without any tailored library for some simple arithmetic. The operation that dominates computational efficiency is a multiplication of many 2048 bit values:

length=len(array)
res=1
for x in range(length):
       res=(res*int(array[x]))
       ret=res%n2

To give you an insight it takes ~3940 seconds to make 10000 multiplications moduli a number for every multiplication for an:

Intel Core i5 CPU M 560 @ 2.67GHz × 4 with 8GB of memory, running Ubuntu 12.04 32bit machine.

Would it make sense to boost it up using a library like gmpy2 or there would not be any advantage?

curious
  • 1,524
  • 6
  • 21
  • 45
  • you can write your own function / class for multiplication using strings might not be the best way – advocateofnone Feb 18 '15 at 12:57
  • What do you mean i do not understand – curious Feb 18 '15 at 12:57
  • there has to be a copy&paste error in your code. also, what is n2? –  Feb 18 '15 at 12:59
  • @hop it's a 2048 bit number – curious Feb 18 '15 at 13:00
  • You now this is not exactly the pattern for `for` loops in Python don't you? You better take a little look at the language before proceeding. And yes, for the performance case, I think it will be better using gmpy2 – jsbueno Feb 18 '15 at 13:15
  • @jsbueno "You now this is not exactly the pattern for for loops?" What do you mean? – curious Feb 18 '15 at 13:20
  • Removing the context made the answer really confusing, so I added it back. – Veedrac Feb 19 '15 at 01:48
  • 1
    @curious: that Python is designed from the beggining, in 1991, to have `for` iterating over a sequence of items, not counting up numbers, and using those numbers as indexes to the items you should want in the first place, like in C or Javascript. thus Python is optimized -both in readability and performance to use `for item in array:` and not `for x in range(len(array)): ... array[x]` – jsbueno Feb 19 '15 at 13:38
  • But keep in mind the kind of performance one gains with this native iteration construct is orders of magnitude less than what you are hitting by needing the big number calculations. The correct answer to that is indeed the one given by @nelfin bellow – jsbueno Feb 19 '15 at 13:45

1 Answers1

6

You seem to be calculating the product of all the numbers first then taking the remainder, rather than exploiting the properties of modular multiplication: a * b * c mod p == (a * b mod p) * c mod p. This takes very little time at all to multiply 10,000 2048-bit numbers modulo some n:

In [1]: import random

In [2]: array = [random.randrange(2**2048) for i in range(10000)]

In [3]: n = random.randrange(2**2048)

In [4]: prod = 1

In [5]: %%time
   ...: for e in array:
   ...:         prod *= e
   ...:         prod %= n
   ...: 
CPU times: user 210 ms, sys: 4.07 ms, total: 214 ms
Wall time: 206 ms

For you, I would suggest:

array = map(int, array)
prod = 1
for x in array:
    prod *= x
    prod %= n2
nelfin
  • 1,019
  • 7
  • 14
  • What's the difference from your last snippet code compared with mine apart from the mapping ?Actually i am not doing what you are saying. i am producing intermediate modular products for each multiplication – curious Feb 18 '15 at 13:37
  • 1
    The difference is you calculate `prod = prod * e` and `prodfin = prod % n` on each iteration, whereas the second snippet I posted calculates `prod = prod % n` (which makes `prod` smaller, simplifying the multiplication without affecting the final result). If you **really** need the intermediate multiplicands, then you will suffer from the quadratic explosion of `prod` and moving to a C-based GMP library will give you only a multiplicative speed up at best. – nelfin Feb 18 '15 at 13:47