Ejemplo n.º 1
0
// Return a * b. This method is known as "Long Multiplication".
// Complexity: O(n^2)
Integer Integer::multiply(Integer& a, Integer& b) const
{
    Integer ans;
    unsigned int i, j, k, n, carry_mult, carry_sum;

    for (i = 0; i < a.size(); i++) {
        carry_mult = carry_sum = 0;
        k = i; // Shifting

        for (j = 0; j < b.size(); j++) {
            n = a[i] * b[j] + carry_mult;
            carry_mult = n / BASE;

            n = ans[k] + n % BASE + carry_sum;
            carry_sum = n / BASE;

            ans[k] = n % BASE;
            k++;
        }

        if (carry_sum > 0 || carry_mult > 0) {
            ans[k++] = carry_sum + carry_mult;
        }

        ans.set_size(k);
    }

    if (ans == ZERO)
        ans.set_sign(PLUS);
    else
        ans.set_sign(a.sign() * b.sign());

    return ans;
}
Ejemplo n.º 2
0
// Split number a in two parts of size half, if a.size() < 2 * half
// trailing zeros are added.
void Integer::split(const Integer& a, Integer& a0, Integer& a1, int half)
{
    int i;
    a0.set_size(half);
    a1.set_size(half);

    for (i = 0; i < half; i++) {
        a0[i] = a[i];
    }

    for (i = half; i < half + half; i++) {
        a1[i - half] = a[i];
    }

    a0.adjust();
    a1.adjust();
}
Ejemplo n.º 3
0
// Returns true if (*this) is probably prime, false otherwise.
// This method is known as: Miller-Rabin.
// NOTE: Experimental
bool Integer::is_probable_prime(int certainty) const
{
    Integer p = *this;

    if (p < TWO) {
        return false;
    }

    if (p != TWO && p.even()) {
        return false;
    }

    Integer minusone = p - ONE;
    Integer s = minusone;
    Integer a, temp, mod;
    srand(time(NULL));

    while (s.even()) {
        s /= TWO;
    }

    for (int i = 0; i < certainty; i++) {
        Integer aux;
        int size = rand() % 500;
        aux.set_size(size);

        for (int j = 0; j < size; j++) {
            aux[j] = rand() % 10;
        }

        aux.adjust();
        cout << aux << endl;


        a = aux % minusone + ONE;
        temp = s;
        mod = a.modpow(temp, p);

        while (temp != minusone && mod != ONE && mod != minusone) {
            mod = (mod * mod) % p;
            temp *= TWO;
        }

        if (mod != minusone && temp.even()) {
            return false;
        }
    }

    return true;
}
Ejemplo n.º 4
0
// Returns a "random" number.
// NOTE: This was the only think that came to my mind in my first attempt .. :).
// TODO: Implement a formal method, a linear congruential method, for example.
Integer Integer::random(int digits) const
{
    Integer n;
    int size = rand() % digits;

    for (int i = 0; i < size; i++) {
        n[i] = rand() % BASE;
    }

    if (size > 0) {
        n.set_size(size);
    }

    n.adjust();
    return n;
}
Ejemplo n.º 5
0
// Returns n >> p => n / 10^p.
Integer Integer::right_shift(const Integer& n, long long p) const
{
    Integer ans = n;

    if (ans == ZERO) {
        return ZERO;
    }

    for (unsigned int i = 0; i + p < ans.size(); i++) {
        ans[i] = ans[i + p];
    }

    ans.set_size(ans.size() - p);
    return ans;

}
Ejemplo n.º 6
0
// a and b are positive integers.
Integer Integer::subtract(Integer& a, Integer& b) const
{
    Integer ans;
    int borrow = 0, n;

    // Three special cases:
    //  a - (-b) ==  a + b
    // -a - b    == -a + (-b)
    // -a - (-b) == -a + b
    if (a.sign() == MINUS || b.sign() == MINUS) {  
        b.set_sign(MINUS * b.sign());
        ans = add(a, b);
        b.set_sign(MINUS * b.sign());
        return ans;
    }

    if (a == b) {
        return ZERO;
    }

    if (a < b) {
        ans = subtract(b, a);
        ans.set_sign(MINUS);
        return ans;
    }

    unsigned int i;

    for (i = 0; i < a.size(); i++) {
        n = a[i] - b[i] - borrow;
        borrow = (n < 0) ? 1 : 0;

        if (n < 0) {
            n += BASE;
        }

        ans[i] = n;
    }

    ans.set_size(i);
    ans.adjust();
    ans.set_sign(PLUS);

    return ans;
}
Ejemplo n.º 7
0
// Calculate a + b and store the result in c. a and b are positive.
void Integer::add(Integer& a, Integer& b, Integer& c) const
{
    int carry = 0, n, i;
    int max = std::max(a.size(), b.size());

    for (i = 0; i < max; i++) {
        n = a[i] + b[i] + carry;
        carry = n / BASE;
        c[i] = n % BASE;
    }

    if (carry > 0) {
        c[i++] = carry;
    }

    c.set_size(i);
    c.adjust();
}
Ejemplo n.º 8
0
// Returns n << p => n * 10^p.
Integer Integer::left_shift(const Integer& n, long long p) const
{
    Integer ans = n;

    if (ans == ZERO) {
        return ZERO;
    }

    for (int i = ans.size() - 1; i >= 0; i--) {
        ans[i + p] = ans[i];
    }

    for (int i = 0; i < p; i++) {
        ans[i] = 0;
    }

    ans.set_size(ans.size() + p);
    return ans;
}
Ejemplo n.º 9
0
// a and b are positive and a > b
void Integer::subtract(Integer& a, Integer& b, Integer& c) const
{
    int n, borrow = 0;
    unsigned int i;

    for (i = 0; i < a.size(); i++) {
        n = a[i] - b[i] - borrow;

        if (n < 0) {
            n += BASE;
        }

        borrow = (n < 0) ? 1 : 0;
        c[i] = n;
    }

    c.set_size(i);
    c.adjust();
    c.set_sign(PLUS);
}
Ejemplo n.º 10
0
// Returns (*this)^2.
Integer Integer::square()
{
    if (size() < MIN_KARATSUBA_SQUARE) {
        return multiply(*this, *this);
    }

    unsigned int i, half = (size() + 1) / 2;
    Integer a0, a1;
    split(*this, a0, a1, half);
    Integer square0 = a0.square();
    Integer square1 = a1.square();
    Integer ans;
    ans.set_size(size() + size());

    for (i = 0; i < 2 * half; i++) {
        ans[i] = square0[i];
    }

    for (i = 2 * half; i < ans.size(); i++) {
        ans[i] = square1[i - 2 * half];
    }

    Integer square2 = (a0 + a1).square();
    square2 -= square0;
    square2 -= square1;
    int n, carry = 0;

    for (i = half; i < ans.size(); i++) {
        n = ans[i] + square2[i - half] + carry;
        carry = n / BASE;
        ans[i] = n % BASE;
    }

    if (carry > 0) {
        ans[i++] = carry;
    }

    ans.adjust();

    return ans;
}
Ejemplo n.º 11
0
// Returns a new integer c = a + b
Integer Integer::add(Integer &a, Integer &b) const
{
    Integer c;
    int carry = 0, i;

    if (a.sign() == b.sign()) {
        c.set_sign(a.sign());
    } else {
        if (a.sign() == MINUS) {
            a.set_sign(PLUS);
            c = subtract(b, a);
            a.set_sign(MINUS);
        } else {
            b.set_sign(PLUS);
            c = subtract(a, b);
            b.set_sign(MINUS);
        }

        return c;
    }

    int max = std::max(a.size(), b.size());
    int n;

    for (i = 0; i < max; i++) {
        n = carry + a[i] + b[i];
        c[i] = n % BASE;
        carry = n / BASE;
    }

    if (carry > 0) {
        c[i++] = carry;
    }

    c.set_size(i);
    c.adjust();
    return c;
}
Ejemplo n.º 12
0
// Return a * b. This method is known as Karatsuba algorithm.
// Complexity: O(n^(log_2 3)) ~ O(n^1.585)
// References:
// [1]  Algorithms and Data Structures: The Basic Toolbox, Kurt Hehlhorn, et al.
// [2]  en.wikipedia.org/wiki/Karatsuba_algorithm
Integer Integer::karatsuba(Integer& a, Integer& b)
{
    unsigned int alength = a.size();
    unsigned int blength = b.size();

    unsigned int half = (max(alength, blength) + 1) / 2;

    // For small numbers the long multiplication is more efficient
    if (max(alength, blength) < MIN_KARATSUBA) {
        return multiply(a, b);
    }

    Integer a0, a1, b0, b1;
    split(a, a0, a1, half);
    split(b, b0, b1, half);

    Integer p1 = karatsuba(a1, b1);
    Integer p0 = karatsuba(a0, b0);

    Integer sum1, sum2;
    add(a0, a1, sum1);
    add(b0, b1, sum2);

    Integer p2 = karatsuba(sum1, sum2);

    unsigned int i;
    int n, carry = 0;

    Integer ans;
    ans.set_size(alength + blength);

    for (i = 0; i < 2 * half; i++) {
        ans[i] = p0[i];
    }

    for (i = 2 * half; i < ans.size(); i++) {
        ans[i] = p1[i - 2 * half];
    }

    // Subtracts
    for (i = 0; i < p2.size(); i++) {
        n = p2[i] - p0[i] - carry;
        carry = (n < 0) ? 1 : 0;

        if (n < 0) {
            n += BASE;
        }

        p2[i] = n;
    }

    p2.adjust();

    for (i = 0; i < p2.size(); i++) {
        n = p2[i] - p1[i] - carry;
        carry = (n < 0) ? 1 : 0;

        if (n < 0) {
            n += BASE;
        }

        p2[i] = n;
    }

    p2.adjust();


    for (i = half; i < ans.size(); i++) {
        n = ans[i] + p2[i - half] + carry;
        carry = n / BASE;
        ans[i] = n % BASE;
    }

    ans.adjust();

    return ans;
}