Exemplo n.º 1
0
void multiply(limb *factor1, limb *factor2, limb *result, int len, int *pResultLen)
{
  int length = len;
    // Compute length of numbers for each recursion.
  if (length > KARATSUBA_CUTOFF)
  {
    int div = 1;
    while (length > KARATSUBA_CUTOFF)
    {
      div *= 2;
      length = (length + 1) / 2;
    }
    length *= div;
  }
  karatLength = length;
  memset(arr, 0, 2 * length*sizeof(limb));
  memcpy(&arr[0], factor1, len*sizeof(limb));
  memcpy(&arr[length], factor2, len*sizeof(limb));
  Karatsuba(0, length, 2 * length);
  memcpy(result, &arr[2 * (karatLength - length)], 2 * length * sizeof(limb));
  if (pResultLen != NULL)
  {
    memcpy(result, &arr[2 * (karatLength - length)], 2 * length * sizeof(limb));
    if (karatLength > length && arr[2 * (karatLength - length)-1].x == 0)
    {
      *pResultLen = length * 2 - 1;
    }
    else
    {
      *pResultLen = length * 2;
    }
  }
}
LongInt Algorithm::Karatsuba(LongInt a_1, LongInt b_1)
{
    if(a_1.length()==1 || b_1.length()==1)//&&
    {
        return a_1*b_1;
    }

    int length;
    if(a_1.length()!=1 && b_1.length()!=1)
    {
        length=(a_1.length() >= b_1.length() ? b_1.length() : a_1.length() )/2;
        LongInt a_2;
        a_2.number=a_1.getVector_of_Number(a_1.length()-length);
        LongInt b_2;
        b_2.number=b_1.getVector_of_Number(b_1.length()-length);
        LongInt ab_1,ab_2;
        ab_1=Karatsuba(a_1,b_1);
        ab_2=Karatsuba(a_2,b_2);
        return ( (((Karatsuba(a_1+a_2,b_1+b_2)-ab_1-ab_2)<<length)
                  + ab_2)
                 + (ab_1<<(2*length))
               );
    }
}
Exemplo n.º 3
0
// Recursive Karatsuba function.
static void Karatsuba(int idxFactor1, int nbrLen, int diffIndex)
{
  int idxFactor2 = idxFactor1 + nbrLen;
  int i;
  unsigned int carry1First, carry1Second;
  unsigned int carry2Second;
  limb *ptrResult, *ptrHigh, tmp;
  int middle;
  int sign;
  int halfLength;
  if (nbrLen <= KARATSUBA_CUTOFF)
  {
    // Check if one of the factors is equal to zero.
    ptrResult = &arr[idxFactor1];
    for (i = nbrLen; i > 0; i--)
    {
      if ((ptrResult++)->x != 0)
      {
        break;
      }
    }
    if (i > 0)
    {     // First factor is not zero. Check second.
      ptrResult = &arr[idxFactor2];
      for (i = nbrLen; i > 0; i--)
      {
        if ((ptrResult++)->x != 0)
        {
          break;
        }
      }
    }
    if (i==0)
    {    // One of the factors is equal to zero.
      for (i = nbrLen - 1; i >= 0; i--)
      {
        arr[idxFactor1 + i].x = arr[idxFactor2 + i].x = 0;
      }
      return;
    }
         // Below cutoff: perform standard classical multiplcation.
    ClassicalMult(idxFactor1, idxFactor2, nbrLen);
    return;
  }
  // Length > KARATSUBA_CUTOFF: Use Karatsuba multiplication.
  // It uses three half-length multiplications instead of four.
  //  x*y = (xH*b + xL)*(yH*b + yL)
  //  x*y = (b + 1)*(xH*yH*b + xL*yL) + (xH - xL)*(yL - yH)*b
  // The length of b is stored in variable halfLength.
  // Since the absolute values of (xH - xL) and (yL - yH) fit in
  // a single limb, there will be no overflow.

  // At this moment the order is: xL, xH, yL, yH.
  // Exchange high part of first factor with low part of 2nd factor.
  halfLength = nbrLen >> 1;
  for (i = idxFactor1 + halfLength; i<idxFactor2; i++)
  {
    tmp.x = arr[i].x;
    arr[i].x = arr[i + halfLength].x;
    arr[i + halfLength].x = tmp.x;
  }
  // At this moment the order is: xL, yL, xH, yH.
  // Get absolute values of (xH-xL) and (yL-yH) and the signs.
  sign = absSubtract(idxFactor1, idxFactor2, diffIndex, halfLength);
  sign ^= absSubtract(idxFactor2 + halfLength, idxFactor1 + halfLength,
    diffIndex + halfLength, halfLength);
  middle = diffIndex;
  diffIndex += nbrLen;
  Karatsuba(idxFactor1, halfLength, diffIndex); // Multiply both low parts.
  Karatsuba(idxFactor2, halfLength, diffIndex); // Multiply both high parts.
  Karatsuba(middle, halfLength, diffIndex);     // Multiply the differences.
     // Process all carries at the end.
     // Obtain (b+1)(xH*yH*b + xL*yL) = xH*yH*b^2 + (xL*yL+xH*yH)*b + xL*yL
     // The first and last terms are already in correct locations.
  ptrResult = &arr[idxFactor1+halfLength];
  carry1First = carry1Second = carry2Second = 0;
  for (i = halfLength; i > 0; i--)
  {
    // The sum of three ints overflows an unsigned int variable,
    // so two adds are required. Also carries must be separated in
    // order to avoid overflow:
    // 00000001 + 7FFFFFFF + 7FFFFFFF = FFFFFFFF
    unsigned int accum1Lo = carry1First + ptrResult->x + (ptrResult + halfLength)->x;
    unsigned int accum2Lo;
    carry1First = accum1Lo >> BITS_PER_GROUP;
    accum2Lo = carry2Second + (accum1Lo & MAX_VALUE_LIMB) +
               (ptrResult - halfLength)->x;
    carry2Second = accum2Lo >> BITS_PER_GROUP;
    accum1Lo = carry1Second + (accum1Lo & MAX_VALUE_LIMB) +
               (ptrResult + nbrLen)->x;
    carry1Second = accum1Lo >> BITS_PER_GROUP;
    (ptrResult + halfLength)->x = accum1Lo & MAX_VALUE_LIMB;
    ptrResult->x = accum2Lo & MAX_VALUE_LIMB;
    ptrResult++;
  }
  (ptrResult + halfLength)->x += carry1First + carry1Second;
  ptrResult->x += carry1First + carry2Second;
  // Process carries.
  ptrResult = &arr[idxFactor1];
  carry1First = 0;
  for (i = 2*nbrLen; i > 0; i--)
  {
    carry1First += ptrResult->x;
    (ptrResult++)->x = carry1First & MAX_VALUE_LIMB;
    carry1First >>= BITS_PER_GROUP;
  }
  // Compute final product.
  ptrHigh = &arr[middle];
  ptrResult = &arr[idxFactor1 + halfLength];
  if (sign != 0)
  {            // (xH-xL) * (yL-yH) is negative.
    int borrow = 0;
    for (i = nbrLen; i > 0; i--)
    {
      borrow += ptrResult->x - (ptrHigh++)->x;
      (ptrResult++)->x = borrow & MAX_VALUE_LIMB;
      borrow >>= BITS_PER_GROUP;
    }
    for (i = halfLength; i > 0; i--)
    {
      borrow += ptrResult->x;
      (ptrResult++)->x = borrow & MAX_VALUE_LIMB;
      borrow >>= BITS_PER_GROUP;
    }
  }