C or C++: Libraries for factoring integers? [closed]
Asked Answered
E

3

11

It seems that there are several really fast prime factorization algorithms around (one that looks ideal is quadratic sieving). However, rather than make my own (likely poor) implementation I would like to use a ready-made library for simplicity.

I need to be able to factor integers of up to 15 digits efficiently. Because of that, I'm not looking for the algorithm that necessarily scales asymptotically best since we can assume the numbers being factored are less than 1015.

I've already had a look at some of the implementations listed on Wikipedia's Quadratic Sieve page. However, some of the implementations don't seem well-maintained; some don't have documentation; and so on! I checked if a few well-known libraries, such as Boost, had factorization methods but they don't seem to.

Can anyone recommend a library that fits the above criteria?

Ez answered 24/5, 2009 at 11:13 Comment(3)
"Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it."Galven
questions like this should be on Software RecommendationsDillondillow
Is there any chance that this very insteresting mathimatical-wise question can be Reopened? Wanted not only to suggest libraries, but also write my own code, with full research and explanations.Weedy
R
5

Check out MSIEVE library for factoring large integers by Jason Papadopoulos.

Msieve is the result of my efforts to understand and optimize how integers are factored using the most powerful modern algorithms.

This documentation corresponds to version 1.46 of the Msieve library. Do not expect to become a factoring expert just by reading it. I've included a relatively complete list of references that you can and should look up if you want to treat the code as more than a black box to solve your factoring problems.

Rosenkranz answered 24/5, 2009 at 12:15 Comment(6)
Again, I can't find any real documentation on it. I'm not sure how it would integrate with my program and, thus, whether it would work!Ez
Well, I said you may... :) I'm interested in factorization too. Factorization is a hard problem and probably it will be hard to find a documented and fast library.Rosenkranz
I agree; especially with the almost mutual exclusivity of a projects documentation and speed. ;)Ez
The linked forum: mersenneforum.org/forumdisplay.php?f=19 seems quite active - I'd suggest asking for help there, and maybe pointing back to this thread.Ferdinande
OK, I've asked... A mod needs to check my first post apparently so I'll post the link when it is okayed.Ez
@Ez is it okayed yet? :PFerland
K
2

To factor integers in C you can try to use a probabilistic approach :

The headers of my proposition :

#include <stdlib.h>
#include <sys/time.h>

typedef unsigned long long int positive_number; // __uint128_t
static inline positive_number multiplication_modulo(positive_number lhs, positive_number rhs, positive_number mod);
static int is_prime(positive_number n, int k); // prime checker
positive_number factor_worker(positive_number n);
positive_number factor(positive_number n, int timeout);

The factorization process manager, because there is a timeout:

double microtime() {
    struct timeval time; gettimeofday(&time, 0);
    return (double) time.tv_sec + (double) time.tv_usec / 1e6;
}

// This is the master function you can call, expecting a number and a timeout(s)
positive_number factor(positive_number n, int timeout) {
    if (n < 4) return n;
    if (n != (n | 1)) return 2;
    double begin = microtime();
    int steps = 8; // primality check iterations
    positive_number a, b;
    for (a = n >> 1, b = (a + n / a) >> 1; b < a; a = b, b = (a + n / a) >> 1, ++steps);
    if (b * b == n) return b ; // we just computed b = sqrt(n)
    if (is_prime(n, steps)) return n;
    do { positive_number res = factor_worker(n);
        if (res != n) return res;
        if (++steps % 96 == 0 && is_prime(n, 32)) return n ; // adjust it
    } while (microtime() - begin < timeout);
    return n;
}

The multiplier helper because computations are done modulo N :

static inline positive_number multiplication_modulo(positive_number lhs, positive_number rhs, positive_number mod) {
    positive_number res = 0; // we avoid overflow in modular multiplication
    for (lhs %= mod, rhs%= mod; rhs; (rhs & 1) ? (res = (res + lhs) % mod) : 0, lhs = (lhs << 1) % mod, rhs >>= 1);
    return res; // <= (lhs * rhs) % mod
}

The prime checker helper, of course :

static int is_prime(positive_number n, int k) {
    positive_number a = 0, b, c, d, e, f, g; int h, i;
    if ((n == 1) == (n & 1)) return n == 2;
    if (n < 51529) // fast constexpr check for small primes (removable)
        return (n & 1) & ((n < 6) * 42 + 0x208A2882) >> n % 30 && (n < 49 || (n % 7 && n % 11 && n % 13 && n % 17 && n % 19 && n % 23 && n % 29 && n % 31 && n % 37 && (n < 1369 || (n % 41 && n % 43 && n % 47 && n % 53 && n % 59 && n % 61 && n % 67 && n % 71 && n % 73 && ( n < 6241 || (n % 79 && n % 83 && n % 89 && n % 97 && n % 101 && n % 103 && n % 107 && n % 109 && n % 113 && ( n < 16129 || (n % 127 && n % 131 && n % 137 && n % 139 && n % 149 && n % 151 && n % 157 && n % 163 && n % 167 && ( n < 29929 || (n % 173 && n % 179 && n % 181 && n % 191 && n % 193 && n % 197 && n % 199 && n % 211 && n % 223))))))))));
    for (b = c = n - 1, h = 0; !(b & 1); b >>= 1, ++h);
    for (; k--;) {
        for (g = 0; g < sizeof(positive_number); ((char*)&a)[g++] = rand()); // random number
        do for (d = e = 1 + a % c, f = n; (d %= f) && (f %= d););
        while (d > 1 && f > 1);
        for (d = f = 1; f <= b; f <<= 1);
        for (; f >>= 1; d = multiplication_modulo(d, d, n), f & b && (d = multiplication_modulo(e, d, n)));
        if (d == 1) continue;
        for (i = h; i-- && d != c; d = multiplication_modulo(d, d, n));
        if (d != c) return 0;
    }
    return 1;
}

The factorization worker, a single call does not guarantee a success, it's a probabilistic try :

positive_number factor_worker(positive_number n) {
    size_t a; positive_number b = 0, c, d, e, f;
    for (a = 0; a < sizeof(positive_number); ((char*)&b)[a++] = rand()); // pick random polynomial
    c = b %= n;
    do {
        b = multiplication_modulo(b, b, n); if(++b == n) b = 0;
        c = multiplication_modulo(c, c, n); if(++c == n) c = 0;
        c = multiplication_modulo(c, c, n); if(++c == n) c = 0;
        for (d = n, e = b > c ? b - c : c - b; e; f = e, e = multiplication_modulo(d / f, f, n), e = (d - e) % n, d = f);
        // handle your precise timeout in the for loop body
    } while (d == 1);
    return d;
}

Example of usage :

#include <stdio.h>

positive_number exec(positive_number n) {
    positive_number res = factor(n, 2); // 2 seconds
    if (res == n) return res + printf("%llu * ", n) * fflush(stdout) ;
    return exec(res) * exec(n / res);
}

int main() {
    positive_number n = 0, mask = -1, res;
    for (int i = 0; i < 1000;) {
        int bits = 4 + rand() % 60; // adjust the modulo for tests
        for (size_t k = 0; k < sizeof(positive_number); ((char*)&n)[k++] = rand());
        // slice a random number with the "bits" variable
        n &= mask >> (8 * sizeof (positive_number) - bits); n += 4;
        printf("%5d. (%2d bits) %llu = ", ++i, bits, n);
        res = exec(n);
        if (res != n) return 1;
        printf("1\n");
    }
}

You can put it into a primes.c file then compile + execute :

gcc -O3 -std=c99 -Wall -pedantic primes.c ; ./a.out ;

Also, 128-bit integers GCC extension extension may be available.

Example output :

  358205873110913227 =    380003149 * 942639223    took 0.01s
  195482582293315223 =    242470939 * 806210357    took 0.0021s
  107179818338278057 =    139812461 * 766597037    took 0.0023s
   44636597321924407 =    182540669 * 244529603    took 0s
  747503348409771887 =    865588487 * 863578201    took 0.016s

// 128-bit extension available output :
170141183460469231731687303715506697937 =
13602473 * 230287853 * 54315095311400476747373 took 0.646652s

Info : This C99 100 lines probabilistic factorization software proposition is based on a Miller–Rabin primality test followed or not by a Pollard's rho algo. Like you, i initially aimed to factorize just a little long long int. By my tests it's working fast enough to me, even for some larger. Thank you.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.

Kliman answered 9/4, 2022 at 5:48 Comment(2)
You could improve this by using more bits from each call to rand(). Here is a simple way assuming RAND_MAX is 1 short of a power of 2: for (k = 1; k; k *= RAND_MAX + 1U) res |= rand() * k;Macey
res is uninitialized in rand_prime(). You probably meant this but it generates a warning and it is technically incorrect because res could be a trap value causing undefined behavior when read for the xor operation.Macey
F
1

How about GMP-ECM (Elliptic Curve Method for Integer Factorization)?

If the link to the official project page at Inria is unavailable, you can check a recent version on the web archive.

Ferdinande answered 24/5, 2009 at 11:21 Comment(4)
I can't find any docs on that (its "Docs" section is empty). Its name also seems to hint that it uses GMP to store integers. I would prefer to use 64bit integers (since I run on a 64bit computer).Ez
Did you check the readme.lib file in the source distribution? It is not the most detailed documentation, but it explains how it works. (However, it does use gmp, and not 64bit integers).Etui
Links is broken in 2021. This is a classic example of the rationale behind discouraging links as answers.Garrulous
@PeterLeopold: a stale pointer is better than no information at all. The web archive often has many backups of useful sites.Macey

© 2022 - 2024 — McMap. All rights reserved.