Для длинных списков разделяй и властвуй, как правило, быстрее. Идея состоит в том, чтобы вычислить мод времени для первой и второй половин, умножить его и взять мод.
Вот пример. Мы будем использовать список из 10 ^ 6 целых чисел, все от 0 до 10 ^ 10.
SeedRandom[1111111];
len = 6;
max = 10;
list = RandomInteger[10^max, 10^len];
Умножение и взятие модуля для немного большего мода (я хотел уменьшить вероятность того, что результат будет нулевым):
In[119]:= Timing[Mod[Times @@ list, 32327541]]
Out[119]= {1.360000, 8826597}
Вот вариант, который я описал. Методика проб и ошибок указала, что списки длиной 2 ^ 9 или около того лучше всего составлять нерекурсивно, по крайней мере для чисел в диапазоне размеров, указанном выше.
tmod2[ll_List, m_] := With[{len=Floor[Length[ll]/2]},
If[len<=256,
Mod[Times @@ ll, m],
Mod[tmod2[Take[ll,len],m] * tmod2[Drop[ll,len],m], m]]]
In[120]:= Timing[tmod2[list, 32327541]]
Out[120]= {0.310000, 8826597}
Когда я увеличиваю длину списка до 10 ^ 7 и разрешаю целые числа от 0 до 10 ^ 20, первый метод занимает 50 секунд, а второй - 5 секунд. Очевидно, что масштабирование работает нам на пользу.
Для ситуаций, когда итерация, чередующая две операции, может быть предпочтительнее, чем разделяй и властвуй, можно использовать Fold, как показано ниже.
tmod3[ll_List, m_] := Fold[Mod[#1*#2,m]&, First[ll], Rest[ll]]
Хотя он и не конкурирует с tmod2 в длинных списках, это быстрее, чем умножение всего до запуска Mod. Для длины 10 ^ 7 и максимального элемента 0f 10 ^ 20 требуется примерно 8 секунд, чтобы сделать то, что сделал tmod2 в 5.