Toom-4.5 (aka Toom-5x4, Toom-6x3, Toom-7x2)

Niels Möller nisse at lysator.liu.se
Fri Oct 9 23:15:43 CEST 2009


David Harvey <dmharvey at cims.nyu.edu> writes:

> (1) can the evaluation points in Marco's code be changed so that
> division by 45 becomes something else that succumbs to these tricks?

Evaluation in 0, oo, ±1, ±2, ±1/2 gives a matrix with determinant

  9331200 = 2^9 * 3^6 * 5^2

So these are the numbers we have to divide out somewhere in the
interpolation. If we want to use the B-1 trick, we can only divide by
3, 5 or 15 at a time, so we'd need at least 6 divisions. Combining
factors, such as 45 = 3^2 * 5, gives fewer but more expensive
divisions.

> (2) can you do fast Hensel division by B^2 - 2*B + 1? Maybe the only
> way is to divide by B - 1 twice, or maybe something faster is possible.

The multiplicative inverse (mod B^2) is 2B + 1, so I'd expect division
to be cheap. But to get a division by 45, you'd also have to multiply
by (B^2 - 2B + 1 ) / 45, which is a two limb number. I'd expect that
to be quite expensive (although with a nicer recurrency than general
divexact which has a long series of dependent multiplications)

> (3) can you do fast Hensel division by 2^64 - 16? (It's not odd, but
> maybe some sense can be made of this?)

Anyway, I think hensel division or divexact by d = 2^60 - 1 should be
fairly efficient, or at least multiplication free. Even id we do it
one full limb at a time. The multiplicative inverse mod 2^64 is 2^60 +
1, so in the loop the lowest quotient word would be computed as

  q_0 = - (u_0 + 2^60 u_0)  (mod B)

and then the update of the partial remainder is

  U -= q_0 u_0

I have some difficulty figuring out exactly what the effect of the mod
B truncation of q_0 will be (we truncate the top 60 bits in 2^60 u0,
then there's a possible carry from the addition, and finally the
negation).

Ignore some of this issues, by putting u0 = 2^4 uh + ul and
considering the quotient word - (u0 + 2^60 ul) (to which one needs to
add 0, B or 2B to get the q_0 above), we get the product

  (u0 + 2^60 ul) (2^60 - 1) = - u0 + 2^64 uh + 2^120 ul 
                                     
So I think it should be possible to do the update of the partial
remainder without multiplication, but perhaps with somewhat complex
carry logic. Since the (uh + 2^56 ul) update term is the sum of 60-bit
quantities, there's no risk of overflow there, so maybe one could do
the update corresponding to a quotient word with some extra bit, and
do the needed carry handling on the q-side?

That would mean, compute the negated quotient, word by word, with
carry

  {cout, q_j} = u_j + (2^60 u_j mod 2^64) + cin

and do the update as

  U += B^{j+1} ( floor (2^{-4} u_j) + 2^56 (u_j mod 16))

(here we also have carry propagation to do between iterations).

Essentially the same method should apply to all divisors of the form
2^k - 1, with k >= word size / 2, with

  (u0 + 2^k ul) (2^k - 1) = - u0 + B uh + 2^{2k} u_l

Regards,
/Niels


More information about the gmp-devel mailing list