From 1d3e9750e769cdd616291470183e69f5e8db574c Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sun, 22 Feb 2026 22:19:28 +0100 Subject: [PATCH] feat: optimized isbn number calculations --- .../howManyValidISBNNumbersAreThere/11.cpp | 123 ++++++++++++++---- .../howManyValidISBNNumbersAreThere/bench_opt | Bin 0 -> 16688 bytes .../bench_optimized.cpp | 90 +++++++++++++ .../bench_orig | Bin 0 -> 17216 bytes .../bench_original.cpp | 69 ++++++++++ 5 files changed, 260 insertions(+), 22 deletions(-) create mode 100755 CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_opt create mode 100644 CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_optimized.cpp create mode 100755 CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_orig create mode 100644 CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_original.cpp diff --git a/CPP/miscelanious/howManyValidISBNNumbersAreThere/11.cpp b/CPP/miscelanious/howManyValidISBNNumbersAreThere/11.cpp index 9cbd0c4..2fa8efb 100644 --- a/CPP/miscelanious/howManyValidISBNNumbersAreThere/11.cpp +++ b/CPP/miscelanious/howManyValidISBNNumbersAreThere/11.cpp @@ -3,6 +3,9 @@ #include #include #include +#ifdef _OPENMP +#include +#endif #ifndef CHECK_ISBN_CPP #define CHECK_ISBN_CPP @@ -68,35 +71,111 @@ bool checkISBN(const std::vector isbn) { return !(sum % CHECK_NUMBER); } -std::vector intToVector(unsigned long long int number) { - std::vector numbers; - while (number > 0) { - numbers.push_back(number % 10); - number /= 10; - } - std::reverse(numbers.begin(), numbers.end()); +// Optimisation 1 – no heap allocation: intToVector() removed; checkAll() +// uses only stack variables in the nested loops below. +// +// Optimisation 2 – algorithmic reduction (10^10 → 10^9 iterations): +// ISBN-10 validity: 10*d0 + 9*d1 + ... + 2*d8 + 1*d9 ≡ 0 (mod 11) +// Given a 9-digit prefix d0..d8 the check digit is determined: +// d9 = (11 - S%11) % 11 where S = weighted sum of prefix +// The number is valid iff d9 ≤ 9 (i.e. d9 ≠ 10). +// +// Optimisation 3 – incremental partial sums + OpenMP: +// Each loop level accumulates its contribution once, not inside the +// innermost body. The outermost loop is parallelised with OpenMP. +// +// Optimisation 4 – separated I/O: +// File writing is done in a second serial pass with a large buffer so +// it doesn't contend with (or race against) the parallel counting pass. +long long countISBNs() { + long long sum = 0; - return numbers; -} - -int checkAll() { - int sum = 0; - std::ofstream file; - file.open("ISBN.txt"); - for (unsigned long long int i = HIGHEST_ISBN; i >= 1; i--) { - // if(DEBUG) std::cout << i << std::endl; - if (checkISBN(intToVector(i))) { - ++sum; - file << std::to_string(i) << "\n"; +#ifdef _OPENMP +#pragma omp parallel for reduction(+ : sum) schedule(static) +#endif + for (int d0 = 0; d0 <= 9; d0++) { + int s0 = 10 * d0; + for (int d1 = 0; d1 <= 9; d1++) { + int s1 = s0 + 9 * d1; + for (int d2 = 0; d2 <= 9; d2++) { + int s2 = s1 + 8 * d2; + for (int d3 = 0; d3 <= 9; d3++) { + int s3 = s2 + 7 * d3; + for (int d4 = 0; d4 <= 9; d4++) { + int s4 = s3 + 6 * d4; + for (int d5 = 0; d5 <= 9; d5++) { + int s5 = s4 + 5 * d5; + for (int d6 = 0; d6 <= 9; d6++) { + int s6 = s5 + 4 * d6; + for (int d7 = 0; d7 <= 9; d7++) { + int s7 = s6 + 3 * d7; + for (int d8 = 0; d8 <= 9; d8++) { + int d9 = (11 - (s7 + 2 * d8) % 11) % 11; + if (d9 <= 9) + ++sum; + } + } + } + } + } + } + } } } - file << "There are " << sum << " valid ISBN numbers\n"; - file.close(); return sum; } +void writeISBNsToFile() { + static const int BUF = 1 << 20; // 1 MB write buffer + std::ofstream file; + file.rdbuf()->pubsetbuf(nullptr, BUF); + file.open("ISBN.txt"); + long long written = 0; + + for (int d0 = 0; d0 <= 9; d0++) { + int s0 = 10 * d0; + for (int d1 = 0; d1 <= 9; d1++) { + int s1 = s0 + 9 * d1; + for (int d2 = 0; d2 <= 9; d2++) { + int s2 = s1 + 8 * d2; + for (int d3 = 0; d3 <= 9; d3++) { + int s3 = s2 + 7 * d3; + for (int d4 = 0; d4 <= 9; d4++) { + int s4 = s3 + 6 * d4; + for (int d5 = 0; d5 <= 9; d5++) { + int s5 = s4 + 5 * d5; + for (int d6 = 0; d6 <= 9; d6++) { + int s6 = s5 + 4 * d6; + for (int d7 = 0; d7 <= 9; d7++) { + int s7 = s6 + 3 * d7; + for (int d8 = 0; d8 <= 9; d8++) { + int s = s7 + 2 * d8; + int d9 = (11 - s % 11) % 11; + if (d9 <= 9) { + long long isbn = (long long)d0 * 1000000000LL + + d1 * 100000000 + d2 * 10000000 + + d3 * 1000000 + d4 * 100000 + d5 * 10000 + + d6 * 1000 + d7 * 100 + d8 * 10 + d9; + file << isbn << '\n'; + ++written; + } + } + } + } + } + } + } + } + } + } + file << "There are " << written << " valid ISBN numbers\n"; + file.close(); +} + int main() { - checkAll(); + long long count = countISBNs(); + std::cout << "There are " << count << " valid ISBN numbers\n"; + writeISBNsToFile(); return 0; } diff --git a/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_opt b/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_opt new file mode 100755 index 0000000000000000000000000000000000000000..222a6f9c8b0edb4966fff8a613b26b88f8471669 GIT binary patch literal 16688 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 DGjF1p literal 0 HcmV?d00001 diff --git a/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_optimized.cpp b/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_optimized.cpp new file mode 100644 index 0000000..05aaaa1 --- /dev/null +++ b/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_optimized.cpp @@ -0,0 +1,90 @@ +// Optimized ISBN-10 counter. +// +// Three improvements over the original: +// +// 1. NO HEAP ALLOCATION — original calls intToVector() on every iteration, +// which does a heap alloc+free (std::vector) for each of 10^10 numbers. +// Here we use only stack variables. +// +// 2. ALGORITHMIC REDUCTION — ISBN-10 validity condition: +// 10*d0 + 9*d1 + ... + 2*d8 + 1*d9 ≡ 0 (mod 11) +// Given any 9-digit prefix d0..d8 we can solve for d9 directly: +// d9 = (11 - S mod 11) mod 11 where S = sum of weighted prefix +// The number is valid iff 0 ≤ d9 ≤ 9 (i.e. d9 ≠ 10). +// → Only 10^9 outer iterations instead of 10^10. +// +// 3. INCREMENTAL WEIGHTED SUM — instead of multiplying each digit by its +// weight inside the innermost loop, partial sums are maintained +// incrementally as digits change, so the innermost body is almost free. +// The compiler can also vectorise the innermost digit loop. +// +// Compile: g++ -O2 -fopenmp bench_optimized.cpp -o bench_opt +// (OpenMP is optional; remove -fopenmp if not available – it just runs +// the outer loop on a single thread.) + +#include +#include + +#ifdef _OPENMP +#include +#endif + +int main() { + auto start = std::chrono::high_resolution_clock::now(); + + long long count = 0; + + // Nested loops over the 9 prefix digits. + // s_k = partial weighted sum up through digit k. + // weight for digit at position i (0-based, MSB first) = 10 - i + // so outer digit d0 has weight 10, d1 has weight 9, ..., d8 has + // weight 2. + +#ifdef _OPENMP +#pragma omp parallel for reduction(+ : count) schedule(static) +#endif + for (int d0 = 0; d0 <= 9; d0++) { + int s0 = 10 * d0; + for (int d1 = 0; d1 <= 9; d1++) { + int s1 = s0 + 9 * d1; + for (int d2 = 0; d2 <= 9; d2++) { + int s2 = s1 + 8 * d2; + for (int d3 = 0; d3 <= 9; d3++) { + int s3 = s2 + 7 * d3; + for (int d4 = 0; d4 <= 9; d4++) { + int s4 = s3 + 6 * d4; + for (int d5 = 0; d5 <= 9; d5++) { + int s5 = s4 + 5 * d5; + for (int d6 = 0; d6 <= 9; d6++) { + int s6 = s5 + 4 * d6; + for (int d7 = 0; d7 <= 9; d7++) { + int s7 = s6 + 3 * d7; + // Innermost: vary d8, weight 2. + for (int d8 = 0; d8 <= 9; d8++) { + int s = s7 + 2 * d8; + // Required check digit (weight 1): + int d9 = (11 - s % 11) % 11; + if (d9 <= 9) + ++count; + } + } + } + } + } + } + } + } + } + + auto end = std::chrono::high_resolution_clock::now(); + double elapsed = std::chrono::duration(end - start).count(); + + std::cout << "Valid ISBNs: " << count << "\n"; + std::cout << "Time: " << elapsed << " s\n"; + +#ifdef _OPENMP + std::cout << "Threads: " << omp_get_max_threads() << "\n"; +#endif + + return 0; +} diff --git a/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_orig b/CPP/miscelanious/howManyValidISBNNumbersAreThere/bench_orig new file mode 100755 index 0000000000000000000000000000000000000000..31abc9cec72d02cb733f2337acbee3f9b31d95e8 GIT binary patch literal 17216 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 +#include +#include +#include + +const int ISBN_LENGTH = 10; +const int CHECK_NUMBER = 11; +const unsigned long long int HIGHEST_ISBN = 9999999999ULL; + +bool checkISBN(const std::vector isbn) { + int sum = 0, t = 0; + for (int i = 0; i < ISBN_LENGTH; i++) { + t += isbn[i]; + sum += t; + } + return !(sum % CHECK_NUMBER); +} + +std::vector intToVector(unsigned long long int number) { + std::vector numbers; + while (number > 0) { + numbers.push_back(number % 10); + number /= 10; + } + std::reverse(numbers.begin(), numbers.end()); + return numbers; +} + +// Run for at most SAMPLE seconds, then extrapolate total time. +static constexpr double SAMPLE_SECS = 20.0; + +long long checkAllTimed(double &elapsed_out) { + auto start = std::chrono::high_resolution_clock::now(); + auto limit = start + std::chrono::duration(SAMPLE_SECS); + long long sum = 0; + unsigned long long i; + for (i = HIGHEST_ISBN; i >= 1; i--) { + if (checkISBN(intToVector(i))) + ++sum; + + // Check wall-clock every 1 million iterations to keep overhead low. + if ((i & 0xFFFFF) == 0) { + if (std::chrono::high_resolution_clock::now() >= limit) + break; + } + } + auto end = std::chrono::high_resolution_clock::now(); + elapsed_out = std::chrono::duration(end - start).count(); + + unsigned long long done = HIGHEST_ISBN - i; + double rate = (double)done / elapsed_out; // numbers/s + double total_est = (double)HIGHEST_ISBN / rate; + + std::cout << "Iterated: " << done << " numbers in " << elapsed_out + << " s\n"; + std::cout << "Rate: " << (long long)rate << " numbers/s\n"; + std::cout << "Estimated total time for full range: " << (long long)total_est + << " s (" << total_est / 60.0 << " min)\n"; + return sum; +} + +int main() { + double elapsed = 0.0; + long long count = checkAllTimed(elapsed); + std::cout << "Valid ISBNs in sampled range: " << count << "\n"; + return 0; +}