From 598fdc383cc7373cff73daa190c110d536446e52 Mon Sep 17 00:00:00 2001 From: saundersp Date: Mon, 24 Jul 2023 02:20:26 +0200 Subject: [PATCH] cpp : Moved unit test to seperate files --- cpp/ViolaJonesGPU.cu | 130 --------------------------- cpp/ViolaJonesGPU.hpp | 3 - cpp/gpu_unit_test.hpp | 5 ++ cpp/gpu_unittest.cu | 128 ++++++++++++++++++++++++++ cpp/projet.cpp | 18 ++-- cpp/toolbox.hpp | 3 +- cpp/toolbox_unit_test.cpp | 185 ++++++++++++++++++++++++++++++++++++++ cpp/toolbox_unit_test.hpp | 6 ++ 8 files changed, 336 insertions(+), 142 deletions(-) create mode 100644 cpp/gpu_unit_test.hpp create mode 100644 cpp/gpu_unittest.cu create mode 100644 cpp/toolbox_unit_test.cpp create mode 100644 cpp/toolbox_unit_test.hpp diff --git a/cpp/ViolaJonesGPU.cu b/cpp/ViolaJonesGPU.cu index d145aa8..0caa5ba 100644 --- a/cpp/ViolaJonesGPU.cu +++ b/cpp/ViolaJonesGPU.cu @@ -1,134 +1,4 @@ -#include #include "data.hpp" -#include "toolbox.hpp" -#include "ViolaJones.hpp" -#include "config.hpp" - -static __global__ void __test_working_kernel__(const np::Array d_x, np::Array d_y, const size_t length) { - const size_t i = blockIdx.x * blockDim.x + threadIdx.x; - if (i < length) - d_y[i] = d_x[i] * i; -} - -void test_working(const size_t& length) noexcept { - const size_t size = length * sizeof(size_t); - -#if __DEBUG - print("Estimating memory footprint at : " + format_byte_size(2 * size)); -#endif - - np::Array x = np::empty({ length }), y = np::empty({ length }); - size_t i; - for (i = 0; i < length; ++i) - x[i] = i; - - np::Array d_x = copyToDevice("x", x), d_y = copyToDevice("y", y); - - const size_t dimX = static_cast(std::ceil(static_cast(length) / static_cast(NB_THREADS))); - const dim3 dimGrid(dimX); - constexpr const dim3 dimBlock(NB_THREADS); - __test_working_kernel__<<>>(d_x, d_y, length); - _print_cuda_error_("synchronize", cudaDeviceSynchronize()); - _print_cuda_error_("memcpy d_y", cudaMemcpy(y.data, d_y.data, size, cudaMemcpyDeviceToHost)); - - size_t ne = 0; - for (i = 0; i < length; ++i) - if (y[i] != x[i] * i) - ++ne; - - if (ne != 0) - fprintf(stderr, "Invalid result : %lu/%lu <=> %f%%\n", ne, length, static_cast(ne) / static_cast(length)); - - cudaFree("d_x", d_x); - cudaFree("d_y", d_y); -} - -static __global__ void __test_working_kernel_2d__(const np::Array d_x, np::Array d_y, const size_t length) { - const size_t idx = threadIdx.x * blockDim.y + threadIdx.y; - const size_t idy = blockIdx.x * gridDim.y + blockIdx.y; - const size_t i = idy * NB_THREADS_2D_X * NB_THREADS_2D_Y + idx; - if (i < length) - d_y[i] = d_x[i] * i; -} - -void test_working_2d(const size_t& N1, const size_t& N2) noexcept { - const size_t length = N1 * N2; - const size_t size = length * sizeof(size_t); - -#if __DEBUG - print("Estimating memory footprint at : " + format_byte_size(2 * size)); -#endif - - np::Array x = np::empty({ length }), y = np::empty({ length }); - size_t i; - for (i = 0; i < length; ++i) - x[i] = i; - - np::Array d_x = copyToDevice("x", x), d_y = copyToDevice("y", y); - - const size_t dimX = static_cast(std::ceil(static_cast(N1) / static_cast(NB_THREADS_2D_X))); - const size_t dimY = static_cast(std::ceil(static_cast(N2) / static_cast(NB_THREADS_2D_Y))); - const dim3 dimGrid(dimX, dimY); - constexpr const dim3 dimBlock(NB_THREADS_2D_X, NB_THREADS_2D_Y); - __test_working_kernel_2d__<<>>(d_x, d_y, length); - _print_cuda_error_("synchronize", cudaDeviceSynchronize()); - _print_cuda_error_("memcpy d_y", cudaMemcpy(y.data, d_y.data, size, cudaMemcpyDeviceToHost)); - - size_t ne = 0; - for (i = 0; i < length; ++i) - if (y[i] != x[i] * i) - ++ne; - - if (ne != 0) - fprintf(stderr, "Invalid result : %lu/%lu <=> %f%%\n", ne, length, static_cast(ne) / static_cast(length)); - - cudaFree("d_x", d_x); - cudaFree("d_y", d_y); -} - -static __global__ void __test_working_kernel_3d__(const np::Array d_x, np::Array d_y, const size_t length) { - const size_t idx = (threadIdx.x * blockDim.y + threadIdx.y) * blockDim.z + threadIdx.z; - const size_t idy = (blockIdx.x * gridDim.y + blockIdx.y) * gridDim.z + blockIdx.z; - const size_t i = idy * NB_THREADS_3D_X * NB_THREADS_3D_Y * NB_THREADS_3D_Z + idx; - if (i < length) - d_y[i] = d_x[i] * i; -} - -void test_working_3d(const size_t& N1, const size_t& N2, const size_t& N3) noexcept { - const size_t length = N1 * N2 * N3; - const size_t size = length * sizeof(size_t); - -#if __DEBUG - print("Estimating memory footprint at : " + format_byte_size(2 * size)); -#endif - - np::Array x = np::empty({ length }), y = np::empty({ length }); - size_t i; - for (i = 0; i < length; ++i) - x[i] = i; - - np::Array d_x = copyToDevice("x", x), d_y = copyToDevice("y", y); - - const size_t dimX = static_cast(std::ceil(static_cast(N1) / static_cast(NB_THREADS_3D_X))); - const size_t dimY = static_cast(std::ceil(static_cast(N2) / static_cast(NB_THREADS_3D_Y))); - const size_t dimZ = static_cast(std::ceil(static_cast(N3) / static_cast(NB_THREADS_3D_Z))); - const dim3 dimGrid(dimX, dimY, dimZ); - constexpr const dim3 dimBlock(NB_THREADS_3D_X, NB_THREADS_3D_Y, NB_THREADS_3D_Z); - __test_working_kernel_3d__<<>>(d_x, d_y, length); - _print_cuda_error_("synchronize", cudaDeviceSynchronize()); - _print_cuda_error_("memcpy d_y", cudaMemcpy(y.data, d_y.data, size, cudaMemcpyDeviceToHost)); - - size_t ne = 0; - for (i = 0; i < length; ++i) - if (y[i] != x[i] * i) - ++ne; - - if (ne != 0) - fprintf(stderr, "Invalid result : %lu/%lu <=> %f%%\n", ne, length, static_cast(ne) / static_cast(length)); - - cudaFree("d_x", d_x); - cudaFree("d_y", d_y); -} static np::Array __scanCPU_3d__(const np::Array& X) noexcept { np::Array X_scan = np::empty(X.shape); diff --git a/cpp/ViolaJonesGPU.hpp b/cpp/ViolaJonesGPU.hpp index 3d305a6..0b16fbe 100644 --- a/cpp/ViolaJonesGPU.hpp +++ b/cpp/ViolaJonesGPU.hpp @@ -1,9 +1,6 @@ #pragma once #include "data.hpp" -void test_working(const size_t&) noexcept; -void test_working_2d(const size_t&, const size_t&) noexcept; -void test_working_3d(const size_t&, const size_t&, const size_t&) noexcept; np::Array set_integral_image_gpu(const np::Array&) noexcept; np::Array apply_features_gpu(const np::Array&, const np::Array&) noexcept; np::Array train_weak_clf_gpu(const np::Array& X_feat, const np::Array& X_feat_argsort, const np::Array& y, diff --git a/cpp/gpu_unit_test.hpp b/cpp/gpu_unit_test.hpp new file mode 100644 index 0000000..f8d8da0 --- /dev/null +++ b/cpp/gpu_unit_test.hpp @@ -0,0 +1,5 @@ +#pragma once + +void test_working(const size_t&) noexcept; +void test_working_2d(const size_t&, const size_t&) noexcept; +void test_working_3d(const size_t&, const size_t&, const size_t&) noexcept; diff --git a/cpp/gpu_unittest.cu b/cpp/gpu_unittest.cu new file mode 100644 index 0000000..e16176e --- /dev/null +++ b/cpp/gpu_unittest.cu @@ -0,0 +1,128 @@ +#include "data.hpp" +#include "toolbox.hpp" + +static __global__ void __test_working_kernel__(const np::Array d_x, np::Array d_y, const size_t length) { + const size_t i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < length) + d_y[i] = d_x[i] * i; +} + +void test_working(const size_t& length) noexcept { + const size_t size = length * sizeof(size_t); + +#if __DEBUG + print("Estimating memory footprint at : " + format_byte_size(2 * size)); +#endif + + np::Array x = np::empty({ length }), y = np::empty({ length }); + size_t i; + for (i = 0; i < length; ++i) + x[i] = i; + + np::Array d_x = copyToDevice("x", x), d_y = copyToDevice("y", y); + + const size_t dimX = static_cast(std::ceil(static_cast(length) / static_cast(NB_THREADS))); + const dim3 dimGrid(dimX); + constexpr const dim3 dimBlock(NB_THREADS); + __test_working_kernel__<<>>(d_x, d_y, length); + _print_cuda_error_("synchronize", cudaDeviceSynchronize()); + _print_cuda_error_("memcpy d_y", cudaMemcpy(y.data, d_y.data, size, cudaMemcpyDeviceToHost)); + + size_t ne = 0; + for (i = 0; i < length; ++i) + if (y[i] != x[i] * i) + ++ne; + + if (ne != 0) + fprintf(stderr, "Invalid result : %lu/%lu <=> %f%%\n", ne, length, static_cast(ne) / static_cast(length)); + + cudaFree("d_x", d_x); + cudaFree("d_y", d_y); +} + +static __global__ void __test_working_kernel_2d__(const np::Array d_x, np::Array d_y, const size_t length) { + const size_t idx = threadIdx.x * blockDim.y + threadIdx.y; + const size_t idy = blockIdx.x * gridDim.y + blockIdx.y; + const size_t i = idy * NB_THREADS_2D_X * NB_THREADS_2D_Y + idx; + if (i < length) + d_y[i] = d_x[i] * i; +} + +void test_working_2d(const size_t& N1, const size_t& N2) noexcept { + const size_t length = N1 * N2; + const size_t size = length * sizeof(size_t); + +#if __DEBUG + print("Estimating memory footprint at : " + format_byte_size(2 * size)); +#endif + + np::Array x = np::empty({ length }), y = np::empty({ length }); + size_t i; + for (i = 0; i < length; ++i) + x[i] = i; + + np::Array d_x = copyToDevice("x", x), d_y = copyToDevice("y", y); + + const size_t dimX = static_cast(std::ceil(static_cast(N1) / static_cast(NB_THREADS_2D_X))); + const size_t dimY = static_cast(std::ceil(static_cast(N2) / static_cast(NB_THREADS_2D_Y))); + const dim3 dimGrid(dimX, dimY); + constexpr const dim3 dimBlock(NB_THREADS_2D_X, NB_THREADS_2D_Y); + __test_working_kernel_2d__<<>>(d_x, d_y, length); + _print_cuda_error_("synchronize", cudaDeviceSynchronize()); + _print_cuda_error_("memcpy d_y", cudaMemcpy(y.data, d_y.data, size, cudaMemcpyDeviceToHost)); + + size_t ne = 0; + for (i = 0; i < length; ++i) + if (y[i] != x[i] * i) + ++ne; + + if (ne != 0) + fprintf(stderr, "Invalid result : %lu/%lu <=> %f%%\n", ne, length, static_cast(ne) / static_cast(length)); + + cudaFree("d_x", d_x); + cudaFree("d_y", d_y); +} + +static __global__ void __test_working_kernel_3d__(const np::Array d_x, np::Array d_y, const size_t length) { + const size_t idx = (threadIdx.x * blockDim.y + threadIdx.y) * blockDim.z + threadIdx.z; + const size_t idy = (blockIdx.x * gridDim.y + blockIdx.y) * gridDim.z + blockIdx.z; + const size_t i = idy * NB_THREADS_3D_X * NB_THREADS_3D_Y * NB_THREADS_3D_Z + idx; + if (i < length) + d_y[i] = d_x[i] * i; +} + +void test_working_3d(const size_t& N1, const size_t& N2, const size_t& N3) noexcept { + const size_t length = N1 * N2 * N3; + const size_t size = length * sizeof(size_t); + +#if __DEBUG + print("Estimating memory footprint at : " + format_byte_size(2 * size)); +#endif + + np::Array x = np::empty({ length }), y = np::empty({ length }); + size_t i; + for (i = 0; i < length; ++i) + x[i] = i; + + np::Array d_x = copyToDevice("x", x), d_y = copyToDevice("y", y); + + const size_t dimX = static_cast(std::ceil(static_cast(N1) / static_cast(NB_THREADS_3D_X))); + const size_t dimY = static_cast(std::ceil(static_cast(N2) / static_cast(NB_THREADS_3D_Y))); + const size_t dimZ = static_cast(std::ceil(static_cast(N3) / static_cast(NB_THREADS_3D_Z))); + const dim3 dimGrid(dimX, dimY, dimZ); + constexpr const dim3 dimBlock(NB_THREADS_3D_X, NB_THREADS_3D_Y, NB_THREADS_3D_Z); + __test_working_kernel_3d__<<>>(d_x, d_y, length); + _print_cuda_error_("synchronize", cudaDeviceSynchronize()); + _print_cuda_error_("memcpy d_y", cudaMemcpy(y.data, d_y.data, size, cudaMemcpyDeviceToHost)); + + size_t ne = 0; + for (i = 0; i < length; ++i) + if (y[i] != x[i] * i) + ++ne; + + if (ne != 0) + fprintf(stderr, "Invalid result : %lu/%lu <=> %f%%\n", ne, length, static_cast(ne) / static_cast(length)); + + cudaFree("d_x", d_x); + cudaFree("d_y", d_y); +} diff --git a/cpp/projet.cpp b/cpp/projet.cpp index f122d1d..50169f4 100644 --- a/cpp/projet.cpp +++ b/cpp/projet.cpp @@ -3,12 +3,12 @@ namespace fs = std::filesystem; #include "data.hpp" #include "toolbox.hpp" #include "config.hpp" +#include "gpu_unit_test.hpp" +#include "toolbox_unit_test.hpp" #include "ViolaJones.hpp" #include "ViolaJonesGPU.hpp" #include "ViolaJonesCPU.hpp" -void test_float() noexcept; - #if GPU_BOOSTED #define LABEL "GPU" #define apply_features apply_features_gpu @@ -290,17 +290,21 @@ void final_unit_test() { } int main(){ -#if __DEBUG + setlocale(LC_NUMERIC, ""); // Allow proper number display + printf("| %-49s | %-18s | %-29s |\n", "Unit testing", "Time spent (ns)", "Formatted time spent"); printf("|%s|%s|%s|\n", S(51), S(20), S(31)); +#if GPU_BOOSTED benchmark_function_void("Testing GPU capabilities 1D", test_working, 3 + (1<<29)); benchmark_function_void("Testing GPU capabilities 2D", test_working_2d, 3 + (1<<15), 2 + (1<<14)); benchmark_function_void("Testing GPU capabilities 3D", test_working_3d, 9 + (1<<10), 5 + (1<<10), 7 + (1<<9)); - benchmark_function_void("Testing toolbox", toolbox_unit_test); - // benchmark_function_void("Testing floating capabilities", test_float); - printf("\n"); #endif - setlocale(LC_NUMERIC, ""); // Allow proper number display + benchmark_function_void("Testing format_time", format_time_test); + benchmark_function_void("Testing format_time_ns", format_time_ns_test); + benchmark_function_void("Testing format_byte_size", format_byte_size_test); + benchmark_function_void("Testing thousand_sep", thousand_sep_test); + printf("\n"); + const auto [ X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test ] = preprocessing(); train(X_train_feat, X_train_feat_argsort, y_train); testing_and_evaluating(X_train_feat, y_train, X_test_feat, y_test); diff --git a/cpp/toolbox.hpp b/cpp/toolbox.hpp index ef4e76a..7b12041 100644 --- a/cpp/toolbox.hpp +++ b/cpp/toolbox.hpp @@ -9,5 +9,4 @@ std::string format_time(uint64_t) noexcept; std::string format_time_ns(uint64_t) noexcept; std::string format_byte_size(uint64_t) noexcept; -void toolbox_unit_test() noexcept; -std::string thousand_sep(uint64_t) noexcept; +std::string thousand_sep(uint64_t, const char& = ',') noexcept; diff --git a/cpp/toolbox_unit_test.cpp b/cpp/toolbox_unit_test.cpp new file mode 100644 index 0000000..e9c6b48 --- /dev/null +++ b/cpp/toolbox_unit_test.cpp @@ -0,0 +1,185 @@ +#include "toolbox.hpp" +#include +#include + +template +void Assert(const char* name, const T& expected, const T& result) noexcept { + if(expected != result){ + std::cerr << "For test named " << name << " Expected '" << expected << "' but got '" << result << "' instead\n"; + assert(false); + } +} + +void format_byte_size_test(void) noexcept { + Assert("format_byte_size null", std::string("0B"), format_byte_size(static_cast(0))); + Assert("format_byte_size byte", std::string("1B"), format_byte_size(static_cast(1))); + Assert("format_byte_size kilobyte", std::string("1KB"), format_byte_size(static_cast(1)<<10)); + Assert("format_byte_size megabyte", std::string("1MB"), format_byte_size(static_cast(1)<<20)); + Assert("format_byte_size gigabyte", std::string("1GB"), format_byte_size(static_cast(1)<<30)); + Assert("format_byte_size terabyte", std::string("1TB"), format_byte_size(static_cast(1)<<40)); + Assert("format_byte_size petabyte", std::string("1PB"), format_byte_size(static_cast(1)<<50)); + Assert("format_byte_size exabyte", std::string("1EB"), format_byte_size(static_cast(1)<<60)); + // Unsupported due to number of byte bigger than currently supported by ISO c++ + //Assert("format_byte_size zettabyte", std::string("1ZB"), format_byte_size(static_cast(1)<<70)); + //Assert("format_byte_size yottabyte", std::string("1YB"), format_byte_size(static_cast(1)<<80)); + // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 + Assert("format_byte_size max", std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B"), format_byte_size(static_cast(-1))); +} + +void format_time_test(void) noexcept { + // https://en.wikipedia.org/wiki/Unit_of_time + Assert("format_time null", std::string("0s"), format_time(static_cast(0))); + Assert("format_time second", std::string("1s"), format_time(static_cast(1))); + Assert("format_time decasecond", std::string("10s"), format_time(static_cast(10))); + Assert("format_time minute", std::string("1m"), format_time(static_cast(60))); + Assert("format_time milliday", std::string("1m 26s"), format_time(static_cast(86))); // missing 0.4s due to precision + Assert("format_time hectosecond", std::string("1m 40s"), format_time(static_cast(100))); + Assert("format_time kilosecond", std::string("16m 40s"), format_time(static_cast(1e3))); + Assert("format_time hour", std::string("1h"), format_time(static_cast(3600))); + Assert("format_time day", std::string("1j"), format_time(static_cast(86400))); + Assert("format_time week/sennight", std::string("1w"), format_time(static_cast(604800))); + Assert("format_time megasecond", std::string("1w 4j 13h 46m 40s"), format_time(static_cast(1e6))); + Assert("format_time fortnight", std::string("2w"), format_time(static_cast(1209600))); + Assert("format_time lunar month (draconitic)", std::string("3w 6j 5h 5m 35s"), format_time(static_cast(2351135))); // missing 0.8 due to precision + Assert("format_time lunar month (tropical)", std::string("3w 6j 7h 43m 4s"), format_time(static_cast(2360584))); // missing 0.7 due to precision + Assert("format_time lunar month (sidereal)", std::string("3w 6j 7h 43m 11s"), format_time(static_cast(2360591))); // missing 0.6 to precision + Assert("format_time lunar month (anomalistic)", std::string("3w 6j 13h 18m 33s"), format_time(static_cast(2380713))); // missing 0.2 due to precision + Assert("format_time lunar month (synodic)", std::string("4w 1j 12h 44m 2s"), format_time(static_cast(2551442))); // missing 0.9 due to precision + Assert("format_time month", std::string("1M"), format_time(static_cast(2678400))); + Assert("format_time quarantine", std::string("1M 1w 2j"), format_time(static_cast(3456e3))); + Assert("format_time semester", std::string("4M 2j"), format_time(static_cast(10886400))); + Assert("format_time lunar year", std::string("11M 1w 6j 8h 52m 48s"), format_time(static_cast(30617568))); + Assert("format_time year", std::string("1y"), format_time(static_cast(31536e3))); + Assert("format_time tropical year", std::string("1y 5h 48m 45s"), format_time(static_cast(31556925))); // missing 0.216 due to precision + Assert("format_time gregorian year", std::string("1y 5h 49m 12s"), format_time(static_cast(31556952))); + Assert("format_time sidereal year", std::string("1y 6h 9m 9s"), format_time(static_cast(31558149))); // missing 0.7635456 due to precision + Assert("format_time leap year", std::string("1y 1j"), format_time(static_cast(31622400))); + Assert("format_time olympiad", std::string("4y"), format_time(static_cast(126144e3))); + Assert("format_time lusturm", std::string("5y"), format_time(static_cast(15768e4))); + Assert("format_time decade", std::string("10y"), format_time(static_cast(31536e4))); + Assert("format_time indiction", std::string("15y"), format_time(static_cast(47304e4))); + Assert("format_time score", std::string("20y"), format_time(static_cast(63072e4))); + Assert("format_time gigasecond", std::string("31y 8M 1w 4j 1h 46m 40s"), format_time(static_cast(1e9))); + Assert("format_time jubilee", std::string("50y"), format_time(static_cast(15768e5))); + Assert("format_time century", std::string("1c"), format_time(static_cast(31536e5))); + Assert("format_time millennium", std::string("10c"), format_time(static_cast(31536e6))); + Assert("format_time age", std::string("257c 72y"), format_time(static_cast(812745792e3))); + Assert("format_time terasecond", std::string("3170c 97y 10M 3w 4j 17h 46m 40s"), format_time(static_cast(1e13))); + Assert("format_time megaannum", std::string("10000c"), format_time(static_cast(31536e9))); + Assert("format_time petasecond", std::string("317097c 91y 11M 2w 4j 1h 46m 40s"), format_time(static_cast(1e15))); + Assert("format_time galactic year", std::string("2300000c"), format_time(static_cast(725328e10))); + Assert("format_time eon", std::string("10000000c"), format_time(static_cast(31536e12))); + Assert("format_time kalpa", std::string("43200000c"), format_time(static_cast(13623552e10))); + Assert("format_time exasecond", std::string("317097919c 83y 9M 1h 46m 40s"), format_time(static_cast(1e18))); + // Cannot use number bigger than currently supported ISO C++ + //Assert("format_time zettasecond", std::string(""), format_time(static_cast(1e21))); + //Assert("format_time yottasecond", std::string(""), format_time(static_cast(1e24))); + //Assert("format_time ronnasecond", std::string(""), format_time(static_cast(1e27))); + //Assert("format_time quettasecond", std::string(""), format_time(static_cast(1e30))); + // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 + Assert("format_time max", std::string("5849424173c 55y 3w 5j 7h 15s"), format_time(static_cast(-1))); +} + +void format_time_ns_test(void) noexcept { + // https://en.wikipedia.org/wiki/Unit_of_time + Assert("format_time_ns null", std::string("0ns"), format_time_ns(static_cast(0))); + Assert("format_time_ns nanosecond", std::string("1ns"), format_time_ns(static_cast(1))); + Assert("format_time_ns shake", std::string("10ns"), format_time_ns(static_cast(10))); + Assert("format_time_ns microsecond", std::string("1us"), format_time_ns(static_cast(1e3))); + Assert("format_time_ns millisecond", std::string("1ms"), format_time_ns(static_cast(1e6))); + Assert("format_time_ns centisecond", std::string("10ms"), format_time_ns(static_cast(1e7))); + Assert("format_time_ns decisecond", std::string("100ms"), format_time_ns(static_cast(1e8))); + Assert("format_time_ns second", std::string("1s"), format_time_ns(static_cast(1e9))); + Assert("format_time_ns decasecond", std::string("10s"), format_time_ns(static_cast(1e10))); + Assert("format_time_ns minute", std::string("1m"), format_time_ns(static_cast(6e10))); + Assert("format_time_ns milliday", std::string("1m 26s 400ms"), format_time_ns(static_cast(864e8))); + Assert("format_time_ns hectosecond", std::string("1m 40s"), format_time_ns(static_cast(1e11))); + Assert("format_time_ns kilosecond", std::string("16m 40s"), format_time_ns(static_cast(1e12))); + Assert("format_time_ns hour", std::string("1h"), format_time_ns(static_cast(36e11))); + Assert("format_time_ns day", std::string("1j"), format_time_ns(static_cast(864e11))); + Assert("format_time_ns week/sennight", std::string("1w"), format_time_ns(static_cast(6048e11))); + Assert("format_time_ns megasecond", std::string("1w 4j 13h 46m 40s"), format_time_ns(static_cast(1e15))); + Assert("format_time_ns fortnight", std::string("2w"), format_time_ns(static_cast(12096e11))); + Assert("format_time_ns lunar month (draconitic)", std::string("3w 6j 5h 5m 35s 800ms"), format_time_ns(static_cast(23511358e8))); + Assert("format_time_ns lunar month (tropical)", std::string("3w 6j 7h 43m 4s 700ms"), format_time_ns(static_cast(23605847e8))); + Assert("format_time_ns lunar month (sidereal)", std::string("3w 6j 7h 43m 11s 600ms"), format_time_ns(static_cast(23605916e8))); + Assert("format_time_ns lunar month (anomalistic)", std::string("3w 6j 13h 18m 33s 200ms"), format_time_ns(static_cast(23807132e8))); + Assert("format_time_ns lunar month (synodic)", std::string("4w 1j 12h 44m 2s 900ms"), format_time_ns(static_cast(25514429e8))); + Assert("format_time_ns month", std::string("1M"), format_time_ns(static_cast(26784e11))); + Assert("format_time_ns quarantine", std::string("1M 1w 2j"), format_time_ns(static_cast(3456e12))); + Assert("format_time_ns semester", std::string("4M 2j"), format_time_ns(static_cast(108864e11))); + Assert("format_time_ns lunar year", std::string("11M 1w 6j 8h 52m 48s"), format_time_ns(static_cast(30617568e9))); + Assert("format_time_ns year", std::string("1y"), format_time_ns(static_cast(31536e12))); + Assert("format_time_ns tropical year", std::string("1y 5h 48m 45s 216ms"), format_time_ns(static_cast(31556925216e6))); + Assert("format_time_ns gregorian year", std::string("1y 5h 49m 12s"), format_time_ns(static_cast(31556952e9))); + Assert("format_time_ns sidereal year", std::string("1y 6h 9m 9s 763ms 545us 600ns"), format_time_ns(static_cast(315581497635456e2))); + Assert("format_time_ns leap year", std::string("1y 1j"), format_time_ns(static_cast(316224e11))); + Assert("format_time_ns olympiad", std::string("4y"), format_time_ns(static_cast(126144e12))); + Assert("format_time_ns lusturm", std::string("5y"), format_time_ns(static_cast(15768e13))); + Assert("format_time_ns decade", std::string("10y"), format_time_ns(static_cast(31536e13))); + Assert("format_time_ns indiction", std::string("15y"), format_time_ns(static_cast(47304e13))); + Assert("format_time_ns score", std::string("20y"), format_time_ns(static_cast(63072e13))); + Assert("format_time_ns gigasecond", std::string("31y 8M 1w 4j 1h 46m 40s"), format_time_ns(static_cast(1e18))); + Assert("format_time_ns jubilee", std::string("50y"), format_time_ns(static_cast(15768e14))); + Assert("format_time_ns century", std::string("1c"), format_time_ns(static_cast(31536e14))); + // Cannot use number bigger than currently supported ISO C++ + //Assert("format_time_ns millennium", std::string("10c"), format_time_ns(static_cast(31536e15))); + //Assert("format_time_ns age", std::string("257c 72y"), format_time_ns(static_cast(812745792e12))); + //Assert("format_time_ns terasecond", std::string("3170c 97y 10M 3w 4j 17h 46m 40s"), format_time_ns(static_cast(1e22))); + //Assert("format_time_ns megaannum", std::string("10000c"), format_time_ns(static_cast(31536e18))); + //Assert("format_time_ns petasecond", std::string("317097c 91y 11M 2w 4j 1h 46m 40s"), format_time_ns(static_cast(1e24))); + //Assert("format_time_ns galactic year", std::string("2300000c"), format_time_ns(static_cast(725328e19))); + //Assert("format_time_ns eon", std::string("10000000c"), format_time_ns(static_cast(31536e21))); + //Assert("format_time_ns kalpa", std::string("43200000c"), format_time_ns(static_cast(13623552e19))); + //Assert("format_time_ns exasecond", std::string("317097919c 83y 9M 1h 46m 40s"), format_time_ns(static_cast(1e27))); + //Assert("format_time_ns zettasecond", std::string(""), format_time_ns(static_cast(1e30))); + //Assert("format_time_ns yottasecond", std::string(""), format_time_ns(static_cast(1e33))); + //Assert("format_time_ns ronnasecond", std::string(""), format_time_ns(static_cast(1e36))); + //Assert("format_time_ns quettasecond", std::string(""), format_time_ns(static_cast(1e39))); + // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 + Assert("format_time_ns max", std::string("5c 84y 11M 2j 23h 34m 33s 709ms 551us 615ns"), format_time_ns(static_cast(-1))); +} + +void thousand_sep_test(void) noexcept { + // https://en.wikipedia.org/wiki/Names_of_large_numbers + Assert("thousand_sep null", std::string("0"), thousand_sep(static_cast(0))); + Assert("thousand_sep unit", std::string("1"), thousand_sep(static_cast(1))); + Assert("thousand_sep ten", std::string("10"), thousand_sep(static_cast(10))); + Assert("thousand_sep hundred", std::string("100"), thousand_sep(static_cast(100))); + Assert("thousand_sep thousand", std::string("1,000"), thousand_sep(static_cast(1e3))); + Assert("thousand_sep ten thousand", std::string("10,000"), thousand_sep(static_cast(1e4))); + Assert("thousand_sep hundred thousand", std::string("100,000"), thousand_sep(static_cast(1e5))); + Assert("thousand_sep million", std::string("1,000,000"), thousand_sep(static_cast(1e6))); + Assert("thousand_sep ten million", std::string("10,000,000"), thousand_sep(static_cast(1e7))); + Assert("thousand_sep hundred million", std::string("100,000,000"), thousand_sep(static_cast(1e8))); + Assert("thousand_sep billion", std::string("1,000,000,000"), thousand_sep(static_cast(1e9))); + Assert("thousand_sep ten billion", std::string("10,000,000,000"), thousand_sep(static_cast(1e10))); + Assert("thousand_sep hundred billion", std::string("100,000,000,000"), thousand_sep(static_cast(1e11))); + Assert("thousand_sep trillion", std::string("1,000,000,000,000"), thousand_sep(static_cast(1e12))); + Assert("thousand_sep ten trillion", std::string("10,000,000,000,000"), thousand_sep(static_cast(1e13))); + Assert("thousand_sep hundred trillion", std::string("100,000,000,000,000"), thousand_sep(static_cast(1e14))); + Assert("thousand_sep quadrillion", std::string("1,000,000,000,000,000"), thousand_sep(static_cast(1e15))); + Assert("thousand_sep ten quadrillion", std::string("10,000,000,000,000,000"), thousand_sep(static_cast(1e16))); + Assert("thousand_sep hundred quadrillion", std::string("100,000,000,000,000,000"), thousand_sep(static_cast(1e17))); + Assert("thousand_sep quintillion", std::string("1,000,000,000,000,000,000"), thousand_sep(static_cast(1e18))); + Assert("thousand_sep ten quintillion", std::string("10,000,000,000,000,000,000"), thousand_sep(static_cast(1e19))); + // Cannot use number bigger than currently supported ISO C++ + //Assert("thousand_sep hundred quintillion", std::string("100,000,000,000,000,000,000"), thousand_sep(static_cast(1e20))); + //Assert("thousand_sep sextillion", std::string("1,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e21))); + //Assert("thousand_sep ten sextillion", std::string("10,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e22))); + //Assert("thousand_sep hundred sextillion", std::string("100,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e23))); + //Assert("thousand_sep septillion", std::string("1,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e24))); + //Assert("thousand_sep ten septillion", std::string("10,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e25))); + //Assert("thousand_sep hundred septillion", std::string("100,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e26))); + //Assert("thousand_sep octillion", std::string("1,000,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e27))); + //Assert("thousand_sep ten octillion", std::string("10,000,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e28))); + //Assert("thousand_sep hundred octillion", std::string("100,000,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e29))); + //Assert("thousand_sep nonillion", std::string("1,000,000,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e30))); + //Assert("thousand_sep ten nonillion", std::string("10,000,000,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e31))); + //Assert("thousand_sep hundred nonillion", std::string("100,000,000,000,000,000,000,000,000,000,000"), thousand_sep(static_cast(1e32))); + Assert("thousand_sep order", std::string("1,234,567,890"), thousand_sep(static_cast(1234567890))); + Assert("thousand_sep reverse order", std::string("9,876,543,210"), thousand_sep(static_cast(9876543210))); + // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 + Assert("thousand_sep max", std::string("18,446,744,073,709,551,615"), thousand_sep(static_cast(-1))); +} + diff --git a/cpp/toolbox_unit_test.hpp b/cpp/toolbox_unit_test.hpp new file mode 100644 index 0000000..121c165 --- /dev/null +++ b/cpp/toolbox_unit_test.hpp @@ -0,0 +1,6 @@ +#pragma once + +void format_byte_size_test(void) noexcept; +void format_time_test(void) noexcept; +void format_time_ns_test(void) noexcept; +void thousand_sep_test(void) noexcept;