#define WANT_OBFUSCATING_OPERATORS #include #include #include #include #include #include "palindromic.h" using namespace std; using namespace cln; bool greedy_binary(int bits, cl_I input, int start) { bool lsb, msb; int reverse = bits - start - 1; // we could make this bits/2, I think. or bin.getNumVars() for (int counter = start; counter < reverse; counter++) { /* lsb = (input >> counter) & 1; msb = (input >> reverse) & 1;*/ lsb = logbitp(counter, input); msb = logbitp(reverse, input); reverse--; if (lsb != msb) return(false); } return(true); } void check_try(Palindromic binary, Palindromic decimal, cl_I residue, int decimal_pos, cl_I cur_try, int last_decimal, bool force_on, cl_I * binary_running_sum, cl_I * decimal_running_sum, unsigned long long & ctr, unsigned long long & actr) { // binary: obvious // decimal: again, obvious // residue: difference given to previous bits. Must be subtracted // for the routine to work // decimal_pos: current decimal position // force_on: Should the bit be forced on? static cl_I adjusted_cur_try, out_residue; bool contradiction, less_than_binary, should_have_binary_on; int bits = binary.getDigits(); // cur_try starts with zeroes at our current position. if (decimal_pos + 10 == last_decimal) cout << ctr << " recursions so far." << endl; for (int counter = 0; counter < 10; counter++) { if (counter > 0) cur_try += *decimal.getConstant(decimal_pos); adjusted_cur_try = cur_try - residue; /*if (decimal_pos == last_decimal) if (adjusted_cur_try < 0) continue;*/ // if the adjusted current try is greater than the current // running sum, there's no way we can represent it, because // the superincreasing property limits our representation. if (adjusted_cur_try > binary_running_sum[decimal_pos]) continue; // It's a contradiction if our modulus calculation shows // the least bit doesn't correspond to what the superincreasing // property says about the number's highest addend. // Find out if the latter bit says we should be larger or // smaller than the binary constant. // // Then find out if we're at a phase transition // (adjusted_cur_try < binary constant, but adjusted_cur_try + // next decimal constant > binary_constant) // // If not, do a simple calculation of contradiction as before // and bail if we have a contradiction // // If we're at a phase transition, shift adjusted_cur_try // left until we're above it, incrementing "barrier" // each time (closest approximation to where it becomes high; // 2, 4, 8), and // if should_have_binary_on is on, set the start // to this digit. otherwise, set the end to this digit. // (assuming end isn't covered) if (decimal_pos != last_decimal) adjusted_cur_try += decimal_running_sum[decimal_pos+1]; // if it's less than zero, that means that there's no // possible way we can get a number out of this (similar to // the binary superincreasing property). // // This relies on the addition above. if (adjusted_cur_try < 0) continue; should_have_binary_on = logbitp(decimal_pos, adjusted_cur_try); // there used to be a clause here saying "if less_than_binary // then (...)" to cut down on time. However, it has been // removed because the optimization (if it's false then it // must always be so for higher numbers) doesn't hold true. // (Dunno when; maybe for negatives. I "can't be arsed" to find // out.) less_than_binary = ( adjusted_cur_try < *binary.getConstant(decimal_pos) ); contradiction = (should_have_binary_on == less_than_binary); // We're not using adjusted_cur_try anymore, so we don't need // to subtract. // If the bit is forced on, and it must be off, then we // have a contradiction. if (force_on && less_than_binary) contradiction = true; if (!contradiction) { ctr++; if (decimal_pos == last_decimal) { actr++; if (greedy_binary(binary.getDigits(), adjusted_cur_try, decimal_pos)) { cout << "\n##############################################################################\n"; cout << "Palindrome: " << cur_try << endl; cout << "##############################################################################\n"; } continue; } if (should_have_binary_on) { out_residue = residue + *binary.getConstant( decimal_pos); check_try(binary, decimal, out_residue, decimal_pos+1, cur_try, last_decimal, false, binary_running_sum, decimal_running_sum, ctr, actr); } else check_try(binary, decimal, residue, decimal_pos+1, cur_try, last_decimal, false, binary_running_sum, decimal_running_sum, ctr, actr); } } } // This is 16 bits slower than the pure integer solution. (This means that // solving 30 bits here takes as much time as solving 46 bits on the integer // solution) void renamed_main_function(int bits, bool use_upper, bool & can_use_upper) { //const int bits = 91; int upper_digits, lower_digits, cur_digits; double conversion_factor = log(2.0)/log(10.0); upper_digits = floor(bits*conversion_factor)+1; lower_digits = floor((bits-1)*conversion_factor)+1; can_use_upper = (lower_digits != upper_digits); if (use_upper) cur_digits = upper_digits; else cur_digits = lower_digits; Palindromic binary(2, bits); Palindromic decimal(10, cur_digits); int counter; unsigned long long ctr = 0, actr = 0; // we need a running sum to remove that which we can never reach. // It may be possible to make the search phase more efficient by // detecting "phase transitions" and locking cl_I binary_sum[binary.getNumVars()], decimal_sum[decimal.getNumVars()]; cl_I binrunsum = 0, decrunsum = 0; for (counter = binary.getNumVars()-1; counter >= 0; counter--) { binrunsum += *binary.getConstant(counter); binary_sum[counter] = binrunsum; } for (counter = decimal.getNumVars()-1; counter >= 0; counter--) { decrunsum += (*decimal.getConstant(counter) * 9); decimal_sum[counter] = decrunsum; // cout << decrunsum << endl; } /*for (counter = 0; counter < binary.getNumVars(); counter++) { cout << binary_sum[counter] << endl; }*/ //for (counter = 0; counter < 8192; counter++) { // check_try(binary, decimal, 0, 0, 0, decimal.getNumVars()-1, true, binary_sum, decimal_sum, ctr, actr); //} cout << endl; cout << ctr << " candidate trawls." << endl; cout << actr << " candidate numbers. " << endl << endl; cout << (double)actr/(double)ctr * 100 << "% search phase "; cout << "efficiency."; cout << endl; } main(int argc, char ** argv) { bool use_upper = false; int startbits = 80; if (argc > 1) { startbits = (int) atoi (argv[1]); } else { printf("dwpalin \n"); exit(1); } for (int counter = startbits; counter < 120; counter++) { cout << "-------------------------------" << endl; cout << counter << " bits follows." << endl; renamed_main_function(counter, false, use_upper); if (use_upper) { cout << "Use upper: " << endl; renamed_main_function(counter, true, use_upper); use_upper = false; } // comment out the next few lines if you want it to continue to the next // bitlength instead of exit: // cout << endl; cout <<"Done searching the "<