// Immortal Number Search // by Daniel Marschall // Please compile with: // g++ immortal.cpp -o immortal -lgmpxx -Wall -fopenmp -O3 -mtune=native -pipe // Needed linux packages: libgmpxx4ldbl, libgomp1 // ------------------------------------------------------------------------------------------------------ /** * Immortal Number Search for C++ 1.18 (09.05.2012) * Base 10, Root 5 * Multithread x64/BigInt version * Immortal Number Report File Version 3.00 * * @author Daniel Marschall - Big credit goes to the users of MatheBoard.de * @see http://www.matheboard.de/archive/435725/thread.html * @see http://www.viathinksoft.de/~daniel-marschall/computing/immortal/ * * More source codes, documents and analyse/stat-utilities coming soon! */ // ------------------------------------------------------------------------------------------------------ // #define verbose // #define r_sum_debug // #define do_integrity_test // This is probably 1 tick slower than with usual multiplication... // #define use_multiply_lookup #define stats_general // #define stats_distribution // Seit 1.7 // Für "sum" BigInt anstelle Int64 verwenden. // Aber die Performance leidet extrem darunter // 32-Bit Überlauf findet sehr früh statt. 64-Bit Überlauf unwahrscheinlich. // #define sum_bigint // Seit 1.7 // Für "r" BigInt anstelle Int64 verwenden. // Aber die Performance leidet extrem darunter // 32-Bit Überlauf findet sehr früh statt. 64-Bit Überlauf unwahrscheinlich. // #define r_bigint // Note: "sum" and "r" are unsigned 64-bit (unsigned long long). With unsigned 32 bit (unsigned long), // "r" will overflow sooner than "sum". // The maximal possible immortal number using 32-bit "r" is exactly 190,875,592 (step 1,908). // With the unsigned 64-bit-implementation you can compute approx 819,855,292,164,868,960 digits without overflow. // Requires "aptitude install libgomp1" and "g++ -fopenmp" #define multithread #ifdef multithread #define TN_STATIC 2 #ifndef TN_STATIC // VTS Maximalregel: Mo-Fr 8-22 und Sa-So 10-24 nur 3 Kerne, in der Nacht 5 Kerne #define TN_DAY 2 #define TN_NIGHT 3 #define DAYTIME_WEEKEND_START 10 #define DAYTIME_WEEKEND_END 24 #define DAYTIME_WORKDAY_START 8 #define DAYTIME_WORKDAY_END 22 #endif #endif // Recommended! #define simple_selftest_step1 // ------------------------------------------------------------------------------------------------------ #include #include #include #include #include #ifdef r_bigint #define include_gmp #endif #ifdef sum_bigint #define include_gmp #endif #ifdef do_integrity_test #define include_gmp #endif #ifdef include_gmp #include #endif const char* DATA_FILENAME = "data.txt"; const char* DATA_NEW = "data.tmp"; const unsigned /* long long */ int SAVE_INTERVAL = 100000; // "1 Step" const char* FILE_LINE_ENDINGS = "\r\n"; #ifdef stats_general const char* STATS_GENERAL = "stats_general.txt"; #endif #ifdef stats_distribution const char* STATS_DISTRIBUTION = "stats_distribution.txt"; #endif const unsigned int BASE = 10; const unsigned int ROOT = 5; const unsigned /* long long */ int EXPANSION_SIZE = 10000000; const unsigned /* long long */ int INITIAL_SIZE = 10000000; const char* VERSION = "1.18"; // ------------------------------------------------------------------------------------------------------ static inline char* getTimeStamp(char *timestamp_buf, const int len) { time_t now = time(0); strftime(timestamp_buf, len, "%a, %d %b %Y %T %z", localtime(&now)); return timestamp_buf; } // ACHTUNG: BEI GROSSEN ZAHLEN GIBTS KERNEL PANIC, LOL (Speicher knapp) #ifdef do_integrity_test static inline bool isImmortal(const mpz_t n, const unsigned int m) { // unsigned int m = n.length(); mpz_t rop; mpz_init(rop); mpz_t m_pow; mpz_init(m_pow); mpz_ui_pow_ui(m_pow, 10, m); mpz_powm_ui(rop, n, 2, m_pow); // rop = n^2 % (mod 10^m) bool res = mpz_cmp(rop, n) == 0; mpz_clear(m_pow); mpz_clear(rop); return res; } #endif #ifdef multithread #ifndef TN_STATIC static inline int tn() { #ifdef TN_STATIC return TN_STATIC; #else // TODO: aus performancegründen die zeiterfassung tn() irgendwie buffern? time_t Zeitstempel; tm *t; Zeitstempel = time(0); t = localtime(&Zeitstempel); bool weekend = (t->tm_wday == 0) || (t->tm_wday == 6); bool night; if (weekend) { night = (t->tm_hour < DAYTIME_WEEKEND_START) || (t->tm_hour >= DAYTIME_WEEKEND_END); } else { night = (t->tm_hour < DAYTIME_WORKDAY_START) || (t->tm_hour >= DAYTIME_WORKDAY_END); } if (night) { return TN_NIGHT; } else { return TN_DAY; } #endif } #endif #endif static inline void mygetline(std::string* line, std::ifstream* myfile) { /* if (myfile.good()) return null; */ if (myfile->eof()) { *line = ""; return; } std::getline(*myfile, *line); if (line->size() == 0) return; if (line->at(line->size() - 1) == '\r') { line->resize(line->size() - 1); } } static inline time_t get_mtime(const char *path) { // http://stackoverflow.com/questions/4021479/getting-file-modification-time-on-unix-using-utime-in-c struct stat statbuf; if (stat(path, &statbuf) == -1) { perror(path); exit(EXIT_FAILURE); } return statbuf.st_mtime; } // TODO: mergen mit stats_distribution? die werte lieber direkt in der main() aus den variablen rausschreiben? wäre doch einfacherer! // TODO: csv wäre besser #ifdef stats_general static inline int main_stats_general(time_t unixtime, const char* maj_sig, const char* min_sig, std::string creation_time, std::string save_timestamp, unsigned int base, unsigned int root, unsigned /* long long */ int digits, unsigned long long int r) { std::ofstream myoutfile; myoutfile.open(STATS_GENERAL, std::ios::out | std::ios::app); // __try { myoutfile << "Unix time:\t" << unixtime << FILE_LINE_ENDINGS; myoutfile << "Maj. Sig:\t" << maj_sig << FILE_LINE_ENDINGS; myoutfile << "Min. Sig:\t" << min_sig << FILE_LINE_ENDINGS; myoutfile << "Testbegin:\t" << creation_time << FILE_LINE_ENDINGS; myoutfile << "Savetime:\t" << save_timestamp << FILE_LINE_ENDINGS; myoutfile << "Base:\t" << base << FILE_LINE_ENDINGS; myoutfile << "Root:\t" << root << FILE_LINE_ENDINGS; myoutfile << "Digit count:\t" << digits << FILE_LINE_ENDINGS; myoutfile << "Param r:\t" << r << FILE_LINE_ENDINGS; myoutfile << FILE_LINE_ENDINGS; // } __finally { myoutfile.close(); // } return EXIT_SUCCESS; } #endif #ifdef stats_distribution static inline int main_stats_distribution(unsigned char* a, unsigned /* long long */ int digits) { int count[10]; for (unsigned int i = 0; i < 10; ++i) count[i] = 0; // TODO: omp? for (unsigned int j = 0; j < digits; ++j) { ++count[a[j]]; } // Now save the stat std::ofstream myfile; myfile.open(STATS_DISTRIBUTION, std::ios::out); // __try { myfile << "Immortal Number Search" << FILE_LINE_ENDINGS; myfile << "Digit Stat 1.0" << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; unsigned int sigma = 0; for (unsigned int i = 0; i < 10; ++i) { myfile << "Digit " << i << "\t" << count[i] << FILE_LINE_ENDINGS; sigma += count[i]; } myfile << FILE_LINE_ENDINGS; myfile << "Sigma\t" << sigma << FILE_LINE_ENDINGS; myfile << "Digits\t" << digits << FILE_LINE_ENDINGS; myfile << "Sigma Match\t"; if (sigma == digits) { myfile << "OK"; } else { myfile << "FAILED!"; } myfile << FILE_LINE_ENDINGS; // } __finally { myfile.close(); // } return EXIT_SUCCESS; } #endif int main(void) { const char* SIGNATURE = "Immortal Number Report File Version 3.00"; const char* END_SIG = "END OF REPORT"; char SIGNATURE_MINOR[2048]; sprintf(SIGNATURE_MINOR, "Immortal Number Search for C++ %s", VERSION); #ifdef multithread sprintf(SIGNATURE_MINOR, "%s MT", SIGNATURE_MINOR); #endif #ifdef sum_bigint sprintf(SIGNATURE_MINOR, "%s sumGMP", SIGNATURE_MINOR); #else sprintf(SIGNATURE_MINOR, "%s sum%d", SIGNATURE_MINOR, (int)sizeof(unsigned long long int)*8 /* 8 bits = 1 byte */); #endif #ifdef r_bigint sprintf(SIGNATURE_MINOR, "%s rGMP", SIGNATURE_MINOR); #else sprintf(SIGNATURE_MINOR, "%s r%d", SIGNATURE_MINOR, (int)sizeof(unsigned long long int)*8 /* 8 bits = 1 byte */); #endif const unsigned int SOFTBREAK = 76; std::string creation_time; unsigned char* a; unsigned /* long long */ int a_size = INITIAL_SIZE; unsigned /* long long */ int top = -1; // u unsigned /* long long */ int digits = -1; // u+1 #ifdef r_bigint mpz_t r; mpz_init(r); #else register unsigned long long int r; // UINT64! #endif char debug_timestamp[255]; bool a_empty; #ifdef verbose getTimeStamp(debug_timestamp, 255); std::cout << debug_timestamp << " - Program started" << std::endl; #endif #ifdef use_multiply_lookup unsigned long int multiply_lookup[10][10]; for (int i = 0; i<10; ++i) { for (int j = 0; j<10; ++j) { multiply_lookup[i][j] = (unsigned long int)i*j; } } #endif std::string line; std::ifstream myfile(DATA_FILENAME); if (myfile.is_open()) { // __try { top = -1; digits = -1; #ifdef r_bigint mpz_set_si(r, -1); #else r = -1; #endif mygetline(&line, &myfile); if (strcmp(line.c_str(), SIGNATURE) != 0 /* not equal */) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Load error: Wrong format signature. Expecting '" << SIGNATURE << "'." << std::endl; myfile.close(); return EXIT_FAILURE; } mygetline(&line, &myfile); // Minor. signature mygetline(&line, &myfile); // "" mygetline(&line, &myfile); // "(Starting time)" mygetline(&creation_time, &myfile); mygetline(&line, &myfile); // "" mygetline(&line, &myfile); // "(Save timestamp)" mygetline(&line, &myfile); // Timestamp mygetline(&line, &myfile); // "" mygetline(&line, &myfile); // "(Base)" mygetline(&line, &myfile); // 10 unsigned int base = atoi(line.c_str()); if (base != BASE) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - This edition can only work with base = " << BASE << "." << std::endl; myfile.close(); return EXIT_FAILURE; } mygetline(&line, &myfile); // "" mygetline(&line, &myfile); // "(Root)" mygetline(&line, &myfile); // 5 unsigned int root = atoi(line.c_str()); if (root != ROOT) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - This edition can only work with root = " << ROOT << "." << std::endl; myfile.close(); return EXIT_FAILURE; } mygetline(&line, &myfile); // "" mygetline(&line, &myfile); // "(Digits)" mygetline(&line, &myfile); digits = atoi(line.c_str()); mygetline(&line, &myfile); // "" mygetline(&line, &myfile); // "(r)" mygetline(&line, &myfile); #ifdef r_bigint mpz_set_str(r, line.c_str(), 10); #else // atoi is for signed 32 bit // r = atoi(line.c_str()); r = strtoull(line.c_str(), NULL, 10); // strtoull is for uint64 #endif mygetline(&line, &myfile); // "" a_size = digits + EXPANSION_SIZE; a = (unsigned char*) calloc(a_size, sizeof(unsigned char)); if (a == NULL) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Memory allocation failed!" << std::endl; myfile.close(); return EXIT_FAILURE; } mygetline(&line, &myfile); // "(Reversed notation)" do { mygetline(&line, &myfile); for (unsigned int i = 0; i < line.length(); ++i) { unsigned char toadd = line.c_str()[i] - '0'; // Cannot overflow if input file is OK. a[++top] = toadd; a_empty = false; } } while (strcmp(line.c_str(), "") != 0 /* not equal */); if (digits != top + 1) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Corrupt: Formal and actual length mismatch!" << std::endl; myfile.close(); return EXIT_FAILURE; } mygetline(&line, &myfile); if (strcmp(line.c_str(), END_SIG) != 0 /* not equal */) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Corrupt: End-signature mismatch." << std::endl; myfile.close(); return EXIT_FAILURE; } // } __finally { myfile.close(); // } } else { a_size = INITIAL_SIZE; a = (unsigned char*) calloc(a_size, sizeof(unsigned char)); if (a == NULL) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Memory allocation failed!" << std::endl; return EXIT_FAILURE; } a_empty = true; } #ifdef do_integrity_test bool firstSave = true; #endif register unsigned /* long long */ int cnt = SAVE_INTERVAL; if (a_empty) { getTimeStamp(debug_timestamp, 255); creation_time = debug_timestamp; cnt -= 2; top += 2; if (top >= a_size) { a_size += EXPANSION_SIZE; a = (unsigned char*) realloc(a, a_size * sizeof(unsigned char)); if (a == NULL) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Memory reallocation failed!" << std::endl; return EXIT_FAILURE; } } a[top-1] = 5 /* ROOT */; a[top] = 2; a_empty = false; digits = 2; #ifdef r_bigint mpz_set_ui(r, a[top]); #else r = a[top]; #endif } #ifdef r_bigint mpz_t tmp_digit; mpz_init(tmp_digit); #endif #ifdef sum_bigint mpz_t sum; #else register unsigned long long int sum; // UINT64! #endif #ifdef multithread register unsigned /* long long */ int halfway; #endif #ifndef r_bigint ldiv_t divt; divt = ldiv(r, 10); #endif // TODO: Abbruchkriterium? z.B. signal? while (true) { #ifdef sum_bigint mpz_init(sum); #else sum = 0; #endif #ifdef multithread halfway = (top>>1) + 1; // = top/2 + 1 #ifdef sum_bigint #ifdef use_multiply_lookup #ifdef TN_STATIC #pragma omp parallel firstprivate/*shared*/(a, digits, halfway, multiply_lookup) num_threads(TN_STATIC) #else unsigned int tn = tn(); #pragma omp parallel firstprivate/*shared*/(a, digits, halfway, multiply_lookup) num_threads(tn) #endif #else #ifdef TN_STATIC #pragma omp parallel firstprivate/*shared*/(a, digits, halfway) num_threads(TN_STATIC) #else unsigned int tn = tn(); #pragma omp parallel firstprivate/*shared*/(a, digits, halfway) num_threads(tn) #endif #endif { mpz_t loc_sum; mpz_init(loc_sum); #pragma omp for for (unsigned int m = 1; m < halfway; ++m) { #ifdef use_multiply_lookup mpz_add_ui(loc_sum, loc_sum, (unsigned long int)multiply_lookup[a[m]][a[digits-m]]); #else mpz_add_ui(loc_sum, loc_sum, (unsigned long int)a[m] * a[digits-m]); #endif } #pragma omp critical(sum) mpz_add(sum, sum, loc_sum); mpz_clear(loc_sum); } #else // TODO: optimierbar...? z.B. Duff's device? multiply-lookup-table? chunksize? prallel block erweitern? performancetest! #ifdef use_multiply_lookup #ifdef TN_STATIC #pragma omp parallel for firstprivate/*shared*/(a, digits, halfway, multiply_lookup) num_threads(TN_STATIC) reduction(+ : sum) #else #pragma omp parallel for firstprivate/*shared*/(a, digits, halfway, multiply_lookup) num_threads(tn()) reduction(+ : sum) #endif #else #ifdef TN_STATIC #pragma omp parallel for firstprivate/*shared*/(a, digits, halfway) num_threads(TN_STATIC) reduction(+ : sum) #else #pragma omp parallel for firstprivate/*shared*/(a, digits, halfway) num_threads(tn()) reduction(+ : sum) #endif #endif for (unsigned int m = 1; m < halfway; ++m) { // __asm__ ("nop"); // marker #ifdef use_multiply_lookup sum += (unsigned long long int)multiply_lookup[a[m]][a[digits-m]]; /* mov %r12d, %ecx # ivtmp.319, ivtmp.319 movzbl (%rbx,%rcx), %edi #* ivtmp.319, tmp86 mov %edx, %ecx # m, m movzbl (%rbx,%rcx), %ecx #* m, tmp88 leaq (%rcx,%rcx,4), %rcx #, tmp91 leaq (%rdi,%rcx,2), %rcx #, tmp93 addq (%rsp,%rcx,8), %rsi # multiply_lookup, sum */ #else sum += (unsigned long long int)a[m] * a[digits-m]; /* mov %r13d, %ecx # ivtmp.312, ivtmp.312 mov %edx, %esi # m, m movzbl (%rbx,%rcx), %ecx #* ivtmp.312, tmp85 movzbl (%rbx,%rsi), %esi #* m, tmp84 imulq %rsi, %rcx # tmp84, tmp85 addq %rcx, %rdi # tmp85, sum */ #endif // __asm__ ("nop"); // marker } #endif #else register unsigned m, k; for (m = 1, k = top; m < k; ++m, --k) { #ifdef sum_bigint mpz_add_ui(sum, sum, (unsigned long int)a[m] * a[k]); #else #ifdef use_multiply_lookup sum += (unsigned long long int)multiply_lookup[a[m]][a[k]]; #else sum += (unsigned long long int)a[m] * a[k]; #endif #endif } #endif #ifdef r_bigint mpz_fdiv_q_ui(r, r, 10); // "floor" div mpz_add_ui(r, r, a[top]); #ifdef sum_bigint mpz_add(r, r, sum); mpz_add(r, r, sum); #else mpz_add_ui(r, r, sum+sum); #endif #else // r = (r - a[top]) / 10 + a[top] + 2*sum; #ifdef sum_bigint r = divt.quot + a[top] + 2*mpz_get_ui(sum); #else r = divt.quot + a[top] + sum + sum; #endif #endif #ifdef multithread if ((top&1 /*%2*/) != 0) { // m = top/2+1; unsigned int m = (top>>1)+1; #else if (m == k) { #endif #ifdef r_bigint #ifdef use_multiply_lookup mpz_add_ui(r, r, (unsigned long int)multiply_lookup[a[m]][a[m]]); #else mpz_add_ui(r, r, (unsigned long int)a[m] * a[m]); #endif #else #ifdef use_multiply_lookup r += (unsigned long long int)multiply_lookup[a[m]][a[m]]; #else r += (unsigned long long int)a[m] * a[m]; #endif #endif } // Increase digit count ++digits; // Do we need to expand our memory allocation? if (++top >= a_size) { a_size += EXPANSION_SIZE; a = (unsigned char*) realloc(a, a_size * sizeof(unsigned char)); if (a == NULL) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Memory reallocation failed!" << std::endl; return EXIT_FAILURE; } } #ifdef r_sum_debug std::cout << "R/Sum-Debug:\t" << digits << "\t" << r << "\t" << sum << std::endl; #endif // Write digit #ifdef r_bigint mpz_mod_ui(tmp_digit, r, 10); a[top] = mpz_get_ui(tmp_digit); #else // a[top] = r % 10; divt = ldiv(r, 10); a[top] = divt.rem; #endif if (--cnt == 0) { cnt = SAVE_INTERVAL; // Manual test #ifdef simple_selftest_step1 if (digits == 100000) { if (r != 2243589) { getTimeStamp(debug_timestamp, 255); std::cout << debug_timestamp << " - Simple selftest for step 1 failed: r mismatch..." << std::endl; return EXIT_FAILURE; #ifdef verbose } else { getTimeStamp(debug_timestamp, 255); std::cout << debug_timestamp << " - Simple selftest for step 1: OK!" << std::endl; #endif } } #endif #ifdef do_integrity_test if (firstSave) { // Wir führen beim ersten Speichern einen weiteren // integrity-Test durch. Grund: Wäre bei einer Fortsetzung einer // Datei das "r" falsch (der Datenteil aber korrekt), dann würde // diese Datei beim Speichern ungültige Daten enthalten (Zahl // nicht immortal). #ifdef verbose getTimeStamp(debug_timestamp, 255); std::cout << debug_timestamp << " - Beginning self test before first save..." << std::endl; #endif mpz_t num; mpz_init(num); mpz_t m_pow; mpz_init(m_pow); mpz_t ra; mpz_init(ra); for (unsigned int i = 0; i < digits; ++i) { unsigned char xa = a[i]; if (i > 0) { xa = 9 - xa; } else { xa = 11 - xa; } mpz_ui_pow_ui(m_pow, 10, i); mpz_mul_ui(ra, m_pow, xa); mpz_add(num, num, ra); } mpz_clear(ra); mpz_clear(m_pow); if (!isImmortal(num, digits)) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Integrity test failed. (Loaded file broken?) Will not save." << std::endl; return EXIT_FAILURE; } mpz_clear(num); } #endif getTimeStamp(debug_timestamp, 255); #ifdef verbose std::cout << debug_timestamp << " - Save at " << digits << " digits" << std::endl; #endif std::string save_timestamp = debug_timestamp; // Write data file std::ofstream myfile; myfile.open(DATA_NEW, std::ios::out); // __try { myfile << SIGNATURE << FILE_LINE_ENDINGS; myfile << SIGNATURE_MINOR << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; myfile << "(Starting time)" << FILE_LINE_ENDINGS; myfile << creation_time << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; myfile << "(Save timestamp)" << FILE_LINE_ENDINGS; myfile << save_timestamp << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; myfile << "(Base)" << FILE_LINE_ENDINGS; myfile << BASE << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; myfile << "(Root)" << FILE_LINE_ENDINGS; myfile << ROOT << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; myfile << "(Digits)" << FILE_LINE_ENDINGS; myfile << digits << FILE_LINE_ENDINGS; myfile << FILE_LINE_ENDINGS; myfile << "(r)" << FILE_LINE_ENDINGS; myfile << r << FILE_LINE_ENDINGS; // hierfür ist "-lgmpxx" notwendig anstelle "-lgmp" (gmpxx ersetzt gmp) myfile << FILE_LINE_ENDINGS; myfile << "(Reversed notation)" << FILE_LINE_ENDINGS; unsigned int i; for (i = 0; i <= top; ++i) { unsigned char xa = a[i] + '0'; myfile << xa; if ((i + 1) % SOFTBREAK == 0) { myfile << FILE_LINE_ENDINGS; } } if (i % SOFTBREAK != 0) { /* nicht +1, da ++i am Ende der FOR-Schleife */ myfile << FILE_LINE_ENDINGS; } myfile << FILE_LINE_ENDINGS; myfile << END_SIG << FILE_LINE_ENDINGS; // } __finally { myfile.close(); // } // Integrity Test #ifdef do_integrity_test if (firstSave) { #ifdef verbose getTimeStamp(debug_timestamp, 255); std::cout << debug_timestamp << " - First save absolved. Stable phase has begun." << std::endl; #endif firstSave = false; } #endif // Create statistics #ifdef stats_distribution { int res = main_stats_distribution(a, digits); if (res != EXIT_SUCCESS) return res; } #endif #ifdef stats_general { int res = main_stats_general(get_mtime(DATA_NEW), SIGNATURE, SIGNATURE_MINOR, creation_time, save_timestamp, BASE, ROOT, digits, r); if (res != EXIT_SUCCESS) return res; } #endif // Replace the old data file int res = rename(DATA_NEW, DATA_FILENAME); if (res != 0) { getTimeStamp(debug_timestamp, 255); std::cerr << debug_timestamp << " - Could not move '" << DATA_NEW << "' to '" << DATA_FILENAME << "' (Error code " << res << ")." << std::endl; return EXIT_FAILURE; } } } #ifdef r_bigint mpz_clear(tmp_digit); mpz_clear(r); #endif #ifdef sum_bigint mpz_clear(sum); #endif }