3

I'm looking for fast a way to compute n mod x1, n mod x2, n mod x3, ... I found a an article about "remainder trees" which claims to do just that.

However, I fail to see how is the above approach any better than naively computing each mod separately (even the last step of the above remaindersusingproducttree seems to doing exactly this). I also trivially benchmarked the above code and it does not seem to run faster.

My question is, I guess "remainder trees" somehow work better than the naive approach but I don't understand how. Please, could anyone shed some light into this?

Alternatively, is there any other way to quickly computing the many mod operations?

minmax
  • 493
  • 3
  • 10
  • From quick look at the article it appears it's meant for use cases where division gets more expensive when the result is longer (smaller divisor means more operations). Have you tried with testcases of numbers that are much larger than your computer's native type, maybe 100 digits or so? – domen Sep 12 '18 at 12:57
  • @domen Yes, I tried and there was no difference. And as I said above, the last step seems to be the same as the naive approach so I'm a bit confused. – minmax Sep 12 '18 at 13:19
  • The last step is not exactly the same as in the naive approach. The naive approach computes n mod x, for a possibly very large n. The tree algorithm first reduces n down to smaller numbers by applying n mod (product of some x) ,and than uses this smaller numbers to calculate the final result. I agree with @domen that this is probably useful when n is very large and we assume a remainder operation that has non-constant runtime. – lwi Sep 12 '18 at 13:30

1 Answers1

1

The speedup of this algorithm assumes that log(n) >> log(x[i]). The time complexity of dividing two numbers is O(b^2), where b is the number of bits in the dividend. The initial division (n mod x[0]x[1]) is quite expensive if n is very large, but the following two divisions are done on the comparatively small remainder from the first division. Thus, to obtain two remainders in the base case, the algorithm is replacing two very expensive divisions by a single very expensive division and two very cheap divisions.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
  • I'm not sure I understand: the naive way uses just one division per element, not two? – minmax Sep 13 '18 at 07:20
  • I'm talking about for the pair, in the base case. I've edited the answer to clarify that. – Sneftel Sep 13 '18 at 07:47
  • I thought division of m-,n-bits number is ceil(m/n)*M(n) + O(m), where M is the cost of multiplication. But anyway, I can now see that computing `d=a%(b*c); d%b, d%c` is faster than `a%b, a%c`. I even saw the improvement in a simple benchmark, it's just `log(n)` had to be in the range of 10^9... – minmax Sep 13 '18 at 09:14