Skip to content

Instantly share code, notes, and snippets.

@jin-x
Last active December 24, 2019 21:30
Show Gist options
  • Select an option

  • Save jin-x/8df799695d31dca18a5f95920f4a6b5b to your computer and use it in GitHub Desktop.

Select an option

Save jin-x/8df799695d31dca18a5f95920f4a6b5b to your computer and use it in GitHub Desktop.
Factorial radix
#include <string>
#include <vector>
// Factorial radix
namespace fact_radix
{
// factorial digit type
using fact_digits = std::vector<int8_t>;
// convert 32-bit integer number to factorial digit vector
void to_fact(const int32_t n, fact_digits& result)
{
result.clear();
std::div_t d;
d.quot = n;
for (int i = 2; d.quot != 0; ++i) {
d = div(d.quot, i);
result.push_back(d.rem);
}
} // to_fact(int32_t)
// convert 64-bit integer number to factorial digit vector
void to_fact(const int64_t n, fact_digits& result)
{
result.clear();
std::lldiv_t d;
d.quot = n;
for (int i = 2; d.quot != 0; ++i) {
d = lldiv(d.quot, i);
result.push_back(d.rem);
}
} // to_fact(int64_t)
// FAST convert 32-bit integer number to factorial digit vector
void to_fact_fast(int32_t n, fact_digits& result)
{
result.clear();
if (n == 0) { return; }
result.push_back(n % 2); n = n / 2;
if (n != 0) { result.push_back(n % 3); n = n / 3;
if (n != 0) { result.push_back(n % 4); n = n / 4;
if (n != 0) { result.push_back(n % 5); n = n / 5;
if (n != 0) { result.push_back(n % 6); n = n / 6;
if (n != 0) { result.push_back(n % 7); n = n / 7;
if (n != 0) { result.push_back(n % 8); n = n / 8;
if (n != 0) { result.push_back(n % 9); n = n / 9;
if (n != 0) { result.push_back(n % 10); n = n / 10;
if (n != 0) { result.push_back(n % 11); n = n / 11;
if (n != 0) { result.push_back(n % 12); n = n / 12;
if (n != 0) { result.push_back(n); }
}}}}}}}}}}
} // to_fact_fast(int32_t)
// FAST convert 64-bit integer number to factorial digit vector
void to_fact_fast(int64_t n, fact_digits& result)
{
result.clear();
if (n == 0) { return; }
result.push_back(n % 2); n = n / 2;
if (n != 0) { result.push_back(n % 3); n = n / 3;
if (n != 0) { result.push_back(n % 4); n = n / 4;
if (n != 0) { result.push_back(n % 5); n = n / 5;
if (n != 0) { result.push_back(n % 6); n = n / 6;
if (n != 0) { result.push_back(n % 7); n = n / 7;
if (n != 0) { result.push_back(n % 8); n = n / 8;
if (n != 0) { result.push_back(n % 9); n = n / 9;
if (n != 0) { result.push_back(n % 10); n = n / 10;
if (n != 0) { result.push_back(n % 11); n = n / 11;
if (n != 0) { result.push_back(n % 12); n = n / 12;
if (n != 0) { result.push_back(n % 13); n = n / 13;
if (n != 0) { result.push_back(n % 14); n = n / 14;
if (n != 0) { result.push_back(n % 15); n = n / 15;
if (n != 0) { result.push_back(n % 16); n = n / 16;
if (n != 0) { result.push_back(n % 17); n = n / 17;
if (n != 0) { result.push_back(n % 18); n = n / 18;
if (n != 0) { result.push_back(n % 19); n = n / 19;
if (n != 0) { result.push_back(n % 20); n = n / 20;
if (n != 0) { result.push_back(n); }
}}}}}}}}}}}}}}}}}}
} // to_fact_fast(int64_t)
// convert factorial digit vector to 64-bit integer number
int64_t from_fact(const fact_digits& n)
{
int64_t result = 0;
int64_t i = 1, fact = 1;
for (const auto x : n) {
result += x * fact;
++i; fact *= i;
}
return result;
} // from_fact
// convert factorial digit vector to string (digits 0..9,A..J)
std::string to_str(const fact_digits& n)
{
if (n.empty()) { return "0"; }
std::string result;
if (n.back() < 0) { result.push_back('-'); }
for (auto i = n.crbegin(); i != n.crend(); ++i) {
int8_t x = std::abs(*i) + '0';
if (x > '9') { x += 'A'-('9'+1); }
result.push_back(x);
};
return result;
} // to_str
// convert factorial digit vector to string (decimal numbers separated by colon)
std::string to_str_sep(const fact_digits& n)
{
if (n.empty()) { return "0"; }
std::string result;
if (n.back() < 0) { result.push_back('-'); }
for (auto i = n.crbegin(); i != n.crend(); ++i) {
result.append(std::to_string(abs(*i)));
result.push_back(':');
};
result.pop_back();
return result;
} // to_str_sep
} // namespace fact_radix
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <chrono>
using namespace std;
using Clock = chrono::steady_clock;
int main()
{
int64_t first, last;
cout << "Enter value range (first and last integer numbers via space): ";
cin >> first >> last;
cin.ignore();
if (last < first) {
cout << "First number must be less than last!" << endl;
return 1;
}
string s;
cout << "Compare fast/slow versions and check reverse conversion? (y/n) [y] : ";
getline(cin, s);
bool check = (tolower(s[0]) != 'n');
cout << "Show numbers? (y/n) [y] : ";
getline(cin, s);
bool show = (tolower(s[0]) != 'n');
int64_t total = last-first+1, to_fact_errors = 0, from_fact_errors = 0;
fact_radix::fact_digits fact, fact2;
Clock::time_point clock_start = Clock::now();
for (int64_t n = first; n != last+1; ++n) {
fact_radix::to_fact_fast(n, fact);
if (show) {
cout << n << " (dec) = " << fact_radix::to_str_sep(fact) << " = "
<< fact_radix::to_str(fact) << " (fact)";
}
if (check) {
fact_radix::to_fact(n, fact2);
if (fact != fact2) {
++to_fact_errors;
if (show) { cout << " - to_fact_fast/to_fact ERROR !!!"; }
}
if (n != fact_radix::from_fact(fact)) {
++from_fact_errors;
if (show) { cout << " - from_fact ERROR !!!"; }
}
}
if (show) { cout << endl; }
}
Clock::time_point clock_end = Clock::now();
double elapsed_time = chrono::duration_cast<chrono::duration<double>>(clock_end - clock_start).count();
cout << "Total: " << total << " numbers";
if (check) {
cout << ", to_fact_fast/to_fact errors: " << to_fact_errors
<< ", from_fact errors: " << from_fact_errors;
}
cout << endl << "Elapsed time: " << fixed << elapsed_time << " seconds" << endl;
return 0;
}
def to_fact_radix(n):
result = ""
neg = (n < 0)
if neg: n = -n
i = 1
while True:
i += 1
result = str(n % i) + result
n //= i
if n == 0: break
result = ":" + result
if neg: result = "-" + result
return result
def from_fact_radix(n):
neg = (n != "" and n[0] == "-")
if neg: n = n[1:]
lst = map(int, reversed(n.split(":")))
result = 0
f = i = 1
for d in lst:
result += d * f
i += 1
f *= i
if neg: result = -result
return result
def row_fact_radix(n):
neg = (n != "" and n[0] == "-")
if neg: n = n[1:]
lst = map(int, reversed(n.split(":")))
result = ""
f = i = 1
for d in lst:
if result != "": result = " + " + result
result = str(d) + "*" + str(i) + "!" + result
i += 1
f *= i
if neg: result = "-(" + result + ")"
return result
for i in range(-2,121):
f = to_fact_radix(i)
print(f"{i} (dec) = {f} (fact) = {row_fact_radix(f)} = {from_fact_radix(f)} (dec)")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment