commit 10666ce5b678f173f00ad8b59daae7d0eebe2b07 Author: amoser Date: Sat Dec 6 20:57:35 2025 +0000 Initial Commit diff --git a/HPC-Klausurvorbereitung.pdf b/HPC-Klausurvorbereitung.pdf new file mode 100644 index 0000000..bfff996 Binary files /dev/null and b/HPC-Klausurvorbereitung.pdf differ diff --git a/a1_ln2_openmp.cpp b/a1_ln2_openmp.cpp new file mode 100644 index 0000000..3d61a90 --- /dev/null +++ b/a1_ln2_openmp.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "test.h" + +void runningWithOpenMPTest(); +void computeLn2Test(); + +// **************************************************** +// TODO: parallelize this function with OpenMP +// **************************************************** + +double ln2(int numTerms) +{ + double sum = 0; +#pragma omp parallel for reduction(+ : sum) + for (int i = 1; i < numTerms + 1; ++i) + { + int sign = 1; + if (i % 2 == 0) { + sign = -1; + } + sum += sign / static_cast(i); + } + return sum; +} + +int main(int argc, char *argv[]) +{ + runningWithOpenMPTest(); + computeLn2Test(); +} + +// Do not change anything below this line! +// **************************************************** + +// Verify that the program actually runs with OpenMP +void runningWithOpenMPTest() +{ +#pragma omp parallel + { + int numThreads = omp_get_num_threads(); + check(numThreads, 4); + } +} + +// Verify correct functionality of ln2() +void computeLn2Test() +{ + check(ln2(4), 0.5833333333333333); + check(ln2(8), 0.6345238095238095); + check(ln2(12), 0.6532106782106781); + check(ln2(100), 0.688172179310195); + check(ln2(1e6), 0.6931466805602525); +} diff --git a/ln2 b/ln2 new file mode 100644 index 0000000..8b6e693 Binary files /dev/null and b/ln2 differ diff --git a/makefile b/makefile new file mode 100644 index 0000000..81494ea --- /dev/null +++ b/makefile @@ -0,0 +1,5 @@ +all: a1_ln2_openmp.cpp + g++ a1_ln2_openmp.cpp -fopenmp -o ln2 + +run: all + OMP_NUM_THREADS=4 ./ln2 \ No newline at end of file diff --git a/test.h b/test.h new file mode 100644 index 0000000..232be71 --- /dev/null +++ b/test.h @@ -0,0 +1,290 @@ +/** test.h, an extremly simple test framework. + * Version 1.4 + * Copyright (C) 2022-2023 Tobias Kreilos, Offenburg University of Applied + * Sciences + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * + * The framework defines a function check(a,b) that can be called with + * parameters of different types. The function asserts + * that the two paramters are equal (within a certain, predefined range for + * floating point numbers) and prints the result of the comparison on the + * command line. Additionally a summary of all tests is printed at the end of + * the program. + * Additionally there is TEST macro, which you can place outside main to group + * tests together. Code in the macro is automatically executed at the beginning + * of the program. + * The file also defines a class InstanceCount, that can be used to + * count how many instances of an object are still alive at the end of a + * program. To use it, derive your class from InstanceCount and the + * message is automatically printed at the end of the program. + */ + +#ifndef VERY_SIMPLE_TEST_H + #define VERY_SIMPLE_TEST_H + + #include + #include + #include + #include + + /** Simple macro to execute the code that follows the macro (without call from + * main) + * + * Define a class, that is directly instantiated + * and contains the test code in the constructor. + * + * Usage: + * TEST(MyTest) + * { + * // test code + * } + */ + #define TEST(name) \ + struct _TestClass##name { \ + _TestClass##name(); \ + } _TestClass##name##Instance; \ + _TestClass##name::_TestClass##name() + +// Use a namespace to hide implementation details +namespace Test::Detail { +/** + * Make it possible to print the underlying value of class enums with ostream + * + * The expression typename std::enable_if::value, + * std::ostream>::type decays to ostream if the type T is an enum. Otherwise, + * the function is not generated. + */ +template +std::ostream& operator<<( + typename std::enable_if::value, std::ostream>::type& stream, + const T& e) { + return stream << static_cast::type>(e); +} + +/** + * Convert anything to a string. + */ +template +std::string toString(const T& t) { + std::ostringstream ss; + ss << t; + return "\"" + ss.str() + "\""; +} + +/** + * Convert bools to string "true" or "false" instead of 0 and 1 + */ +template <> +inline std::string toString(const bool& b) { + return b ? "\"true\"" : "\"false\""; +} + +/** + * Comparison function for different types + */ +template +bool isEqual(const T& t1, const T& t2) { + return t1 == t2; +} + +/** + * Double values are equal if they differ no more than 1e-12 + */ +template <> +inline bool isEqual(const double& expectedValue, + const double& actualValue) { + const double epsilon = 1e-12; + const double distance = fabs(actualValue - expectedValue); + return (distance < epsilon); +} + +/** + * Float values are equal if they differ no more than 1e-6 + */ +template <> +inline bool isEqual(const float& expectedValue, + const float& actualValue) { + const double epsilon = 1e-6; + const double distance = fabs(actualValue - expectedValue); + return (distance < epsilon); +} + +/** + * This class realizes some basics of the test framework. + * Test summary is printed in the destructor. + * Apart from that, the class implements counting of total and failed tests, + * comparison of floating point numbers within sensible boundaries and prints + * the result of each test on the command line. + */ +class Test { + public: + /** + * Test class is a Singleton + */ + static Test& instance() { + static Test test; + return test; + } + + /** + * the main entry point for tests. Test two values for equality and output the + * result. + */ + template + bool check(const T& expectedValue, const T& actualValue) { + bool testResult = isEqual(expectedValue, actualValue); + if (testResult == true) { + registerPassingTest(); + #pragma omp critical + std::cout << "Test successful! Expected value == actual value (=" + << toString(expectedValue) << ")" << std::endl; + } else { + registerFailingTest(); + #pragma omp critical + std::cout << "Error in test: expected value " << toString(expectedValue) + << ", but actual value was " << toString(actualValue) + << std::endl; + } + + return testResult; + } + + private: + /** + * On destruction, print a summary of all tests. + */ + ~Test() { + std::cout << "\n--------------------------------------" << std::endl; + std::cout << "Test summary:" << std::endl; + std::cout << "Executed tests: " << numTests_ << std::endl; + std::cout << "Failed tests: " << numFailedTests_ << std::endl; + } + + void registerPassingTest() { numTests_++; } + + void registerFailingTest() { + numTests_++; + numFailedTests_++; + } + + /** + * For statistics + */ + std::atomic numTests_ = 0; + + /** + * For statistics + */ + std::atomic numFailedTests_ = 0; +}; + +template +class InstanceCounterHelper { + public: + ~InstanceCounterHelper() { + std::cout << "The remaining number of objects of type " << typeid(T).name() + << " at the end of the program is " << count; + if (count > 0) + std::cout << " (NOT zero!)"; + std::cout << "\nThe total number of objects created was " << total + << std::endl; + } + + void increment() { + count++; + total++; + } + + void decrement() { count--; } + + private: + std::atomic count = 0; + std::atomic total = 0; +}; + +} // namespace Test::Detail + +/** + * Count the instances of a class T. + * Result gets printed automatically at the end of the program. + * To use it, inherit T from InstanceCounter, e.g. + * class MyClass : InstanceCounter + */ +template +class InstanceCounter { + public: + InstanceCounter() { counter().increment(); } + + InstanceCounter(const InstanceCounter&) { counter().increment(); } + + InstanceCounter(const InstanceCounter&&) { counter().increment(); } + + virtual ~InstanceCounter() { counter().decrement(); } + + Test::Detail::InstanceCounterHelper& counter() { + static Test::Detail::InstanceCounterHelper c; + return c; + } +}; + +/** + * Check if the expected value is equal to the actual value. + * Result is printed on the command line and at the end of the program, a + * summary of all tests is printed. + */ +template +void check(const T1& actualValue, const T2& expectedValue) { + const T1& expectedValueCasted{ + expectedValue}; // allows conversion in general, but avoids narrowing + // conversion + Test::Detail::Test::instance().check(expectedValueCasted, actualValue); +} + +// allow conversion from int to double explicitely +template <> +inline void check(const int& actualValue, const double& expectedValue) { + Test::Detail::Test::instance().check(expectedValue, + static_cast(actualValue)); +} + +// allow conversion from int to double explicitely +template <> +inline void check(const double& actualValue, const int& expectedValue) { + Test::Detail::Test::instance().check(static_cast(expectedValue), + actualValue); +} + +/** + * Check if the entered value is true. + * Result is printed on the command line and at the end of the program, a + * summary of all tests is printed. + */ +inline void check(bool a) { + Test::Detail::Test::instance().check(true, a); +} + +#endif // VERY_SIMPLE_TEST_H + +/** + * V1.0: Creation of franework + * V1.1: make check(bool) inline, automatically convert expected value type to + * actual value type + * V1.2: added possibilty to count constructions and destructions of some type + * V1.3: tweaks on check for int and double types + * V1.4: Adding thread safety in OpenMP programs (not general thread safety, as + * OpenMP and std::thread might not play along) + */ \ No newline at end of file