-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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