on a very slow function

Steve D'Aprano steve+python at pearwood.info
Sun Oct 1 22:14:46 EDT 2017


On Mon, 2 Oct 2017 12:00 pm, Ben Bacarisse wrote:


>> Better:
>>
>> last = (pow(last, 2, N) + (2 % N)) % N
> 
> You meant c rather than 2, I think.

Oops, yes, that was a typo.


> And I'm not convinced all the %Ns 
> are worth while.

They are all necessary.


py> (2**75 + 7) % 12  # Expected value.
3
py> ((2**75) % 12 + (7 % 12)) % 12  # Correct.
3
py> (2**75) % 12 + (7 % 12)  # Incorrect.
15


This follows from the rules of modulo arithmetic:

if a ≡ x (mod N)
and b ≡ y (mod N)

then a + b ≡ x + y (mod N)




> Will typical implementations spot that c does not 
> change and calculate c % N only once?

No.


> Also, a very naive test (I don't 
> know much about how to profile Python) suggests that my line is faster
> for the specific N being used in the OP's example.
> 
>> will almost certainly be faster for large values of last.
> 
> Do you mean for large values of N?  If the calculations are mod N, it
> seems like N will the number that matters.

No, I meant "last". Although on testing, I think you might need so really big
values before you'll see a difference. Like hundreds of digits or more.

I just tried it with:

    last = 123456789012345**85

which has over 1000 digits, comparing:

    (last**2 + 17) % 95

versus:

    (pow(last, 2, 95) + (17 % 95)) % 95


and the second form is about ten times faster.

But for smaller values of last, I agree, the first form will be faster.



-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list