diff --git a/Sheet1/mainEx3.cpp b/Sheet1/mainEx3.cpp new file mode 100644 index 0000000..94b606b --- /dev/null +++ b/Sheet1/mainEx3.cpp @@ -0,0 +1,52 @@ +#include +#include +using namespace std; +using namespace std::chrono; + +long long sumMultiplesLoop(int n) { // long long is like int but for big numbers + long long sum = 0; + for (int i = 1; i <= n; ++i) { + if (i % 3 == 0 || i % 5 == 0) { + sum += i; + } + } + return sum; +} + +long long sumOfMultiples(int n, int k) { //known formula: k*m*(m+1)/2 for multiples of k leq n + long long m = n / k; // how many multiples + return (long long)k * m * (m + 1) / 2; +} + +// Formula version (no loop) +long long sumMultiplesFormula(int n) { + return sumOfMultiples(n, 3) + sumOfMultiples(n, 5) - sumOfMultiples(n, 15); //subtract multiples of 15 because they count double +} + +int main() { + int n = 1432987; + + auto start1 = high_resolution_clock::now(); + long long result1 = 0; + for (int i = 0; i < 1000; ++i) { + result1 = sumMultiplesLoop(n); + } + auto end1 = high_resolution_clock::now(); + duration average1 = (end1 - start1) / 1000; + + auto start2 = high_resolution_clock::now(); + long long result2 = 0; + for (int i = 0; i < 1000; ++i) { + result2 = sumMultiplesFormula(n); + } + auto end2 = high_resolution_clock::now(); + duration average2 = (end2 - start2) / 1000; + + cout << "Loop result: " << result1 << endl; + cout << "Loop average time: " << average1.count() << " seconds" << endl; + cout << "Formula result: " << result2 << endl; + cout << "Formula average time: " << average2.count() << " seconds" << endl; + + return 0; +} + diff --git a/Sheet1/mainEx4.cpp b/Sheet1/mainEx4.cpp new file mode 100644 index 0000000..6f6128d --- /dev/null +++ b/Sheet1/mainEx4.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +using namespace std; + +double NormalSeries(size_t N) +{ + double sum = 0.0; + for (size_t i = 1; i <= N; ++i) + { + sum += 1.0 / (double(i) * double(i)); + } + return sum; +} + +double KahanSeries(size_t N) +{ + double sum = 0.0; + double c = 0.0; + for (size_t i = 1; i <= N; ++i) { + double term = 1.0 / (double(i) * double(i)); + double y = term - c; + double t = sum + y; + c = (t - sum) - y; + sum = t; + } + return sum; +} + +int main() +{ + const double pi2_over_6 = (M_PI * M_PI) / 6.0; + // vector ns = {10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000}; + vector ns = {1000000, 10000000, 100000000, 500000000, 1000000000}; + + + for (size_t n : ns) + { + double s_norm = NormalSeries(n); + double s_kahan = KahanSeries(n); + double err_norm = fabs(s_norm - pi2_over_6); + double err_kahan = fabs(s_kahan - pi2_over_6); + + cout.setf(ios::fixed); + cout.precision(10); + cout << "\n--- n = " << n << " ---" << endl; + cout << "Normal summation: " << s_norm << endl; + cout << "Normal error: " << err_norm << endl; + cout << "Kahan summation: " << s_kahan << endl; + cout << "Kahan error: " << err_kahan << endl; + } + + return 0; +} diff --git a/Sheet1/mainEx5.cpp b/Sheet1/mainEx5.cpp new file mode 100644 index 0000000..e38f1eb --- /dev/null +++ b/Sheet1/mainEx5.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include // for lower_bound and is_sorted +#include // for random number generation +#include // for timing +using namespace std; + +void insertIntoVector(vector& vec, int n) +{ + minstd_rand generator; + uniform_int_distribution distribution(1, n); + + for (int i = 0; i < n; ++i) + { + int value = distribution(generator); + auto position = lower_bound(vec.begin(), vec.end(), value); + vec.insert(position, value); + } + if (!is_sorted(vec.begin(), vec.end())) + cout << "Warning: Vector is not sorted!\n"; +} + +void insertIntoList(list& lst, int n) +{ + minstd_rand generator; + uniform_int_distribution distribution(1, n); + for (int i = 0; i < n; ++i) + { + int value = distribution(generator); + auto position = find_if(lst.begin(), lst.end(), + [value](int x){ return x >= value; }); + lst.insert(position, value); + } + vector tmp(lst.begin(), lst.end()); + if (!is_sorted(tmp.begin(), tmp.end())) + cout << "Warning: List is not sorted!\n"; +} + +double measureVector(int n) +{ + vector vec(n); + for (int i = 0; i < n; ++i) + vec[i] = i + 1; + + auto start = chrono::high_resolution_clock::now(); + insertIntoVector(vec, n); + auto end = chrono::high_resolution_clock::now(); + chrono::duration elapsed = end - start; + + cout << "Vector final size: " << vec.size() + << ", is_sorted: " << boolalpha + << is_sorted(vec.begin(), vec.end()) << endl; + + return elapsed.count(); +} + +double measureList(int n) +{ + list lst; + for (int i = 1; i <= n; ++i) + lst.push_back(i); + + auto start = chrono::high_resolution_clock::now(); + insertIntoList(lst, n); + auto end = chrono::high_resolution_clock::now(); + chrono::duration elapsed = end - start; + + vector tmp(lst.begin(), lst.end()); + cout << "List final size: " << lst.size() + << ", is_sorted: " << boolalpha + << is_sorted(tmp.begin(), tmp.end()) << endl; + + return elapsed.count(); +} + +int main() +{ + int testSizes[] = {1000, 5000, 10000}; + + for (int i = 0; i < 3; ++i) + { + int n = testSizes[i]; + cout << "--- n = " << n << " ---" << endl; + + double timeVec = measureVector(n); + double timeList = measureList(n); + + cout << "Vector time: " << timeVec << " seconds" << endl; + cout << "List time: " << timeList << " seconds" << endl; + cout << endl; + } + return 0; +} diff --git a/Sheet1/mainEx6.cpp b/Sheet1/mainEx6.cpp new file mode 100644 index 0000000..cd5dce1 --- /dev/null +++ b/Sheet1/mainEx6.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include +#include "mayer_primes.h" +using namespace std; + +#include "mayer_primes.h" + +int single_goldbach(int k, const vector& primes, const vector& is_prime) //how many pairs (p,q) satisfy p+q=k +{ + int count = 0; + for (size_t i = 0; i < primes.size(); ++i) + { + int p = primes[i]; + if (p > k / 2) break; + int q = k - p; //compute the complementary number + if (q >= 0 && q < (int)is_prime.size() && is_prime[q]) //check if the q is prime too + ++count; + } + return count; +} + +vector> count_goldbach(int n, const vector& primes, const vector& is_prime) +{ + vector> results; + for (int k = 4; k <= n; k += 2) //loop over evn numbers + { + int c = single_goldbach(k, primes, is_prime); // how many pairs do we have for each k + results.push_back({k, c}); //append the result for each k + } + return results; +} + +vector>> all_decompositions(int n, const vector& primes, const vector& is_prime) +{ + vector>> out; //container for all the decopomistions of one k + for (int k = 4; k <= n; k += 2) //loop over even numbers + { + vector> decomp; // temporary vector to accumulate pairs of that particular k + for (size_t i = 0; i < primes.size(); ++i) + { + int p = primes[i]; + if (p > k / 2) break; + int q = k - p; + if (q >= 0 && q < (int)is_prime.size() && is_prime[q]) + decomp.push_back({p, q}); //same as earlier, check if q and p are both prime, if yes, saves the tuple + } + out.push_back(std::move(decomp)); //add all of the tuples to the vector out for this k + } + return out; +} + +vector make_is_prime(int n, const vector& primes) +{ + vector is_prime(n + 1, 0); //makes a vector 0...n with =1 if x is prime, 0 if not. + for (int p : primes) + { + if (p <= n) is_prime[p] = 1; + } + return is_prime; +} + +int main() +{ + //vector test_ns = {10000, 100000, 400000, 1000000, 2000000}; + vector test_ns = {10000, 100000, 400000}; + for (int n : test_ns) + { + cout << "Computing up to n = " << n << " even numbers from 4 to n \n"; + auto t0 = chrono::system_clock::now(); + + vector primes = get_primes(n); //generates all prime + auto t1 = chrono::system_clock::now(); + chrono::duration gen_time = t1 - t0; + + cout << "Generated " << primes.size() << " primes up to " << n + << " in " << gen_time.count() << " s\n"; + + vector is_prime = make_is_prime(n, primes); //creates the boolean vector for that particular n + + auto start = chrono::system_clock::now(); + vector> results = count_goldbach(n, primes, is_prime); //computes for all even k up to n + auto end = chrono::system_clock::now(); + chrono::duration elapsed = end - start; + + int max_k = 0; + int max_count = 0; + for (size_t i = 0; i < results.size(); ++i) //find the k with most decomposition + { + int k = results[i].first; + int count = results[i].second; + if (count > max_count) + { + max_count = count; + max_k = k; + } + } + cout << "Max decompositions: k = " << max_k + << " with " << max_count << " decompositions\n"; + + cout << "Time to count decompositions (count_goldbach): " + << elapsed.count() << " s\n"; + cout << "--- \n"; + } + + return 0; +} \ No newline at end of file diff --git a/Sheet1/mainEx7.cpp b/Sheet1/mainEx7.cpp new file mode 100644 index 0000000..c2a8f8d --- /dev/null +++ b/Sheet1/mainEx7.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +double sigmoid(double x) { + return 1.0 / (1.0 + exp(-x)); +} + +class DenseMatrix { +private: + int n, m; + vector data; + +public: + // Constructor + DenseMatrix(int n_, int m_) : n(n_), m(m_), data(n_ * m_) { //initalizes n,m, allocates data with n*m elements = 0 + int nm; + if (n > m) + nm = n; + else + nm = m; + + for (int i = 0; i < n; ++i) { //for each row index compute xi + double xi = 10.0 * i / (nm - 1) - 5.0; + for (int j = 0; j < m; ++j) { //for each column index compute xj + double xj = 10.0 * j / (nm - 1) - 5.0; + data[i * m + j] = sigmoid(xi) * sigmoid(xj); //compute every element + } + } + } + + vector Mult(const vector &u) const { + assert((int)u.size() == m); //checks if the dimensions match + vector result(n, 0.0); //prepares the empty vector, size n + for (int i = 0; i < n; ++i) { + for (int j = 0; j < m; ++j) { + result[i] += data[i * m + j] * u[j]; //row wise acces + } + } + return result; + } + + vector MultT(const vector &v) const { //same as above, but the other way + assert((int)v.size() == n); + vector result(m, 0.0); + for (int j = 0; j < m; ++j) { + for (int i = 0; i < n; ++i) { + result[j] += data[i * m + j] * v[i]; + } + } + return result; + } +}; + +class TensorMatrix { //rank one matrix M=u*v^T +private: + int n; + vector u, v; + +public: + TensorMatrix(int n_) : n(n_), u(n_), v(n_) { + for (int k = 0; k < n; ++k) { + double xk = 10.0 * k / (n - 1) - 5.0; + u[k] = sigmoid(xk); + v[k] = sigmoid(xk); //ensures simmetry + } + } + + vector Mult(const vector &x) const { + assert((int)x.size() == n); //does u*(v^T*x) so the parenthesis first + vector result(n, 0.0); + double dot_vx = 0.0; + for (int k = 0; k < n; ++k) + dot_vx += v[k] * x[k]; + for (int i = 0; i < n; ++i) + result[i] = u[i] * dot_vx; + return result; + } + + vector MultT(const vector &y) const { //same as above + assert((int)y.size() == n); + vector result(n, 0.0); + double dot_uy = 0.0; + for (int k = 0; k < n; ++k) + dot_uy += u[k] * y[k]; + for (int j = 0; j < n; ++j) + result[j] = v[j] * dot_uy; + return result; + } +}; + + +int main() { + DenseMatrix M(5, 3); //example with a small dense matrix + vector u = {1, 2, 3}; + vector f1 = M.Mult(u); + vector v = {-1, 2, -3, 4, -5}; + vector f2 = M.MultT(v); + + cout << "Result of M.Mult(u): "; + for (double x : f1) cout << x << " "; + cout << endl; + cout << "Result of M.MultT(v): "; + for (double x : f2) cout << x << " "; + cout << endl; + + int n = 1000; //example with a big matrix + + vector w(n); //random non trivial test vector w + std::mt19937 gen(42); + std::uniform_real_distribution dist(-1.0, 1.0); //values uniformly distributed in [-1,1] + for (int i = 0; i < n; ++i) + w[i] = dist(gen); + + int NLOOPS = 50; //how many repetitions + + DenseMatrix M2(n, n); //Matrix + vector res1, res2; + + auto t0 = chrono::system_clock::now(); + for (int k = 0; k < NLOOPS; ++k) + res1 = M2.Mult(w); + auto t1 = chrono::system_clock::now(); + chrono::duration timeMult = (t1 - t0) / NLOOPS; + + t0 = chrono::system_clock::now(); + for (int k = 0; k < NLOOPS; ++k) + res2 = M2.MultT(w); + t1 = chrono::system_clock::now(); + chrono::duration timeMultT = (t1 - t0) / NLOOPS; + + cout << "\nAverage time per Mult: " << timeMult.count() << " sec\n"; + cout << "Average time per MultT: " << timeMultT.count() << " sec\n"; + + double diff = 0.0; + for (int i = 0; i < n; ++i) + diff += fabs(res1[i] - res2[i]); + diff /= n; + cout << "Average difference between Mult and MultT results: " << diff << endl; + + TensorMatrix T(n); //Tensor + vector res1T, res2T; + + auto t0T = chrono::system_clock::now(); + for (int k = 0; k < NLOOPS; ++k) + res1T = T.Mult(w); + auto t1T = chrono::system_clock::now(); + chrono::duration timeMult2 = (t1T - t0T) / NLOOPS; + + t0T = chrono::system_clock::now(); + for (int k = 0; k < NLOOPS; ++k) + res2T = T.MultT(w); + t1T = chrono::system_clock::now(); + chrono::duration timeMultT2 = (t1T - t0T) / NLOOPS; + + cout << "\nTensorMatrix Mult time: " << timeMult2.count() << " sec\n"; + cout << "TensorMatrix MultT time: " << timeMultT2.count() << " sec\n"; + + double diffT = 0.0; + for (int i = 0; i < n; ++i) + diffT += fabs(res1T[i] - res2T[i]); + diffT /= n; + cout << "Average difference between Tensor Mult and MultT results: " << diffT << endl; + + return 0; +}