Skip to content

Instantly share code, notes, and snippets.

@tdulcet
Created September 10, 2023 15:18
Show Gist options
  • Save tdulcet/6393865769644aaf9244561f3eb4e9c2 to your computer and use it in GitHub Desktop.
Save tdulcet/6393865769644aaf9244561f3eb4e9c2 to your computer and use it in GitHub Desktop.
A simple wrapper program for the EPR Factoring Library that is compatible with the GNU factor command.
// Copyright (c) 2020-2022 Jeffrey Hurchalla and Teal Dulcet.
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// Adapted from: https://github.com/hurchalla/factoring/blob/master/examples/example_without_cmake/example.cpp
/* Compile:
mkdir tmp
cd tmp/
cmake -S.. -B.
cmake --install . --prefix ../temp
cd ../temp/
g++ -std=gnu++17 -Wall -Wextra -g -O3 -flto -march=native -DNDEBUG -DHURCHALLA_ALLOW_INLINE_ASM_ALL -Iinclude -o gcc_example example.cpp
clang++ -std=gnu++17 -Wall -Wextra -g -O3 -flto -march=native -DNDEBUG -DHURCHALLA_ALLOW_INLINE_ASM_ALL -Iinclude -o clang_example example.cpp
cp {gcc,clang}_example ..
*/
// Run: ./example [NUMBER(S)]...
// This example is intended for the case that you are not using CMake.
// If you haven't already, you need to follow the steps in the README.md
// for "How to use the library" | "Without CMake"
#include "hurchalla/factoring/factorize.h"
#include <iostream>
#include <sstream>
#include <cstring>
#include <iomanip>
#include <cinttypes>
#include <map>
using namespace std;
#ifndef NDEBUG
// remove this if you want to allow asserts
// (they're very good for testing and debugging but may drastically slow down
// the library).
#error "Performance warning: asserts are enabled and will slow performance"
#endif
constexpr __int128 INT128_MAX = numeric_limits<__int128>::max();
constexpr __int128 INT128_MIN = numeric_limits<__int128>::min();
__int128 strtoi128(const char *nptr, char **endptr, int base)
{
const char *s = nptr;
int c;
bool neg = false;
do
{
c = *s++;
} while (isspace(c));
if (c == '-')
{
neg = true;
c = *s++;
}
else if (c == '+')
c = *s++;
if ((base == 0 or base == 16) and c == '0' and (*s == 'x' or *s == 'X'))
{
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
unsigned __int128 cutoff = neg ? -(unsigned __int128)INT128_MIN : INT128_MAX;
const int cutlim = cutoff % base;
cutoff /= base;
unsigned __int128 acc;
int any;
for (acc = 0, any = 0;; c = *s++)
{
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 or acc > cutoff or (acc == cutoff and c > cutlim))
any = -1;
else
{
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0)
{
acc = neg ? INT128_MIN : INT128_MAX;
errno = ERANGE;
}
else if (neg)
acc = -acc;
if (endptr != nullptr)
*endptr = (char *)(any ? s - 1 : nptr);
return acc;
}
// Output number in bases 2 - 36
template <typename T>
string outputbase(const T number, const short base = 10, const bool uppercase = false)
{
if (base < 2 or base > 36)
{
cerr << "Error: <BASE> must be 2 - 36.\n";
exit(1);
}
make_unsigned_t<T> anumber = number;
anumber = number < 0 ? -anumber : anumber;
string str;
// This reserves too much space for higher bases
str.reserve(__bit_width(anumber) + (number < 0));
do
{
char digit = anumber % base;
digit += digit < 10 ? '0' : (uppercase ? 'A' : 'a') - 10;
str = digit + str;
anumber /= base;
} while (anumber > 0);
if (number < 0)
str = '-' + str;
return str;
}
// Output prime factors of number
template <typename T>
string outputfactors(const T &number, const bool print_exponents)
{
if (number < 1)
{
cerr << "Error: Number must be > 0\n";
return {};
}
// make_unsigned_t<T> n = number;
T n = number;
ostringstream strm;
vector<T> factors;
factors.reserve(numeric_limits<T>::digits);
hurchalla::factorize(n, factors);
// sort(factors.begin(), factors.end());
map<T, size_t> counts;
for (const auto &factor : factors)
++counts[factor];
for (const auto &[prime, exponent] : counts)
{
for (size_t j = 0; j < exponent; ++j)
{
if (strm.tellp())
strm << ' ';
if constexpr (is_same_v<T, __int128>)
strm << outputbase(prime);
else
strm << prime;
if (print_exponents and exponent > 1)
{
strm << '^' << exponent;
break;
}
}
}
return strm.str();
}
int integers(const char *const token, const int frombase, const bool print_exponents)
{
char *p;
const long l = strtol(token, &p, frombase);
if (*p)
{
cerr << "Error: Invalid integer number: " << quoted(token) << ".\n";
return 1;
}
if (errno == ERANGE)
{
errno = 0;
const intmax_t imax = strtoimax(token, &p, frombase);
if (*p)
{
cerr << "Error: Invalid integer number: " << quoted(token) << ".\n";
return 1;
}
if (errno == ERANGE)
{
errno = 0;
const __int128 i128 = strtoi128(token, &p, frombase);
if (*p)
{
cerr << "Error: Invalid integer number: " << quoted(token) << ".\n";
return 1;
}
if (errno == ERANGE)
{
cerr << "Error: Integer number too large to input: " << quoted(token) << " (" << strerror(errno) << ").\n";
return 1;
}
else
{
cout << outputbase(i128) << ": " << outputfactors(i128, print_exponents) << '\n'; // endl;
}
}
else
{
cout << imax << ": " << outputfactors(imax, print_exponents) << '\n'; // endl;
}
}
else if (l > INT_MAX or l < INT_MIN)
{
cout << l << ": " << outputfactors(l, print_exponents) << '\n'; // endl;
}
else
{
const int i = l;
cout << i << ": " << outputfactors(i, print_exponents) << '\n'; // endl;
}
return 0;
}
int main(int argc, char *argv[])
{
int frombase = 0;
bool print_exponents = false;
int code = 0;
if (argc > 1)
{
for (int i = 1; i < argc; ++i)
code |= integers(argv[i], frombase, print_exponents);
}
else
{
string token;
while (cin >> token)
code |= integers(token.c_str(), frombase, print_exponents);
}
return code;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment