diff --git a/math/area.cpp b/math/area.cpp index 691fe91f0fc..230b9398af8 100644 --- a/math/area.cpp +++ b/math/area.cpp @@ -1,33 +1,51 @@ /** * @file - * @brief Implementations for the [area](https://en.wikipedia.org/wiki/Area) of - * various shapes - * @details The area of a shape is the amount of 2D space it takes up. + * @brief Basic function implementations for working out the + * [area](https://en.wikipedia.org/wiki/Area) of various shapes. + * + * @details + * The area of a shape is the amount of 2D space it takes up. * All shapes have a formula to get the area of any given shape. * These implementations support multiple return types. * * @author [Focusucof](https://github.com/Focusucof) */ -#define _USE_MATH_DEFINES -#include /// for assert -#include /// for M_PI definition and pow() -#include + +#define _USE_MATH_DEFINES /// This definition is required to use M_PI. + +#include /// for assert +#include /// for M_PI definition and pow() #include /// for uint16_t datatype #include /// for IO operations /** - * @namespace math * @brief Mathematical algorithms + * @namespace math */ namespace math { + /** * @brief area of a [square](https://en.wikipedia.org/wiki/Square) (l * l) * @param length is the length of the square - * @returns area of square + * @returns area of square. */ -template -T square_area(T length) { - return length * length; +uint64_t square_area(uint32_t length) { + /* + The parameter type of this function replaces the template type T because + it is safer. If we use the same parameter type as the return type then + there is a potential for the calculated value to roll over and give an + incorrect calculation. + + e.g. (UINT8_T_MAX * UINT8_T_MAX) == 65025 + To store this calculation we would need to specify a return type of + uint16_t + + This is important to know for the following functions because it dictates + what data type we decide upon when setting up the function parameters and + the value returned by the function. + */ + uint64_t area_of_square = (uint64_t)length * (uint64_t)length; + return area_of_square; } /** @@ -36,32 +54,40 @@ T square_area(T length) { * @param width is the width of the rectangle * @returns area of the rectangle */ -template -T rect_area(T length, T width) { - return length * width; +uint64_t rect_area(uint32_t length, uint32_t width) { + /* + You may notice that these variables are prepended with (uint64_t) + This is because when doing the multiplication we need to give these data + types a wider area of memory when doing this calculation so we need a 64 + bit variable. + + We could make the parameters 64 bit but that would require adding checks + to make sure out calculation doesn't exceed 64 bits. So this is easier. + */ + uint64_t area_of_rectangle = (uint64_t)length * (uint64_t)width; + return area_of_rectangle; } /** - * @brief area of a [triangle](https://en.wikipedia.org/wiki/Triangle) (b * h / - * 2) + * @brief area of a [triangle](https://en.wikipedia.org/wiki/Triangle) (b * h)/2 * @param base is the length of the bottom side of the triangle * @param height is the length of the tallest point in the triangle * @returns area of the triangle */ -template -T triangle_area(T base, T height) { - return base * height / 2; +double triangle_area(uint32_t base, uint32_t height) { + double area_of_triangle = (base * height) / 2; + return area_of_triangle; } /** - * @brief area of a [circle](https://en.wikipedia.org/wiki/Area_of_a_circle) (pi - * * r^2) + * @brief area of a [circle](https://en.wikipedia.org/wiki/Area_of_a_circle) + * (pi * r^2) * @param radius is the radius of the circle * @returns area of the circle */ -template -T circle_area(T radius) { - return M_PI * pow(radius, 2); +double circle_area(uint32_t radius) { + double area_of_circle = M_PI * pow(radius, 2); + return area_of_circle; } /** @@ -71,20 +97,20 @@ T circle_area(T radius) { * @param height is the length of the tallest point in the parallelogram * @returns area of the parallelogram */ -template -T parallelogram_area(T base, T height) { - return base * height; +uint64_t parallelogram_area(uint32_t base, uint32_t height) { + uint64_t area_of_parallelogram = (uint64_t)base * (uint64_t)height; + return area_of_parallelogram; } /** - * @brief surface area of a [cube](https://en.wikipedia.org/wiki/Cube) ( 6 * (l - * * l)) + * @brief surface area of a [cube](https://en.wikipedia.org/wiki/Cube) + * ( 6 * (l * l)) * @param length is the length of the cube * @returns surface area of the cube */ -template -T cube_surface_area(T length) { - return 6 * length * length; +uint64_t cube_surface_area(uint16_t length) { + uint64_t surface_area_of_cube = 6u * (uint64_t)length * (uint64_t)length; + return surface_area_of_cube; } /** @@ -93,9 +119,9 @@ T cube_surface_area(T length) { * @param radius is the radius of the sphere * @returns surface area of the sphere */ -template -T sphere_surface_area(T radius) { - return 4 * M_PI * pow(radius, 2); +double sphere_surface_area(uint16_t radius) { + double surface_area_of_sphere = 4 * M_PI * pow(radius, 2); + return surface_area_of_sphere; } /** @@ -105,168 +131,184 @@ T sphere_surface_area(T radius) { * @param height is the height of the cylinder * @returns surface area of the cylinder */ -template -T cylinder_surface_area(T radius, T height) { - return 2 * M_PI * radius * height + 2 * M_PI * pow(radius, 2); +double cylinder_surface_area(uint16_t radius, uint16_t height) { + double surface_area_of_cylinder = + 2 * M_PI * radius * height + 2 * M_PI * pow(radius, 2); + return surface_area_of_cylinder; } + } // namespace math /** - * @brief Self-test implementations + * @brief This self test is used to test the basic functionality of the + * square_area function to see if it behaves as expected. + * @returns void + */ +static void test_square_area_functionality() { + // Given we the lengths of different squares. + uint32_t square_a_side_length = 20u; + uint32_t square_b_side_length = 1024u; + uint32_t square_c_side_length = 35233030u; + uint32_t square_d_side_length = 0u; + + // When we calculate the area of the different squares + uint64_t actual_area_square_a = math::square_area(square_a_side_length); + uint64_t actual_area_square_b = math::square_area(square_b_side_length); + uint64_t actual_area_square_c = math::square_area(square_c_side_length); + uint64_t actual_area_square_d = math::square_area(square_d_side_length); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(400u == actual_area_square_a); + assert(1048576u == actual_area_square_b); + assert(1241366402980900u == actual_area_square_c); + assert(0u == actual_area_square_d); + + std::cout << "TEST PASSED: Square Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * rect_area function to see if it behaves as expected. + * @returns void + */ +static void test_rect_area_functionality() { + // Given we have a rectangle length and width. + uint32_t rectangle_side_length = 1024u; + uint32_t rectangle_side_width = 35233030u; + + // When we calculate the area of the rectangle. + uint64_t actual_area_rectangle = + math::rect_area(rectangle_side_length, rectangle_side_width); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(36078622720u == actual_area_rectangle); + + std::cout << "TEST PASSED: Rectangle Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * triangle_area function to see if it behaves as expected. + * @returns void + */ +static void test_triangle_area_functionality() { + // Given we have a triangle base length and height. + uint32_t triangle_base_length = 2420u; + uint32_t triangle_height = 115642u; + + // When we calculate the area of the triangle. + double actual_triangle_area = + math::triangle_area(triangle_base_length, triangle_height); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(139926820u == actual_triangle_area); + + std::cout << "TEST PASSED: Triangle Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * circle_area function to see if it behaves as expected. * @returns void */ -static void test() { - // I/O variables for testing - uint16_t int_length = 0; // 16 bit integer length input - uint16_t int_width = 0; // 16 bit integer width input - uint16_t int_base = 0; // 16 bit integer base input - uint16_t int_height = 0; // 16 bit integer height input - uint16_t int_expected = 0; // 16 bit integer expected output - uint16_t int_area = 0; // 16 bit integer output - - float float_length = NAN; // float length input - float float_expected = NAN; // float expected output - float float_area = NAN; // float output - - double double_length = NAN; // double length input - double double_width = NAN; // double width input - double double_radius = NAN; // double radius input - double double_height = NAN; // double height input - double double_expected = NAN; // double expected output - double double_area = NAN; // double output - - // 1st test - int_length = 5; - int_expected = 25; - int_area = math::square_area(int_length); - - std::cout << "AREA OF A SQUARE (int)" << std::endl; - std::cout << "Input Length: " << int_length << std::endl; - std::cout << "Expected Output: " << int_expected << std::endl; - std::cout << "Output: " << int_area << std::endl; - assert(int_area == int_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 2nd test - float_length = 2.5; - float_expected = 6.25; - float_area = math::square_area(float_length); - - std::cout << "AREA OF A SQUARE (float)" << std::endl; - std::cout << "Input Length: " << float_length << std::endl; - std::cout << "Expected Output: " << float_expected << std::endl; - std::cout << "Output: " << float_area << std::endl; - assert(float_area == float_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 3rd test - int_length = 4; - int_width = 7; - int_expected = 28; - int_area = math::rect_area(int_length, int_width); - - std::cout << "AREA OF A RECTANGLE (int)" << std::endl; - std::cout << "Input Length: " << int_length << std::endl; - std::cout << "Input Width: " << int_width << std::endl; - std::cout << "Expected Output: " << int_expected << std::endl; - std::cout << "Output: " << int_area << std::endl; - assert(int_area == int_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 4th test - double_length = 2.5; - double_width = 5.7; - double_expected = 14.25; - double_area = math::rect_area(double_length, double_width); - - std::cout << "AREA OF A RECTANGLE (double)" << std::endl; - std::cout << "Input Length: " << double_length << std::endl; - std::cout << "Input Width: " << double_width << std::endl; - std::cout << "Expected Output: " << double_expected << std::endl; - std::cout << "Output: " << double_area << std::endl; - assert(double_area == double_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 5th test - int_base = 10; - int_height = 3; - int_expected = 15; - int_area = math::triangle_area(int_base, int_height); - - std::cout << "AREA OF A TRIANGLE" << std::endl; - std::cout << "Input Base: " << int_base << std::endl; - std::cout << "Input Height: " << int_height << std::endl; - std::cout << "Expected Output: " << int_expected << std::endl; - std::cout << "Output: " << int_area << std::endl; - assert(int_area == int_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 6th test - double_radius = 6; - double_expected = - 113.09733552923255; // rounded down because the double datatype - // truncates after 14 decimal places - double_area = math::circle_area(double_radius); - - std::cout << "AREA OF A CIRCLE" << std::endl; - std::cout << "Input Radius: " << double_radius << std::endl; - std::cout << "Expected Output: " << double_expected << std::endl; - std::cout << "Output: " << double_area << std::endl; - assert(double_area == double_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 7th test - int_base = 6; - int_height = 7; - int_expected = 42; - int_area = math::parallelogram_area(int_base, int_height); - - std::cout << "AREA OF A PARALLELOGRAM" << std::endl; - std::cout << "Input Base: " << int_base << std::endl; - std::cout << "Input Height: " << int_height << std::endl; - std::cout << "Expected Output: " << int_expected << std::endl; - std::cout << "Output: " << int_area << std::endl; - assert(int_area == int_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 8th test - double_length = 5.5; - double_expected = 181.5; - double_area = math::cube_surface_area(double_length); - - std::cout << "SURFACE AREA OF A CUBE" << std::endl; - std::cout << "Input Length: " << double_length << std::endl; - std::cout << "Expected Output: " << double_expected << std::endl; - std::cout << "Output: " << double_area << std::endl; - assert(double_area == double_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 9th test - double_radius = 10.0; - double_expected = 1256.6370614359172; // rounded down because the whole - // value gets truncated - double_area = math::sphere_surface_area(double_radius); - - std::cout << "SURFACE AREA OF A SPHERE" << std::endl; - std::cout << "Input Radius: " << double_radius << std::endl; - std::cout << "Expected Output: " << double_expected << std::endl; - std::cout << "Output: " << double_area << std::endl; - assert(double_area == double_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; - - // 10th test - double_radius = 4.0; - double_height = 7.0; - double_expected = 276.46015351590177; - double_area = math::cylinder_surface_area(double_radius, double_height); - - std::cout << "SURFACE AREA OF A CYLINDER" << std::endl; - std::cout << "Input Radius: " << double_radius << std::endl; - std::cout << "Input Height: " << double_height << std::endl; - std::cout << "Expected Output: " << double_expected << std::endl; - std::cout << "Output: " << double_area << std::endl; - assert(double_area == double_expected); - std::cout << "TEST PASSED" << std::endl << std::endl; +static void test_circle_area_functionality() { + // Given we have a circle radius. + uint32_t circle_radius = 555u; + + // When we calculate the area of the circle. + double actual_circle_area = math::circle_area(circle_radius); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(967689.07712199597 == actual_circle_area); + + std::cout << "TEST PASSED: Circle Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * parallelogram_area function to see if it behaves as expected. + * @returns void + */ +static void test_parallelogram_area_functionality() { + // Given we the base and height of a parallelogram. + uint32_t parallelogram_base = 20u; + uint32_t parallelogram_height = 1024u; + + // When we calculate the area of the parallelogram + uint64_t actual_area_parallelogram = + math::parallelogram_area(parallelogram_base, parallelogram_height); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(20480u == actual_area_parallelogram); + + std::cout << "TEST PASSED: Parallelogram Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * cube_surface_area function to see if it behaves as expected. + * @returns void + */ +static void test_cube_surface_area_functionality() { + // Given we the length of one face of the cube. + uint16_t cube_face_length = 4121u; + + // When we calculate the cube surface area. + uint64_t actual_cube_surface_area = + math::cube_surface_area(cube_face_length); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(101895846u == actual_cube_surface_area); + + std::cout << "TEST PASSED: Cube Surface Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * sphere_surface_area function to see if it behaves as expected. + * @returns void + */ +static void test_sphere_surface_area_functionality() { + // Given we the radius of the sphere. + uint16_t sphere_radius = 5678u; + + // When we calculate the sphere surface area. + uint64_t actual_sphere_surface_area = + math::sphere_surface_area(sphere_radius); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(405135817 == actual_sphere_surface_area); + + std::cout << "TEST PASSED: Sphere Surface Area" << std::endl << std::endl; +} + +/** + * @brief This self test is used to test the basic functionality of the + * cylinder_surface_area function to see if it behaves as expected. + * @returns void + */ +static void test_cylinder_surface_area_functionality() { + // Given we the radius and the height of the cylinder. + uint16_t cylinder_radius = 42u; + uint16_t cylinder_height = 413u; + + // When we calculate the cylinder surface area. + uint64_t actual_cylinder_surface_area = + math::cylinder_surface_area(cylinder_radius, cylinder_height); + + // Then we should get the area calculated as we expect. + // is the expected == actual? + assert(120071 == actual_cylinder_surface_area); + + std::cout << "TEST PASSED: Sphere Surface Area" << std::endl + << std::endl; // sphere_surface_area } /** @@ -274,6 +316,13 @@ static void test() { * @returns 0 on exit */ int main() { - test(); // run self-test implementations + test_square_area_functionality(); // run self-test implementations + test_rect_area_functionality(); + test_triangle_area_functionality(); + test_circle_area_functionality(); + test_parallelogram_area_functionality(); + test_cube_surface_area_functionality(); + test_sphere_surface_area_functionality(); + test_cylinder_surface_area_functionality(); return 0; }