diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 57af82144..a725098fa 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,3 +1,3 @@ { - "image": "stillwater/builders:clang14builder" + "image": "stillwater/builders:clang16builder" } diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index dc5f5d69d..b21926d94 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -2,7 +2,7 @@ name: CMake on: push: - branches: [ v3.77, dev, main ] + branches: [ v3.78, dev, main ] pull_request: branches: [ main ] diff --git a/CMakeLists.txt b/CMakeLists.txt index a15447ac3..41c8c9594 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ if(NOT DEFINED UNIVERSAL_VERSION_MAJOR) set(UNIVERSAL_VERSION_MAJOR 3) endif() if(NOT DEFINED UNIVERSAL_VERSION_MINOR) - set(UNIVERSAL_VERSION_MINOR 77) + set(UNIVERSAL_VERSION_MINOR 78) endif() if(NOT DEFINED UNIVERSAL_VERSION_PATCH) set(UNIVERSAL_VERSION_PATCH 1) @@ -130,6 +130,8 @@ option(BUILD_NUMBER_FIXPNTS "Set to ON to build static fixed-point option(BUILD_NUMBER_BFLOATS "Set to ON to build static bfloat tests" OFF) option(BUILD_NUMBER_CFLOATS "Set to ON to build static cfloat tests" OFF) option(BUILD_NUMBER_DFLOATS "Set to ON to build static dfloat tests" OFF) +option(BUILD_NUMBER_DDS "Set to ON to build static double-double tests" OFF) +option(BUILD_NUMBER_QDS "Set to ON to build static quad-double tests" OFF) option(BUILD_NUMBER_AREALS "Set to ON to build static areal tests" OFF) option(BUILD_NUMBER_UNUM1S "Set to ON to build static unum type 1 tests" OFF) option(BUILD_NUMBER_UNUM2S "Set to ON to build static unum type 2 tests" OFF) @@ -449,7 +451,7 @@ macro (compile_all testing prefix folder) get_filename_component (test ${source} NAME_WE) string(REPLACE " " ";" new_source ${source}) set(test_name ${prefix}_${test}) - message(STATUS "Add test ${test_name} from source ${new_source}.") + #message(STATUS "Add test ${test_name} from source ${new_source}.") add_executable (${test_name} ${new_source}) #add_custom_target(valid SOURCES ${SOURCES}) @@ -660,6 +662,8 @@ if(BUILD_NUMBER_STATICS) set(BUILD_NUMBER_BFLOATS ON) set(BUILD_NUMBER_CFLOATS ON) set(BUILD_NUMBER_DFLOATS ON) + set(BUILD_NUMBER_DDS ON) + set(BUILD_NUMBER_QDS ON) set(BUILD_NUMBER_AREALS ON) set(BUILD_NUMBER_UNUM1S ON) set(BUILD_NUMBER_UNUM2S ON) @@ -822,6 +826,16 @@ if(BUILD_NUMBER_DFLOATS) add_subdirectory("static/dfloat") endif(BUILD_NUMBER_DFLOATS) +# double-double floats +if(BUILD_NUMBER_DDS) +add_subdirectory("static/dd") +endif(BUILD_NUMBER_DDS) + +# quad-double floats +if(BUILD_NUMBER_QDS) +add_subdirectory("static/qd") +endif(BUILD_NUMBER_QDS) + # conversion tests suites if(BUILD_NUMBER_CONVERSIONS) add_subdirectory("static/conversions") @@ -925,6 +939,7 @@ add_subdirectory("applications/accuracy/optimization") add_subdirectory("applications/accuracy/pde") add_subdirectory("applications/accuracy/roots") add_subdirectory("applications/accuracy/science") +add_subdirectory("applications/accuracy/mathematics") add_subdirectory("applications/approximation/taylor") add_subdirectory("applications/approximation/chebyshev") diff --git a/Dockerfile b/Dockerfile index 618b185cb..957b7b808 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,6 @@ RUN cmake -DBUILD_ALL=ON .. && make # RELEASE stage #FROM alpine:latest as release # hitting a segfault during startup of some playground programs -#FROM debian:buster-slim as release FROM ubuntu:latest as release LABEL Theodore Omtzigt diff --git a/README.md b/README.md index ee90ec07f..f7c7d63ee 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Universal: a header-only C++ template library for universal number arithmetic +# Universal: a header-only C++ template library of custom arithmetic plug-in types | **System** | **Status** | **More information** | diff --git a/applications/accuracy/engineering/chem_equilibrium.cpp b/applications/accuracy/engineering/chem_equilibrium.cpp index b5f1fc0a1..02f95e92d 100644 --- a/applications/accuracy/engineering/chem_equilibrium.cpp +++ b/applications/accuracy/engineering/chem_equilibrium.cpp @@ -1,6 +1,7 @@ // chem_equilibrium.cpp : example of calculating the chemical balance of a solution // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/accuracy/engineering/water.cpp b/applications/accuracy/engineering/water.cpp index e04e0be95..1f7c3fa06 100644 --- a/applications/accuracy/engineering/water.cpp +++ b/applications/accuracy/engineering/water.cpp @@ -1,6 +1,7 @@ // water.cpp: example program showing water chemical equilibrium calculation sensitivity // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. // diff --git a/applications/accuracy/mathematics/CMakeLists.txt b/applications/accuracy/mathematics/CMakeLists.txt new file mode 100644 index 000000000..bf0bb1c36 --- /dev/null +++ b/applications/accuracy/mathematics/CMakeLists.txt @@ -0,0 +1,3 @@ +file (GLOB SOURCES "./*.cpp") + +compile_all("true" "math" "Applications/Accuracy/Mathematics" "${SOURCES}") diff --git a/applications/accuracy/mathematics/README.md b/applications/accuracy/mathematics/README.md new file mode 100644 index 000000000..1987f5d5e --- /dev/null +++ b/applications/accuracy/mathematics/README.md @@ -0,0 +1,47 @@ +# Computational Mathematics Examples + +This directory contains computational Mathematics examples that demonstrate and quantify the benefits +of using custom arithmetic to solve difficult numerical calculations using approximated real numbers. + +## Accuracy + +Posits control their precision by the difference between `nbits`and `es`. The number of fraction bits in the posit +is given by the equation: + +`fraction_bits = nbits - sign_bit - regime_bits - exponent_bits` + +Around `1` and `-1`, the regime field is encoded in its minimum form of 2 bits. +At the extreme regimes, the posit encoding will have no fraction bits, and effectively be an exponential. + +## Dynamic Range + +Posits control their dynamic range by the number of exponent bits. The number of exponent bits directly +controls the value of useed, which is the exponential shift, 2^2^es, of the regime. + +```text +IEEE float configurations from numeric_limits + float minexp scale -125 maxexp scale 128 minimum 1.17549e-38 maximum 3.40282e+38 + double minexp scale -1021 maxexp scale 1024 minimum 2.22507e-308 maximum 1.79769e+308 + long double minexp scale -1021 maxexp scale 1024 minimum 2.22507e-308 maximum 1.79769e+308 +``` + +## Reproducibility + +The crown jewel of posit arithmetic is the ability to restore associative and distributive laws of algebra. + +With IEEE floating point, associativity, that is + +```eq + y = (a + b) + c -> y = a + (b + c) +``` + +does not hold. The reason is that with IEEE floating point arithmetic, each operation immediately rounds +the result to the available precision. This caused two different rounding paths for the two equations. + +Similarly, distribution, that is + +```eq + y = (a + b) * c -> y = a*c + b*c +``` + +also does not hold, for the same reason. diff --git a/applications/accuracy/mathematics/numeric_constants.cpp b/applications/accuracy/mathematics/numeric_constants.cpp new file mode 100644 index 000000000..dd301fb2a --- /dev/null +++ b/applications/accuracy/mathematics/numeric_constants.cpp @@ -0,0 +1,223 @@ +// numeric_constants.cpp: experiments with mixed-precision representations of important numerical constants +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include // since C++20 + +namespace sw { + namespace universal { + + /* + template + struct _Invalid { + static_assert(_Always_false<_Ty>, "A program that instantiates a primary template of a mathematical constant " + "variable template is ill-formed. (N4950 [math.constants]/3)"); + }; + + template + inline constexpr _Ty e_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty log2e_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty log10e_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty pi_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty inv_pi_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty inv_sqrtpi_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty ln2_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty ln10_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty sqrt2_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty sqrt3_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty inv_sqrt3_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty egamma_v = _Invalid<_Ty>{}; + template + inline constexpr _Ty phi_v = _Invalid<_Ty>{}; + */ + + template + inline CONSTEXPRESSION _Ty e_v = static_cast<_Ty>(2.718281828459045); + template + inline CONSTEXPRESSION _Ty log2e_v = static_cast<_Ty>(1.4426950408889634); + template + inline CONSTEXPRESSION _Ty log10e_v = static_cast<_Ty>(0.4342944819032518); + template + inline CONSTEXPRESSION _Ty pi_v = static_cast<_Ty>(3.141592653589793); + template + inline CONSTEXPRESSION _Ty inv_pi_v = static_cast<_Ty>(0.3183098861837907); + template + inline CONSTEXPRESSION _Ty inv_sqrtpi_v = static_cast<_Ty>(0.5641895835477563); + template + inline CONSTEXPRESSION _Ty ln2_v = static_cast<_Ty>(0.6931471805599453); + template + inline CONSTEXPRESSION _Ty ln10_v = static_cast<_Ty>(2.302585092994046); + template + inline CONSTEXPRESSION _Ty sqrt2_v = static_cast<_Ty>(1.4142135623730951); + template + inline CONSTEXPRESSION _Ty sqrt3_v = static_cast<_Ty>(1.7320508075688772); + template + inline CONSTEXPRESSION _Ty inv_sqrt3_v = static_cast<_Ty>(0.5773502691896257); + template + inline CONSTEXPRESSION _Ty egamma_v = static_cast<_Ty>(0.5772156649015329); + template + inline CONSTEXPRESSION _Ty phi_v = static_cast<_Ty>(1.618033988749895); + + inline CONSTEXPRESSION half e_h = e_v; + inline CONSTEXPRESSION half log2e_h = log2e_v; + inline CONSTEXPRESSION half log10e_h = log10e_v; + inline CONSTEXPRESSION half pi_h = pi_v; + inline CONSTEXPRESSION half inv_pi_h = inv_pi_v; + inline CONSTEXPRESSION half inv_sqrtpi_h = inv_sqrtpi_v; + inline CONSTEXPRESSION half ln2_h = ln2_v; + inline CONSTEXPRESSION half ln10_h = ln10_v; + inline CONSTEXPRESSION half sqrt2_h = sqrt2_v; + inline CONSTEXPRESSION half sqrt3_h = sqrt3_v; + inline CONSTEXPRESSION half inv_sqrt3_h = inv_sqrt3_v; + inline CONSTEXPRESSION half egamma_h = egamma_v; + inline CONSTEXPRESSION half phi_h = phi_v; + + inline CONSTEXPRESSION single e_f = e_v; + inline CONSTEXPRESSION single log2e_f = log2e_v; + inline CONSTEXPRESSION single log10e_f = log10e_v; + inline CONSTEXPRESSION single pi_f = pi_v; + inline CONSTEXPRESSION single inv_pi_f = inv_pi_v; + inline CONSTEXPRESSION single inv_sqrtpi_f = inv_sqrtpi_v; + inline CONSTEXPRESSION single ln2_f = ln2_v; + inline CONSTEXPRESSION single ln10_f = ln10_v; + inline CONSTEXPRESSION single sqrt2_f = sqrt2_v; + inline CONSTEXPRESSION single sqrt3_f = sqrt3_v; + inline CONSTEXPRESSION single inv_sqrt3_f = inv_sqrt3_v; + inline CONSTEXPRESSION single egamma_f = egamma_v; + inline CONSTEXPRESSION single phi_f = phi_v; + + inline CONSTEXPRESSION double e_d = std::numbers::e_v; + inline CONSTEXPRESSION double log2e_d = std::numbers::log2e_v; + inline CONSTEXPRESSION double log10e_d = std::numbers::log10e_v; + inline CONSTEXPRESSION double pi_d = std::numbers::pi_v; + inline CONSTEXPRESSION double inv_pi_d = std::numbers::inv_pi_v; + inline CONSTEXPRESSION double inv_sqrtpi_d = std::numbers::inv_sqrtpi_v; + inline CONSTEXPRESSION double ln2_d = std::numbers::ln2_v; + inline CONSTEXPRESSION double ln10_d = std::numbers::ln10_v; + inline CONSTEXPRESSION double sqrt2_d = std::numbers::sqrt2_v; + inline CONSTEXPRESSION double sqrt3_d = std::numbers::sqrt3_v; + inline CONSTEXPRESSION double inv_sqrt3_d = std::numbers::inv_sqrt3_v; + inline CONSTEXPRESSION double egamma_d = std::numbers::egamma_v; + inline CONSTEXPRESSION double phi_d = std::numbers::phi_v; + } +} + +template +void Compare(const std::string& tag, _Ty c, double ref) { + using namespace sw::universal; + + std::cout << tag << " : "; + auto old = std::cout.precision(); + std::cout << std::setprecision(std::numeric_limits<_Ty>::digits10); + std::cout << to_binary(c) << " : " << std::left << std::scientific << std::setw(std::numeric_limits<_Ty>::digits10+2) << std::setfill('0') << c << " : "; + double error = ref - double(c); + std::cout << std::left << std::scientific << std::setw(std::numeric_limits<_Ty>::digits10 + 3) << std::setfill('0') << std::abs(error) << '\n'; + std::cout << std::setprecision(old); +} + +void CompareHalfPrecisionConstants() { + using namespace sw::universal; + using namespace std::numbers; + + std::cout << "constant : binary : value : error\n"; + Compare("e_h ", e_h, e); + Compare("log2e_h ", log2e_h, log2e); + Compare("log10e_h ", log10e_h, log10e); + Compare("pi_h ", pi_h, pi); + Compare("inv_pi_h ", inv_pi_h, inv_pi); + Compare("inv_sqrtpi_h", inv_sqrtpi_h, inv_sqrtpi); + Compare("ln2_h ", ln2_h, ln2); + Compare("ln10_h ", ln10_h, ln10); + Compare("sqrt2_h ", sqrt2_h, sqrt2); + Compare("inv_sqrt3_h ", inv_sqrt3_h, inv_sqrt3); + Compare("egamma_h ", egamma_h, egamma); + Compare("phi_h ", phi_h, phi); +} + +void CompareSinglePrecisionConstants() { + using namespace sw::universal; + using namespace std::numbers; + + std::cout << "constant : binary : value : error\n"; + Compare("e_f ", e_f, e); + Compare("log2e_f ", log2e_f, log2e); + Compare("log10e_f ", log10e_f, log10e); + Compare("pi_f ", pi_f, pi); + Compare("inv_pi_f ", inv_pi_f, inv_pi); + Compare("inv_sqrtpi_f", inv_sqrtpi_f, inv_sqrtpi); + Compare("ln2_f ", ln2_f, ln2); + Compare("ln10_f ", ln10_f, ln10); + Compare("sqrt2_f ", sqrt2_f, sqrt2); + Compare("inv_sqrt3_f ", inv_sqrt3_f, inv_sqrt3); + Compare("egamma_f ", egamma_f, egamma); + Compare("phi_f ", phi_f, phi); +} + +void CompareDoublePrecisionConstants() { + using namespace sw::universal; + using namespace std::numbers; + + std::cout << "constant : binary : value : error\n"; + Compare("e_d ", e_d, e); + Compare("log2e_d ", log2e_d, log2e); + Compare("log10e_d ", log10e_d, log10e); + Compare("pi_d ", pi_d, pi); + Compare("inv_pi_d ", inv_pi_d, inv_pi); + Compare("inv_sqrtpi_d", inv_sqrtpi_d, inv_sqrtpi); + Compare("ln2_d ", ln2_d, ln2); + Compare("ln10_d ", ln10_d, ln10); + Compare("sqrt2_d ", sqrt2_d, sqrt2); + Compare("inv_sqrt3_d ", inv_sqrt3_d, inv_sqrt3); + Compare("egamma_d ", egamma_d, egamma); + Compare("phi_d ", phi_d, phi); +} + +int main() +try { + using namespace sw::universal; + + CompareHalfPrecisionConstants(); + CompareSinglePrecisionConstants(); + CompareDoublePrecisionConstants(); + + return EXIT_SUCCESS; +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (std::runtime_error& err) { + std::cerr << "Caught unexpected runtime error: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} + diff --git a/applications/accuracy/ode/convergence.cpp b/applications/accuracy/ode/convergence.cpp index 79707a981..1531fdabf 100644 --- a/applications/accuracy/ode/convergence.cpp +++ b/applications/accuracy/ode/convergence.cpp @@ -1,6 +1,7 @@ // convergence.cpp: convergence analysis of ODE solvers // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Author: Jacob Todd jtodd1@une.edu // // This file is part of the universal numbers project, which is released under an MIT Open Source license diff --git a/applications/accuracy/ode/first_order_ode.cpp b/applications/accuracy/ode/first_order_ode.cpp index 5d94a7c1f..5b767a87c 100644 --- a/applications/accuracy/ode/first_order_ode.cpp +++ b/applications/accuracy/ode/first_order_ode.cpp @@ -1,6 +1,7 @@ // first_order_ode.cpp: program to compare different numerical solvers // -// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #define _USE_MATH_DEFINES diff --git a/applications/accuracy/ode/general_runge_kutta.cpp b/applications/accuracy/ode/general_runge_kutta.cpp index df43247c2..f40987627 100644 --- a/applications/accuracy/ode/general_runge_kutta.cpp +++ b/applications/accuracy/ode/general_runge_kutta.cpp @@ -1,6 +1,7 @@ // general_runge_kutta.cpp: program to solve odes with general RK method using coefficients from Butcher's table // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Author: Jacob Todd jtodd1@une.edu // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/applications/accuracy/pde/cg.cpp b/applications/accuracy/pde/cg.cpp index fe629af82..3eefd48bc 100644 --- a/applications/accuracy/pde/cg.cpp +++ b/applications/accuracy/pde/cg.cpp @@ -2,6 +2,7 @@ // using matrix-vector fused dot product operator, and compensation fused dot product operators // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/applications/accuracy/pde/gauss_seidel.cpp b/applications/accuracy/pde/gauss_seidel.cpp index 7614318b7..92c6eab9a 100644 --- a/applications/accuracy/pde/gauss_seidel.cpp +++ b/applications/accuracy/pde/gauss_seidel.cpp @@ -1,6 +1,7 @@ // gauss-seidel.cpp: Gauss-Seidel iterative method // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt, Allan Leal // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/applications/accuracy/pde/jacobi.cpp b/applications/accuracy/pde/jacobi.cpp index d5a7ee1df..a7af99c79 100644 --- a/applications/accuracy/pde/jacobi.cpp +++ b/applications/accuracy/pde/jacobi.cpp @@ -1,6 +1,7 @@ // jacobi.cpp: Jacobi iterative method // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt, Allan Leal // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/applications/accuracy/pde/sor.cpp b/applications/accuracy/pde/sor.cpp index 82c44a84c..d490c096e 100644 --- a/applications/accuracy/pde/sor.cpp +++ b/applications/accuracy/pde/sor.cpp @@ -1,6 +1,7 @@ // sor.cpp: Successive Over-Relaxation (SOR) iterative method // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/applications/accuracy/science/physics_constants.cpp b/applications/accuracy/science/physics_constants.cpp index 6626d73c8..6d33b70ad 100644 --- a/applications/accuracy/science/physics_constants.cpp +++ b/applications/accuracy/science/physics_constants.cpp @@ -1,9 +1,11 @@ // physics_constants.cpp: experiments with posit representations of important constants in physics // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include +#include #include #include #include @@ -67,44 +69,6 @@ std::string version_string(int a, int b, int c) { return ss.str(); } -std::string report_compiler_version() { -#if defined(__clang__) - /* Clang/LLVM. ---------------------------------------------- */ - return version_string(__clang_major__, __clang_minor__, __clang_patchlevel__); - -#elif defined(__ICC) || defined(__INTEL_COMPILER) - /* Intel ICC/ICPC. ------------------------------------------ */ - return std::string("Intel Compiler"); - -#elif defined(__GNUC__) || defined(__GNUG__) - /* GNU GCC/G++. --------------------------------------------- */ - return version_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); - -#elif defined(__HP_cc) || defined(__HP_aCC) - /* Hewlett-Packard C/C++. ---------------------------------- */ - return std::string("Hewlett-Packard C/C++ compiler"); - -#elif defined(__IBMC__) || defined(__IBMCPP__) - /* IBM XL C/C++. -------------------------------------------- */ - return std::string("IBM XL C/C++"); - -#elif defined(_MSC_VER) - /* Microsoft Visual Studio. --------------------------------- */ - // Visual C++ compiler is 15.00.20706.01, the _MSC_FULL_VER will be 15002070601 - char version[16]; - sprintf(version, "%d", _MSC_FULL_VER); - return std::string("Microsoft Visual Studio C++ compiler version ") + std::string(version); - -#elif defined(__PGI) - /* Portland Group PGCC/PGCPP. ------------------------------- */ - return std::string("Portland Group PGCC/PGCPP"); - -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - /* Oracle Solaris Studio. ----------------------------------- */ - return std::string("Oracle Solaris Studio"); -#endif -} - template void Represent(std::ostream& ostr, Scalar s, std::streamsize precision = 17, bool hexFormat = false) { // preserve the existing ostream precision @@ -123,15 +87,24 @@ void Represent(std::ostream& ostr, Scalar s, std::streamsize precision = 17, boo void Sample(std::ostream& ostr, long double constant) { using namespace sw::universal; - Represent(ostr << minmax_range< long double >() << " : ", constant, 23); - Represent(ostr << minmax_range< double >() << " : ", double(constant), 15); - Represent(ostr << minmax_range< float >() << " : ", float(constant), 6); - Represent(ostr << minmax_range< posit<32, 2> >() << " : ", posit<32, 2>(constant), 4, true); - Represent(ostr << minmax_range< posit<32, 3> >() << " : ", posit<32, 3>(constant), 6, true); - Represent(ostr << minmax_range< posit<40, 3> >() << " : ", posit<40, 3>(constant), 8, true); - Represent(ostr << minmax_range< posit<48, 3> >() << " : ", posit<48, 3>(constant), 10, true); - Represent(ostr << minmax_range< posit<56, 3> >() << " : ", posit<56, 3>(constant), 12, true); - Represent(ostr << minmax_range< posit<64, 3> >() << " : ", posit<64, 3>(constant), 15, true); + ostr << minmax_range< long double >(); ostr << " : "; + Represent(ostr, constant, 23); + ostr << minmax_range< double >(); ostr << " : "; + Represent(ostr, double(constant), 15); + ostr << minmax_range< float >(); ostr << " : "; + Represent(ostr, float(constant), 6); + std::string str = minmax_range< posit<32, 2> >(); ostr << str << " : "; + Represent(ostr, posit<32, 2>(constant), 4, true); + str = minmax_range< posit<32, 3> >(); ostr << str << " : "; + Represent(ostr, posit<32, 3>(constant), 6, true); + str = minmax_range< posit<40, 3> >(); ostr << str << " : "; + Represent(ostr, posit<40, 3>(constant), 8, true); + str = minmax_range< posit<48, 3> >(); ostr << str << " : "; + Represent(ostr, posit<48, 3>(constant), 10, true); + str = minmax_range< posit<56, 3> >(); ostr << str << " : "; + Represent(ostr, posit<56, 3>(constant), 12, true); + str = minmax_range< posit<64, 3> >(); ostr << str << " : "; + Represent(ostr, posit<64, 3>(constant), 15, true); } void CompareIEEEValues(std::ostream& ostr, long double constant) { @@ -157,7 +130,6 @@ void CompareIEEEValues(std::ostream& ostr, long double constant) { std::streamsize old_precision = std::cout.precision(); - ostr << report_compiler_version() << std::endl; ostr << "float precision : " << f_fbits << " bits\n"; ostr << "double precision : " << d_fbits << " bits\n"; ostr << "long double precision : " << q_fbits << " bits\n"; @@ -172,7 +144,7 @@ void CompareIEEEValues(std::ostream& ostr, long double constant) { std::cout << std::setprecision(old_precision); } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; @@ -183,6 +155,8 @@ try { // print detailed bit-level computational intermediate results // bool verbose = false; + report_compiler(); + long double h = 6.62607015e-34; // (J⋅s) long double e = 1.602176634e-19; // (C) long double k = 1.380649e-23; // (J⋅K−1) diff --git a/applications/precision/constants/euler.cpp b/applications/precision/constants/euler.cpp index 4d3202fe6..b609c81be 100644 --- a/applications/precision/constants/euler.cpp +++ b/applications/precision/constants/euler.cpp @@ -1,6 +1,7 @@ // euler.cpp: generating a 'perfect' approximation of Euler's constant e for a given number system // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/constants/phi.cpp b/applications/precision/constants/phi.cpp index c9ee8e165..a24ad9041 100644 --- a/applications/precision/constants/phi.cpp +++ b/applications/precision/constants/phi.cpp @@ -1,6 +1,7 @@ // phi.cpp: generating a 'perfect' approximation of the Golden Ratio constant phi for a given number system // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/constants/pi.cpp b/applications/precision/constants/pi.cpp index 2f1e6faa3..2c634d7c0 100644 --- a/applications/precision/constants/pi.cpp +++ b/applications/precision/constants/pi.cpp @@ -1,6 +1,7 @@ // pi.cpp: generating a 'perfect' approximation of pi for a given number system // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/catastrophic_cancellation.cpp b/applications/precision/floating-point/catastrophic_cancellation.cpp index c894edf1f..5ae31bc3d 100644 --- a/applications/precision/floating-point/catastrophic_cancellation.cpp +++ b/applications/precision/floating-point/catastrophic_cancellation.cpp @@ -1,6 +1,7 @@ // catastrophic_cancellation.cpp: examples of catastrophic cancellation // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/contract_expand.cpp b/applications/precision/floating-point/contract_expand.cpp index 72a94534f..bc8bab1a7 100644 --- a/applications/precision/floating-point/contract_expand.cpp +++ b/applications/precision/floating-point/contract_expand.cpp @@ -1,6 +1,7 @@ // contract_expand.cpp: evaluation of contractions and expansions of posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include @@ -41,10 +42,10 @@ void ContractionExpansion(int depth) { template void RangeTable(std::ostream& ostr) { using namespace sw::universal; - constexpr size_t nbits = Scalar::nbits; + constexpr unsigned nbits = Scalar::nbits; static_assert(nbits < 16, "size of the table is constrained to nbits < 16"); - size_t COLUMN_WIDTH = 10; + unsigned COLUMN_WIDTH = 10; size_t NR_SAMPLES = (1ull << (nbits - 1)); // ignore negative values Scalar x; ostr << std::setw(COLUMN_WIDTH) << "x" << ',' @@ -54,7 +55,7 @@ void RangeTable(std::ostream& ostr) { << std::setw(COLUMN_WIDTH) << "y = sqrt(x^2)" << ',' << std::setw(COLUMN_WIDTH) << "y = sqrt(x)^2" << '\n'; - for (size_t i = 0; i < NR_SAMPLES; ++i) { + for (unsigned i = 0; i < NR_SAMPLES; ++i) { x.setbits(i); Scalar sqrt_x = pow(x, 0.5); Scalar x_sqr = pow(x, 2.0); @@ -72,7 +73,7 @@ void RangeTable(std::ostream& ostr) { void SquareRootSquared(std::ostream& ostr) { constexpr size_t nbits = 8; // the sampling - size_t COLUMN_WIDTH = 10; + unsigned COLUMN_WIDTH = 10; size_t NR_SAMPLES = (1ull << (nbits - 1)); // ignore negative values using c8_2 = sw::universal::cfloat< 8, 2, uint8_t, true, true, false>; using c10_2 = sw::universal::cfloat<10, 2, uint8_t, true, true, false> ; @@ -88,7 +89,7 @@ void SquareRootSquared(std::ostream& ostr) { << std::setw(COLUMN_WIDTH) << "cfloat<16,2>" << ',' << '\n'; c8_2 x; - for (size_t i = 0; i < NR_SAMPLES; ++i) { + for (unsigned i = 0; i < NR_SAMPLES; ++i) { x.setbits(i); float v = float(x); c8_2 v8(v); @@ -109,8 +110,8 @@ void SquareRootSquared(std::ostream& ostr) { } void SquareRootSquared2(std::ostream& ostr) { - constexpr size_t nbits = 8; // the sampling - size_t COLUMN_WIDTH = 10; + constexpr unsigned nbits = 8; // the sampling + unsigned COLUMN_WIDTH = 10; size_t NR_SAMPLES = (1ull << (nbits - 1)); // ignore negative values using c8_2 = sw::universal::cfloat<8, 2>; using c10_2 = sw::universal::cfloat<10, 2>; @@ -126,7 +127,7 @@ void SquareRootSquared2(std::ostream& ostr) { << std::setw(COLUMN_WIDTH) << "cfloat<16,5>" << ',' << '\n'; c8_2 x; - for (size_t i = 0; i < NR_SAMPLES; ++i) { + for (unsigned i = 0; i < NR_SAMPLES; ++i) { x.setbits(i); float v = float(x); c8_2 v8(v); diff --git a/applications/precision/numeric/doubledouble.cpp b/applications/precision/floating-point/doubledouble.cpp similarity index 56% rename from applications/precision/numeric/doubledouble.cpp rename to applications/precision/floating-point/doubledouble.cpp index d0873534a..8a7bc528f 100644 --- a/applications/precision/numeric/doubledouble.cpp +++ b/applications/precision/floating-point/doubledouble.cpp @@ -1,24 +1,21 @@ // doubledouble.cpp: experiments with double-double floating-point arithmetic // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include #include #include -#if (__cplusplus == 202003L) || (_MSVC_LANG == 202003L) #include // high-precision numbers -#endif + +#include // the double-double format +//#include // the quad-double format +#include // the classic floating-point reference + #include #include -// select the number systems we would like to compare -#include -#include -#include -#include -#include - /* Definition of FAITHFUL arithmetic For a t-digit number a and b, and op element {+,-,*,/}, let c = a op b exactly. @@ -43,15 +40,59 @@ try { std::streamsize precision = std::cout.precision(); { - using LNS = lns<16, 10, std::uint16_t>; + using doubledouble = dd; - LNS a{}, b{}, c{}; + doubledouble a, b{}, c{}; a = 0.5; b = 2.0; c = a * b; ReportBinaryOperation(a, "*", b, c); } + { + dd a; + a = 1.0f; + std::cout << to_binary(a) << " : " << a << '\n'; + } + + // important behavioral traits + { + using TestType = dd; + ReportTrivialityOfType(); + } + + // default behavior + std::cout << "+--------- Default doubledouble has subnormals, but no supernormals\n"; + { + using Real = dd; + + Real a(1.0f), b(0.5f); + ArithmeticOperators(a, b); + } + + // report on the dynamic range of some standard configurations + std::cout << "+--------- Dynamic ranges of standard double configurations --------+\n"; + { + dd a; // uninitialized + + a.maxpos(); + std::cout << "maxpos bfloat16 : " << to_binary(a) << " : " << a << '\n'; + a.setbits(0x0080); // positive min normal + std::cout << "minnorm bfloat16 : " << to_binary(a) << " : " << a << '\n'; + a.minpos(); + std::cout << "minpos bfloat16 : " << to_binary(a) << " : " << a << '\n'; + a.zero(); + std::cout << "zero : " << to_binary(a) << " : " << a << '\n'; + a.minneg(); + std::cout << "minneg bfloat16 : " << to_binary(a) << " : " << a << '\n'; + a.setbits(0x8080); // negative min normal + std::cout << "minnegnorm : " << to_binary(a) << " : " << a << '\n'; + a.maxneg(); + std::cout << "maxneg bfloat16 : " << to_binary(a) << " : " << a << '\n'; + + std::cout << "---\n"; + } + std::cout << std::setprecision(precision); std::cout << std::endl; diff --git a/applications/precision/floating-point/exponentiation.cpp b/applications/precision/floating-point/exponentiation.cpp index d95bced7a..2084dee10 100644 --- a/applications/precision/floating-point/exponentiation.cpp +++ b/applications/precision/floating-point/exponentiation.cpp @@ -1,6 +1,7 @@ // exponentiation.cpp: evaluation of exponentiation of posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/integer_cover.cpp b/applications/precision/floating-point/integer_cover.cpp index be4e6fbee..a094d0d16 100644 --- a/applications/precision/floating-point/integer_cover.cpp +++ b/applications/precision/floating-point/integer_cover.cpp @@ -1,6 +1,7 @@ // integer_cover.cpp: measuring the covering of the integers with a posit // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/kahan_sum.cpp b/applications/precision/floating-point/kahan_sum.cpp index e517828bf..a1ffe2c66 100644 --- a/applications/precision/floating-point/kahan_sum.cpp +++ b/applications/precision/floating-point/kahan_sum.cpp @@ -1,6 +1,7 @@ // kahan_sum.cpp: Kahan summation evaluation of posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/linear_cover.cpp b/applications/precision/floating-point/linear_cover.cpp index 631c87a39..89dc9adc8 100644 --- a/applications/precision/floating-point/linear_cover.cpp +++ b/applications/precision/floating-point/linear_cover.cpp @@ -1,8 +1,10 @@ // linear_cover.cpp: covering a linear range with a posit // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. +#include #include #include // ReportTestResult #include @@ -84,7 +86,7 @@ void TestLinearSamples() { } } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/floating-point/precision.cpp b/applications/precision/floating-point/precision.cpp index 282baa5c8..26da593a8 100644 --- a/applications/precision/floating-point/precision.cpp +++ b/applications/precision/floating-point/precision.cpp @@ -1,8 +1,10 @@ // precision.cpp: experiments with accuracy and precision in posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. +#include #include /* @@ -72,7 +74,7 @@ we know the focal length to ~0.65 decimal digits, or ~2.16 bits. */ -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/floating-point/printing.cpp b/applications/precision/floating-point/printing.cpp index 5faa8d135..6e197bcf7 100644 --- a/applications/precision/floating-point/printing.cpp +++ b/applications/precision/floating-point/printing.cpp @@ -1,8 +1,10 @@ // printing.cpp: experiments with printing floating-point numbers // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. +#include #include #include #include @@ -65,7 +67,7 @@ void Convert(Real v, sw::universal::support::decimal& digits) { std::cout << "(" << e << ", " << nLeft << ", " << nRight << ")\n"; Digits(nLeft, nRight); } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/floating-point/rounding_error_addition.cpp b/applications/precision/floating-point/rounding_error_addition.cpp index e610182fe..286c3934e 100644 --- a/applications/precision/floating-point/rounding_error_addition.cpp +++ b/applications/precision/floating-point/rounding_error_addition.cpp @@ -1,6 +1,7 @@ // rounding_error_addition.cpp: rounding error comparision for addition // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/rounding_error_multiplication.cpp b/applications/precision/floating-point/rounding_error_multiplication.cpp index 90f005696..10b1eec00 100644 --- a/applications/precision/floating-point/rounding_error_multiplication.cpp +++ b/applications/precision/floating-point/rounding_error_multiplication.cpp @@ -1,6 +1,7 @@ // rounding_error_multiplication.cpp: evaluation of rounding errors of multiplication in the posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/sterbenz_lemma.cpp b/applications/precision/floating-point/sterbenz_lemma.cpp index 9c51e2da2..ae4b5b391 100644 --- a/applications/precision/floating-point/sterbenz_lemma.cpp +++ b/applications/precision/floating-point/sterbenz_lemma.cpp @@ -1,6 +1,7 @@ // sterbenz_lemma.cpp: Demonstration of Sterbenz Lemma // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/sum_of_integers.cpp b/applications/precision/floating-point/sum_of_integers.cpp index e58bc699d..2d4076ec3 100644 --- a/applications/precision/floating-point/sum_of_integers.cpp +++ b/applications/precision/floating-point/sum_of_integers.cpp @@ -1,6 +1,7 @@ // sum_of_integers.cpp: evaluation of a sequence of additions in the posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/thin_triangle.cpp b/applications/precision/floating-point/thin_triangle.cpp index 4eec8d14d..6bf4ffa42 100644 --- a/applications/precision/floating-point/thin_triangle.cpp +++ b/applications/precision/floating-point/thin_triangle.cpp @@ -1,6 +1,7 @@ // goldberg_thin_triangle.cpp: example program showing the Goldberg thin triangle example // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/floating-point/two_sum.cpp b/applications/precision/floating-point/two_sum.cpp index 20161b10a..4a98b3ed4 100644 --- a/applications/precision/floating-point/two_sum.cpp +++ b/applications/precision/floating-point/two_sum.cpp @@ -1,8 +1,10 @@ // two_sum.cpp: TwoSum evaluation of posit number systems // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. +#include #include #include @@ -82,7 +84,7 @@ bool GenerateTwoSumTestCase(const Scalar& a, const Scalar& b) { // enumerate all addition cases for a posit configuration: is within 10sec till about nbits = 14 template -int ValidateTwoSum(const std::string& tag, bool reportTestCases) { +int ValidateTwoSum(bool reportTestCases) { const unsigned NR_POSITS = (unsigned(1) << nbits); int nrOfFailedTests = 0; using Posit = sw::universal::posit; @@ -155,32 +157,32 @@ try { ReportTestSuiteResults(test_suite, nrOfFailedTestCases); return EXIT_SUCCESS; // ignore failures #else - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<2, 0>(test_tag, reportTestCases), "posit<2,0>", "twoSum"); - - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<3, 0>(test_tag, reportTestCases), "posit<3,0>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<3, 1>(test_tag, reportTestCases), "posit<3,1>", "twoSum"); - - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<4, 0>(test_tag, reportTestCases), "posit<4,0>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<4, 1>(test_tag, reportTestCases), "posit<4,1>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<4, 2>(test_tag, reportTestCases), "posit<4,2>", "twoSum"); - - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 0>(test_tag, reportTestCases), "posit<5,0>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 1>(test_tag, reportTestCases), "posit<5,1>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 2>(test_tag, reportTestCases), "posit<5,2>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 3>(test_tag, reportTestCases), "posit<5,3>", "twoSum"); - - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 0>(test_tag, reportTestCases), "posit<6,0>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 1>(test_tag, reportTestCases), "posit<6,1>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 2>(test_tag, reportTestCases), "posit<6,2>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 3>(test_tag, reportTestCases), "posit<6,3>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 4>(test_tag, reportTestCases), "posit<6,4>", "twoSum"); - - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 0>(test_tag, reportTestCases), "posit<8,0>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 1>(test_tag, reportTestCases), "posit<8,1>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 2>(test_tag, reportTestCases), "posit<8,2>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 3>(test_tag, reportTestCases), "posit<8,3>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 4>(test_tag, reportTestCases), "posit<8,4>", "twoSum"); - nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 5>(test_tag, reportTestCases), "posit<8,5>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<2, 0>(reportTestCases), "posit<2,0>", "twoSum"); + + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<3, 0>(reportTestCases), "posit<3,0>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<3, 1>(reportTestCases), "posit<3,1>", "twoSum"); + + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<4, 0>(reportTestCases), "posit<4,0>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<4, 1>(reportTestCases), "posit<4,1>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<4, 2>(reportTestCases), "posit<4,2>", "twoSum"); + + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 0>(reportTestCases), "posit<5,0>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 1>(reportTestCases), "posit<5,1>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 2>(reportTestCases), "posit<5,2>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<5, 3>(reportTestCases), "posit<5,3>", "twoSum"); + + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 0>(reportTestCases), "posit<6,0>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 1>(reportTestCases), "posit<6,1>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 2>(reportTestCases), "posit<6,2>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 3>(reportTestCases), "posit<6,3>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<6, 4>(reportTestCases), "posit<6,4>", "twoSum"); + + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 0>(reportTestCases), "posit<8,0>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 1>(reportTestCases), "posit<8,1>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 2>(reportTestCases), "posit<8,2>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 3>(reportTestCases), "posit<8,3>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 4>(reportTestCases), "posit<8,4>", "twoSum"); + nrOfFailedTestCases += ReportTestResult(ValidateTwoSum<8, 5>(reportTestCases), "posit<8,5>", "twoSum"); ReportTestSuiteResults(test_suite, nrOfFailedTestCases); diff --git a/applications/precision/floating-point/underflow.cpp b/applications/precision/floating-point/underflow.cpp index 29752fb8b..f705cfd35 100644 --- a/applications/precision/floating-point/underflow.cpp +++ b/applications/precision/floating-point/underflow.cpp @@ -1,6 +1,7 @@ // underflow.cpp: experiments with underfow in posit number systems // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the UNIVERSAL project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/math/decimal_lpp.cpp b/applications/precision/math/decimal_lpp.cpp index 28f9cf4e9..ac9925074 100644 --- a/applications/precision/math/decimal_lpp.cpp +++ b/applications/precision/math/decimal_lpp.cpp @@ -1,8 +1,10 @@ // edecimal_lpp.cpp : algorithm to find the largest palindrome product using adaptive precision decimal number system // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include diff --git a/applications/precision/math/distinct_powers.cpp b/applications/precision/math/distinct_powers.cpp index b47182b2c..46b9f4f47 100644 --- a/applications/precision/math/distinct_powers.cpp +++ b/applications/precision/math/distinct_powers.cpp @@ -1,8 +1,10 @@ // distinct_powers.cpp : algorithm to find all integer combinations of a^b for some range [min, max] // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include diff --git a/applications/precision/math/irrational_powers.cpp b/applications/precision/math/irrational_powers.cpp index 30e52a798..04e7911a1 100644 --- a/applications/precision/math/irrational_powers.cpp +++ b/applications/precision/math/irrational_powers.cpp @@ -1,8 +1,10 @@ // irrational_powers.cpp: experiments with irrational numbers and their approximations // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include @@ -25,7 +27,7 @@ * Let's see what happens when you use floating-point arithmetic */ -static constexpr size_t FIELD_WIDTH = 60; +static constexpr size_t FIELD_WIDTH = 75; template Real r_to_q_to_q(const Real& r, const Real& q) { @@ -41,11 +43,10 @@ void evaluate(double _r, double _q) Real r(_r); Real q(_q); - std::stringstream tt; -// tt << std::setw(FIELD_WIDTH) << sw::universal::type_tag(r); TODO: make this work - tt << std::setw(FIELD_WIDTH) << typeid(r).name() << ": "; + std::stringstream t; + t << std::right << std::setw(FIELD_WIDTH) << sw::universal::type_tag(r) << ": "; - std::cout << tt.str() << s.str() << r_to_q_to_q(r, q) << '\n'; + std::cout << t.str() << s.str() << r_to_q_to_q(r, q) << '\n'; } void CompareIrrationalPowers(double _r, double _q) { @@ -73,7 +74,7 @@ void CompareIrrationalPowers(double _r, double _q) { std::cout << '\n'; } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/math/largest_palindrome_product.cpp b/applications/precision/math/largest_palindrome_product.cpp index c586fd035..bc57cd76e 100644 --- a/applications/precision/math/largest_palindrome_product.cpp +++ b/applications/precision/math/largest_palindrome_product.cpp @@ -1,8 +1,10 @@ // largest_palindrome_product.cpp : algorithm to find the largest palindrome product // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include diff --git a/applications/precision/math/numbers_irrational.cpp b/applications/precision/math/numbers_irrational.cpp index f0636abd9..c24bb307d 100644 --- a/applications/precision/math/numbers_irrational.cpp +++ b/applications/precision/math/numbers_irrational.cpp @@ -1,8 +1,10 @@ // numbers_irrational.cpp: experiments with irrational numbers and their approximations // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include @@ -32,10 +34,10 @@ Ty PhiThroughFibonacciSequence(unsigned terms) { template void GoldenRatioTerms(unsigned terms) { auto p = sw::sequences::GoldenRatio(terms); - std::cout << p.first << " " << p.second << " : approximation to phi " << 1.0 + p.first / p. second << std::endl; + std::cout << p.first << " " << p.second << " : approximation to phi " << (1.0 + double(p.first / p. second)) << std::endl; } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/math/numbers_rational.cpp b/applications/precision/math/numbers_rational.cpp index a6d2fad5b..f8f7926dd 100644 --- a/applications/precision/math/numbers_rational.cpp +++ b/applications/precision/math/numbers_rational.cpp @@ -1,8 +1,10 @@ // numbers_rational.cpp: experiments with rational numbers and their approximations // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include @@ -10,7 +12,7 @@ /* Rational numbers: what do we want to show? */ -int main(int argc, char** argv) +int main() try { using namespace sw::universal; using namespace sw::sequences; diff --git a/applications/precision/math/pascals_triangle.cpp b/applications/precision/math/pascals_triangle.cpp index 4dded3dcf..de9d81790 100644 --- a/applications/precision/math/pascals_triangle.cpp +++ b/applications/precision/math/pascals_triangle.cpp @@ -2,9 +2,11 @@ // // Binomial coefficients are useful to generate the inverse of a Hilbert matrix // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal number project, which is released under an MIT Open Source license. +#include #include #include // enable posit arithmetic exceptions @@ -12,9 +14,10 @@ #include #include -std::string spacing(unsigned n) { +std::string spacing(int n) { std::stringstream ss; - for (unsigned i = 0; i < n; ++i) { + if (n < 0) return std::string(""); + for (int i = 0; i < n; ++i) { ss << ' '; } return ss.str(); diff --git a/applications/precision/math/primes.cpp b/applications/precision/math/primes.cpp index 68541a1b0..4f77158d7 100644 --- a/applications/precision/math/primes.cpp +++ b/applications/precision/math/primes.cpp @@ -2,7 +2,8 @@ // // prime number generation and Fermat factorization // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal number project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/math/sincospi.cpp b/applications/precision/math/sincospi.cpp index b8ddb401d..7299f6e62 100644 --- a/applications/precision/math/sincospi.cpp +++ b/applications/precision/math/sincospi.cpp @@ -3,9 +3,11 @@ // sinpi/cospi trigonometric functions // inspired by: https://stackoverflow.com/questions/42792939/implementation-of-sinpi-and-cospi-using-standard-c-math-library // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal number project, which is released under an MIT Open Source license. +#include #include #include #include diff --git a/applications/precision/math/stirlings_approximation.cpp b/applications/precision/math/stirlings_approximation.cpp index 9c6313f6f..e713bbeb6 100644 --- a/applications/precision/math/stirlings_approximation.cpp +++ b/applications/precision/math/stirlings_approximation.cpp @@ -1,8 +1,10 @@ // stirlings_approximation.cpp : Stirling's approximation for factorials // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include diff --git a/applications/precision/numeric/constants.cpp b/applications/precision/numeric/constants.cpp index c52bf4133..03f8bdddd 100644 --- a/applications/precision/numeric/constants.cpp +++ b/applications/precision/numeric/constants.cpp @@ -1,6 +1,7 @@ // numbers.cpp: example program to use C++20 high precision constants // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -93,14 +94,8 @@ try { std::cout << "high-precision constants\n"; -#if LONG_DOUBLE_SUPPORT - using Native = long double; - std::string native = "long double"; -#else - using Native = double; std::string native = "double"; - -#endif + using Native = double; using Fixed = fixpnt<80,75>; using Posit = posit<64,2>; using HP = cfloat< 16, 5, uint32_t, true>; @@ -117,7 +112,6 @@ try { // CompareBabylonianMethods(2.0); - // MSVC doesn't support proper long double: this is guarded with a compile guard: LONG_DOUBLE_SUPPORT { std::cout << "sqrt(2)\n"; float f = 2.0f; diff --git a/applications/precision/numeric/midpoint.cpp b/applications/precision/numeric/midpoint.cpp index 23c60be74..f12d78f37 100644 --- a/applications/precision/numeric/midpoint.cpp +++ b/applications/precision/numeric/midpoint.cpp @@ -1,130 +1,108 @@ // midpoint.cpp: example program to use C++20 lerp and midpoint functions // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include -#include // lerp and midpoint -#if (__cplusplus == 202003L) || (_MSVC_LANG == 202003L) -#include // high-precision numbers -#endif - +#include // lerp +#include // midpoint +#include // high-precision constants // select the number systems we would like to compare +#include #include #include #include #include #include -#include -#include -#include -#include +#include -int main(int argc, char** argv) -try { - using namespace sw::universal; - std::cout << "high-precision constants\n"; - -#if defined(_MSC_VER) && (_MSC_VER >= 1300) - std::cout << "Microsoft Visual C++: " << _MSC_VER << '\n'; - /* - MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010 version 10.0) - MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012 version 11.0) - MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013 version 12.0) - MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015 version 14.0) - MSVC++ 14.1 _MSC_VER == 1910 (Visual Studio 2017 version 15.0) - MSVC++ 14.11 _MSC_VER == 1911 (Visual Studio 2017 version 15.3) - MSVC++ 14.12 _MSC_VER == 1912 (Visual Studio 2017 version 15.5) - MSVC++ 14.13 _MSC_VER == 1913 (Visual Studio 2017 version 15.6) - MSVC++ 14.14 _MSC_VER == 1914 (Visual Studio 2017 version 15.7) - MSVC++ 14.15 _MSC_VER == 1915 (Visual Studio 2017 version 15.8) - MSVC++ 14.16 _MSC_VER == 1916 (Visual Studio 2017 version 15.9) - MSVC++ 14.2 _MSC_VER == 1920 (Visual Studio 2019 Version 16.0) - MSVC++ 14.21 _MSC_VER == 1921 (Visual Studio 2019 Version 16.1) - MSVC++ 14.22 _MSC_VER == 1922 (Visual Studio 2019 Version 16.2) - MSVC++ 14.23 _MSC_VER == 1923 (Visual Studio 2019 Version 16.3) - MSVC++ 14.24 _MSC_VER == 1924 (Visual Studio 2019 Version 16.4) - MSVC++ 14.25 _MSC_VER == 1925 (Visual Studio 2019 Version 16.5) - MSVC++ 14.26 _MSC_VER == 1926 (Visual Studio 2019 Version 16.6) - MSVC++ 14.27 _MSC_VER == 1927 (Visual Studio 2019 Version 16.7) - */ - if (_MSC_VER == 1600) std::cout << "(Visual Studio 2010 version 10.0)\n"; - else if (_MSC_VER == 1700) std::cout << "(Visual Studio 2012 version 11.0)\n"; - else if (_MSC_VER == 1800) std::cout << "(Visual Studio 2013 version 12.0)\n"; - else if (_MSC_VER == 1900) std::cout << "(Visual Studio 2015 version 14.0)\n"; - else if (_MSC_VER == 1910) std::cout << "(Visual Studio 2017 version 15.0)\n"; - else if (_MSC_VER == 1911) std::cout << "(Visual Studio 2017 version 15.3)\n"; - else if (_MSC_VER == 1912) std::cout << "(Visual Studio 2017 version 15.5)\n"; - else if (_MSC_VER == 1913) std::cout << "(Visual Studio 2017 version 15.6)\n"; - else if (_MSC_VER == 1914) std::cout << "(Visual Studio 2017 version 15.7)\n"; - else if (_MSC_VER == 1915) std::cout << "(Visual Studio 2017 version 15.8)\n"; - else if (_MSC_VER == 1916) std::cout << "(Visual Studio 2017 version 15.9)\n"; - else if (_MSC_VER == 1920) std::cout << "(Visual Studio 2019 Version 16.0)\n"; - else if (_MSC_VER == 1921) std::cout << "(Visual Studio 2019 Version 16.1)\n"; - else if (_MSC_VER == 1922) std::cout << "(Visual Studio 2019 Version 16.2)\n"; - else if (_MSC_VER == 1923) std::cout << "(Visual Studio 2019 Version 16.3)\n"; - else if (_MSC_VER == 1924) std::cout << "(Visual Studio 2019 Version 16.4)\n"; - else if (_MSC_VER == 1925) std::cout << "(Visual Studio 2019 Version 16.5)\n"; - else if (_MSC_VER == 1926) std::cout << "(Visual Studio 2019 Version 16.6)\n"; - else if (_MSC_VER == 1927) std::cout << "(Visual Studio 2019 Version 16.7)\n"; - else std::cout << "Microsoft Visual C++: " << _MSC_VER << '\n'; - - std::cout << "__cplusplus: " << __cplusplus << '\n'; - - /* - _MSVC_LANG Defined as an integer literal that specifies the C++ language standard targeted by the compiler. - It's set only in code compiled as C++. The macro is the integer literal value 201402L by default, - or when the /std:c++14 compiler option is specified. The macro is set to 201703L if the /std:c++17 - compiler option is specified. It's set to a higher, unspecified value when the /std:c++latest option - is specified. Otherwise, the macro is undefined. - The _MSVC_LANG macro and /std(Specify Language Standard Version) compiler options are available - beginning in Visual Studio 2015 Update 3. - */ - if (_MSVC_LANG == 201402l) std::cout << "/std:c++14\n"; - else if (_MSVC_LANG == 201703l) std::cout << "/std:c++17\n"; - else if (_MSVC_LANG == 201704l) std::cout << "/std:c++latest\n"; - else std::cout << "_MSVC_LANG: " << _MSVC_LANG << '\n'; +void example() { + using std::midpoint; +#if (__cplusplus >= 202002L) + + std::cout << std::setprecision(50); + std::cout << "midpoint " << std::midpoint(5, 7) << '\n'; + std::cout << "lerp " << std::lerp(5, 7, 0.5f) << '\n'; + + using Real = float; + + Real a(1.0), b(2.0); + Real mp = midpoint(a, b); + std::cout << "midpoint(1.0, 2.0) = " << mp << '\n'; + std::cout << "a=" << a << '\n' + << "b=" << b << '\n' + << "mid point=" << std::lerp(a, b, 0.5f) << '\n' + << std::boolalpha << (a == std::lerp(a, b, 0.0f)) << '\n'; #else - if (__cplusplus == 202003L) std::cout << "C++20\n"; - else if (__cplusplus == 201703L) std::cout << "C++17\n"; - else if (__cplusplus == 201402L) std::cout << "C++14\n"; - else if (__cplusplus == 201103L) std::cout << "C++11\n"; - else if (__cplusplus == 199711L) std::cout << "C++98\n"; - else std::cout << __cplusplus << " pre-standard C++\n"; + std::cerr << "midpoint program requires C++20\n"; #endif +} + +template +std::pair GenerateRange(Real lb, Real nr_ulps = Real(7)) { + using namespace sw::universal; + + Real n = nextafter(lb, Real(2.0) * lb); + Real lb_ulp = n - lb; + std::cout << "ULP " << to_binary(lb_ulp) << " : " << lb_ulp << '\n'; + + Real ub = lb + nr_ulps * lb_ulp; + + return std::pair(lb, ub); +} + +template +void Midpoint(const std::pair p) { + using namespace sw::universal; + using std::midpoint; // in case Real is a native type supported by std + + Real mp = std::midpoint(p.first, p.second); + + std::cout << type_tag(mp) << '\n'; + ReportValue(p.first); + ReportValue(mp); + ReportValue(p.second); +} + +template +void GenerateMidpointTestCase(Real lb, Real multiple_ulps) { + Midpoint(GenerateRange(lb, multiple_ulps)); +} + +int main() +try { + using namespace sw::universal; + using std::midpoint; + + std::cout << "lerp and midpoint operators\n"; -#if MIXED using int32 = integer<32>; using fixpnt32 = fixpnt<32,16>; using posit32 = posit<32,2>; using areal32 = areal<32,8>; - using lns32 = lns<32>; -#endif + using lns32 = lns<32,23>; // check difficult midpoint and lerp operations on different number systems std::streamsize precision = std::cout.precision(); -#if (__cplusplus == 202003L) || (_MSVC_LANG == 202003L) - - cout << std::setprecision(50); - cout << "midpoint " << std::midpoint(5,7) << endl; - cout << "lerp " << std::lerp(5,7,0.5f) << endl; + std::cout << std::setprecision(23); - float a=10.0f, b=20.0f; - - std::cout << "a=" << a << '\n' - << "b=" << b << '\n' - << "mid point=" << std::lerp(a,b,0.5f) << '\n' - << std::boolalpha << (a == std::lerp(a,b,0.0f)) << '\n'; -#endif + GenerateMidpointTestCase(1, 7); +// GenerateMidpointTestCase(1, 6); +// GenerateMidpointTestCase(1, 6); +// GenerateMidpointTestCase(1, 6); +// GenerateMidpointTestCase(1, 6); +// GenerateMidpointTestCase(1, 6); - std::cout << std::setprecision(precision); - std::cout << std::endl; + std::cout << std::setprecision(precision); + std::cout << std::endl; return EXIT_SUCCESS; } diff --git a/applications/precision/numeric/numbers.cpp b/applications/precision/numeric/numbers.cpp index 2406b7347..ca5f380a4 100644 --- a/applications/precision/numeric/numbers.cpp +++ b/applications/precision/numeric/numbers.cpp @@ -1,6 +1,7 @@ // numbers.cpp: example program to use C++20 high precision constants // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -10,9 +11,7 @@ #include #include #include -#if (__cplusplus == 202003L) || (_MSVC_LANG == 202003L) -#include // high-precision numbers -#endif +#include // high-precision constants // select the number systems we would like to compare #include diff --git a/applications/precision/numeric/posit_properties.cpp b/applications/precision/numeric/posit_properties.cpp index 921a92b26..182dc6a0f 100644 --- a/applications/precision/numeric/posit_properties.cpp +++ b/applications/precision/numeric/posit_properties.cpp @@ -1,8 +1,10 @@ // posit_properties.cpp example program comparing epsilon and minpos across posit configurations // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include @@ -105,7 +107,7 @@ std::string properties(const std::string& label) { return ostr.str(); } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/numeric/priest.cpp b/applications/precision/numeric/priest.cpp index 580484883..8e39c881e 100644 --- a/applications/precision/numeric/priest.cpp +++ b/applications/precision/numeric/priest.cpp @@ -1,6 +1,7 @@ // priest.cpp: experiments with Douglas Priest's arbitrary precision floating-point arithmetic // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/precision/numeric/quadratic.cpp b/applications/precision/numeric/quadratic.cpp index 5ba7f2576..b2293c35a 100644 --- a/applications/precision/numeric/quadratic.cpp +++ b/applications/precision/numeric/quadratic.cpp @@ -1,13 +1,12 @@ // quadratic.cpp: demonstration of catastrophic cancellation in the quadratic formula // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include #include -#if (__cplusplus == 202003L) || (_MSVC_LANG == 202003L) -#include // high-precision numbers -#endif +#include // high-precision constants /* Background on the poor numerical performance of the quadratic solution @@ -56,11 +55,11 @@ void CompareBigTerms(float a, float b, float c) { std::cout << " (b^2 - 4ac) : " << sw::universal::to_binary(difference) << " : " << difference << '\n'; { - Fixed64 a; - a = 100000.0f; - std::cout << "a : " << to_binary(a) << " : " << a << '\n'; - a *= a; - std::cout << "a^2 : " << to_binary(a) << " : " << a << '\n'; + Fixed64 v; + v = 100000.0f; + std::cout << "a : " << to_binary(v) << " : " << v << '\n'; + v *= v; + std::cout << "a^2 : " << to_binary(v) << " : " << v << '\n'; } } diff --git a/applications/precision/numeric/residual.cpp b/applications/precision/numeric/residual.cpp index b1ab86027..f568862fd 100644 --- a/applications/precision/numeric/residual.cpp +++ b/applications/precision/numeric/residual.cpp @@ -1,8 +1,10 @@ // residual.cpp: example program to show exact residual calucation using the quire // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include @@ -62,7 +64,7 @@ blas::vector> residual(const blas::matrix>& A, } template -void FrankMatrixTest(int N) { +void FrankMatrixTest(unsigned N) { using Vector = blas::vector; using Matrix = blas::matrix; Matrix A = sw::universal::blas::frank(N); @@ -78,7 +80,7 @@ void FrankMatrixTest(int N) { } void Experiment1() { - blas::vector sizes = { 5, 15, 45, 95 }; + blas::vector sizes = { 5, 15, 45, 95 }; for (auto N : sizes) { FrankMatrixTest(N); FrankMatrixTest>(N); @@ -87,23 +89,21 @@ void Experiment1() { template void ResidualTest(const Matrix& A) { - /* using namespace sw::universal; using namespace sw::universal::blas; - using Scalar = posit; + using Scalar = Matrix::value_type; using Vector = sw::universal::blas::vector; - using Matrix = matrix; size_t M = num_rows(A); size_t N = num_cols(A); if (M != N) { - cerr << "Matrix should be square, but is (" << M << " by " << N << ")\n"; + std::cerr << "Matrix should be square, but is (" << M << " by " << N << ")\n"; return; } - cout << "Matrix order " << N << endl; - cout << setw(14) << A << endl; - cout << hex_format(A) << endl; + std::cout << "Matrix order " << N << '\n'; + std::cout << A << '\n'; + Vector b(N), ones(N), x(N); ones = Scalar(1); b = A * ones; // <-- posit specialized FDP matrix-vector multiply @@ -111,67 +111,62 @@ void ResidualTest(const Matrix& A) { Matrix LU(A); // the LU decomposition is in place, so create a copy first auto error = ludcmp(LU, indx); if (error != 0) { - cerr << "LU decomposition failed\n"; + std::cerr << "LU decomposition failed\n"; } - cout << "LU decomposition\n"; - cout << hex_format(LU) << endl; + std::cout << "LU decomposition\n"; + std::cout << (LU) << '\n'; x = lubksb(LU, indx, b); - cout << "right hand side : [ " << hex_format(b) << "]\n"; - cout << "right hand side : [ " << (b) << "]\n"; - cout << "solution vector x : [ " << hex_format(x) << "]\n"; - cout << "solution vector x : [ " << (x) << "]\n"; + std::cout << "right hand side : " << (b) << '\n'; + std::cout << "solution vector x : " << (x) << '\n'; Vector e = A * x - b; Vector r = residual(A, x, b); - cout << "Residual (non-quire) : [ " << hex_format(e) << "]\n"; - cout << "Residual (non-quire) : [ " << (e) << "]\n"; - cout << "Residual (quire) : [ " << hex_format(r) << "]\n"; - cout << "Residual (quire) value : [ " << setw(14) << r << "]\n"; - cout << '\n'; + std::cout << "Residual (non-quire) : " << (e) << '\n'; + std::cout << "Residual (quire) value : " << (r) << '\n'; + std::cout << '\n'; Vector minposRef(N); Scalar mp; minpos<32, 2>(mp); minposRef = mp; - cout << "Minpos reference : [ " << hex_format(minposRef) << "]\n\n"; + std::cout << "Minpos reference : " << (minposRef) << '\n'; // solve for the residual Vector c = lubksb(LU, indx, r); - cout << "right hand side : [ " << hex_format(r) << "]\n"; - cout << "right hand side : [ " << (r) << "]\n"; - cout << "solution vector c : [ " << hex_format(c) << "]\n"; + std::cout << "right hand side : " << (r) << '\n'; + std::cout << "solution vector c : " << (c) << '\n'; e = A * c - r; r = residual(A, c, r); - cout << "Residual (non-quire) : [ " << hex_format(e) << "]\n"; - cout << "Residual (non-quire) : [ " << (e) << "]\n"; - cout << "Residual (quire) : [ " << hex_format(r) << "]\n"; - cout << "Residual (quire) value : [ " << setw(14) << r << "]\n"; - cout << '\n'; - - cout << "Result x' = x - c\n"; - cout << "Solution vector x' : [ " << hex_format(x - c) << "]\n"; - cout << "Solution vector x' : [ " << (x - c) << "]\n"; - cout << "Exact solution vector : [ " << hex_format(ones) << "]\n"; - cout << '\n'; - - cout << "1-norm x' - ones : " << norm1(x - c - ones) << '\n'; - */ + std::cout << "Residual (non-quire) : " << (e) << '\n'; + std::cout << "Residual (quire) value : " << (r) << '\n'; + std::cout << '\n'; + + std::cout << "Result x' = x - c\n"; + std::cout << "Solution vector x' : " << (x - c) << '\n'; + std::cout << "Exact solution vector : " << (ones) << '\n';; + std::cout << '\n'; + + std::cout << "1-norm x' - ones : " << normL1(x - c - ones) << '\n'; } void Experiment2() { - constexpr unsigned nbits = 32; - constexpr unsigned es = 2; - using Scalar = posit; - using Matrix = blas::matrix; constexpr unsigned N = 5; - Matrix A = blas::frank(N); - std::cout << "Frank matrix\n"; - ResidualTest(A); - std::cout << '\n'; + { + constexpr unsigned nbits = 32; + constexpr unsigned es = 2; + using Scalar = posit; + using Matrix = blas::matrix; - std::cout << "Hilbert matrix\n"; - A = sw::universal::blas::hilbert(N); - ResidualTest(A); + Matrix A = blas::frank(N); + + std::cout << "Frank matrix\n"; + ResidualTest(A); + std::cout << '\n'; + + std::cout << "Hilbert matrix\n"; + A = sw::universal::blas::hilbert(N); + ResidualTest(A); + } { // reference float version @@ -247,7 +242,6 @@ void QuireCompensation(const blas::matrix>& A, const posit(MATRIX_ROWS); IeeeReference(MATRIX_ROWS); + ResidualTest(A); + std::cout << std::setprecision(precision); std::cout << std::endl; diff --git a/applications/precision/numeric/rump_equation.cpp b/applications/precision/numeric/rump_equation.cpp index 02f83403d..fda7d4662 100644 --- a/applications/precision/numeric/rump_equation.cpp +++ b/applications/precision/numeric/rump_equation.cpp @@ -1,8 +1,10 @@ // rump_equation.cpp: example program to show Rump computation requiring high-precision floats to work // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include // nextafter diff --git a/applications/precision/numeric/solvetest.cpp b/applications/precision/numeric/solvetest.cpp index e293a4619..5563b59aa 100644 --- a/applications/precision/numeric/solvetest.cpp +++ b/applications/precision/numeric/solvetest.cpp @@ -2,14 +2,17 @@ * Solve System of Equation Tests * * @author: James Quinlan - * @date: 2022-12-13 - * @copyright: Copyright (c) 2022 Stillwater Supercomputing, Inc. - * @license: MIT Open Source license +* @date: 2022-12-13 +* @copyright: Copyright (c) 2017 Stillwater Supercomputing, Inc. +* @license: MIT Open Source license +* +* SPDX-License-Identifier: MIT * * This file is part of the Universal Number Library project. * ************************************************************************* */ // Build Directory = universal/build/applications/numeric +#include // #define POSIT_VERBOSE_OUTPUT #define POSIT_TRACE_MUL @@ -70,7 +73,7 @@ sw::universal::blas::matrix submat(sw::universal::blas::matrix &A, } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/numeric/traits.cpp b/applications/precision/numeric/traits.cpp index 4614cee87..0fc59a523 100644 --- a/applications/precision/numeric/traits.cpp +++ b/applications/precision/numeric/traits.cpp @@ -1,8 +1,10 @@ // traits.cpp example program comparing number trait of different number systems // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include // select the number systems we would like to compare @@ -18,7 +20,7 @@ //constexpr long double e = 2.71828182845904523536; //constexpr long double log_2e = 1.44269504088896340736; -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/precision/numeric/ulp_math.cpp b/applications/precision/numeric/ulp_math.cpp index ee0ffa43c..de152198f 100644 --- a/applications/precision/numeric/ulp_math.cpp +++ b/applications/precision/numeric/ulp_math.cpp @@ -1,8 +1,10 @@ // ulp_math.cpp: example program to show operations on Unit in Last Position // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include #include #include #include // nextafter @@ -57,7 +59,7 @@ void smallest_value() { std::cout << "first representable value less than zero : " << nexttoward(Scalar(0.0), -1.0L) << '\n'; } -int main(int argc, char** argv) +int main() try { using namespace sw::universal; diff --git a/applications/reproducibility/blas/hilbert.cpp b/applications/reproducibility/blas/hilbert.cpp index fe8f7ff37..75ba8f50a 100644 --- a/applications/reproducibility/blas/hilbert.cpp +++ b/applications/reproducibility/blas/hilbert.cpp @@ -1,6 +1,7 @@ // hilbert.cpp: Hilbert matrix // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifdef _MSC_VER diff --git a/applications/reproducibility/blas/inverse.cpp b/applications/reproducibility/blas/inverse.cpp index 2494fb7d5..fbf15873a 100644 --- a/applications/reproducibility/blas/inverse.cpp +++ b/applications/reproducibility/blas/inverse.cpp @@ -1,6 +1,7 @@ // inverse.cpp: example program comparing float vs posit using Gauss-Jordan algorithm // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the HPRBLAS project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/blas/l1_fused_dot.cpp b/applications/reproducibility/blas/l1_fused_dot.cpp index c5facb872..123048d26 100644 --- a/applications/reproducibility/blas/l1_fused_dot.cpp +++ b/applications/reproducibility/blas/l1_fused_dot.cpp @@ -1,6 +1,7 @@ // l1_fused_dot.cpp: example program showing a fused-dot product for error free linear algebra // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifdef _MSC_VER diff --git a/applications/reproducibility/blas/l2_fused_mv.cpp b/applications/reproducibility/blas/l2_fused_mv.cpp index 1e263fecd..3d7959410 100644 --- a/applications/reproducibility/blas/l2_fused_mv.cpp +++ b/applications/reproducibility/blas/l2_fused_mv.cpp @@ -1,6 +1,7 @@ // l2_fused_mv.cpp: example program showing a fused matrix-vector product // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifdef _MSC_VER diff --git a/applications/reproducibility/blas/l3_fused_mm.cpp b/applications/reproducibility/blas/l3_fused_mm.cpp index 96abdbafd..ba54a0703 100644 --- a/applications/reproducibility/blas/l3_fused_mm.cpp +++ b/applications/reproducibility/blas/l3_fused_mm.cpp @@ -1,6 +1,7 @@ // l3_fused_mm.cpp: example program showing a fused matrix-matrix product // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/blas/lu.cpp b/applications/reproducibility/blas/lu.cpp index 53704afde..65993a5c6 100644 --- a/applications/reproducibility/blas/lu.cpp +++ b/applications/reproducibility/blas/lu.cpp @@ -204,7 +204,7 @@ void FrankMatrix() { } template -void MagicSquareTest(int N) { +void MagicSquareTest(unsigned N) { using std::abs; using namespace sw::universal::blas; using Vector = sw::universal::blas::vector; diff --git a/applications/reproducibility/blas/norms.cpp b/applications/reproducibility/blas/norms.cpp index 2a369bbb5..d23cead67 100644 --- a/applications/reproducibility/blas/norms.cpp +++ b/applications/reproducibility/blas/norms.cpp @@ -1,6 +1,7 @@ // norms.cpp: example program showing different norms that use the quire for reproducible linear algebra // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifdef _MSC_VER diff --git a/applications/reproducibility/blas/randsvd.cpp b/applications/reproducibility/blas/randsvd.cpp index 694dbe0e4..cfe304d54 100644 --- a/applications/reproducibility/blas/randsvd.cpp +++ b/applications/reproducibility/blas/randsvd.cpp @@ -1,6 +1,7 @@ // randsvd.cpp: Randsvd matrix // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/cryptography/fermat.cpp b/applications/reproducibility/cryptography/fermat.cpp index 506d6f539..aa32cfda0 100644 --- a/applications/reproducibility/cryptography/fermat.cpp +++ b/applications/reproducibility/cryptography/fermat.cpp @@ -1,6 +1,7 @@ // fermat.cpp: factor numbers using Fermat's basic factorization algorithm, a^2 - b^2 = N // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/cryptography/large_lcm.cpp b/applications/reproducibility/cryptography/large_lcm.cpp index ff4a354ae..2726e3319 100644 --- a/applications/reproducibility/cryptography/large_lcm.cpp +++ b/applications/reproducibility/cryptography/large_lcm.cpp @@ -1,6 +1,7 @@ // large_lcm.cpp: calculating a least common multiple of a very large set // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/cryptography/pollard_rho.cpp b/applications/reproducibility/cryptography/pollard_rho.cpp index 9b82e5567..5042820ff 100644 --- a/applications/reproducibility/cryptography/pollard_rho.cpp +++ b/applications/reproducibility/cryptography/pollard_rho.cpp @@ -1,6 +1,7 @@ // pollard_rho.cpp: factor numbers using Pollard-Rho factorization // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/cryptography/quadratic_sieve.cpp b/applications/reproducibility/cryptography/quadratic_sieve.cpp index 6476fa160..8e553ec41 100644 --- a/applications/reproducibility/cryptography/quadratic_sieve.cpp +++ b/applications/reproducibility/cryptography/quadratic_sieve.cpp @@ -1,6 +1,7 @@ // quadratic_sieve.cpp: factor numbers using quadratic sieve // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/sequences/fibonacci.cpp b/applications/reproducibility/sequences/fibonacci.cpp index 0fd2ee7a0..ae88be8dd 100644 --- a/applications/reproducibility/sequences/fibonacci.cpp +++ b/applications/reproducibility/sequences/fibonacci.cpp @@ -1,6 +1,7 @@ // fibonacci.cpp: experiments with representing Fibonacci sequences // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/applications/reproducibility/sequences/tribonacci.cpp b/applications/reproducibility/sequences/tribonacci.cpp index 437ebd645..41a06c866 100644 --- a/applications/reproducibility/sequences/tribonacci.cpp +++ b/applications/reproducibility/sequences/tribonacci.cpp @@ -1,6 +1,6 @@ // fibonacci.cpp: experiments with representing Fibonacci sequences // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. // SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/applications/stl/common.hpp b/applications/stl/common.hpp deleted file mode 100644 index af981d4f2..000000000 --- a/applications/stl/common.hpp +++ /dev/null @@ -1,51 +0,0 @@ -// common.hpp : include file for standard system include files -#pragma once -#ifdef _MSC_VER -#pragma warning(disable : 4514) // warning C4514: 'std::complex::complex': unreferenced inline function has been removed -#pragma warning(disable : 4571) // warning C4571: Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught -#pragma warning(disable : 4625) // warning C4625: 'std::moneypunct': copy constructor was implicitly defined as deleted -#pragma warning(disable : 4626) // warning C4626: 'std::codecvt_base': assignment operator was implicitly defined as deleted -#pragma warning(disable : 4710) // warning C4710: 'int swprintf_s(wchar_t *const ,const size_t,const wchar_t *const ,...)': function not inlined -#pragma warning(disable : 4774) // warning C4774: 'sprintf_s' : format string expected in argument 3 is not a string literal -#pragma warning(disable : 4820) // warning C4820: 'std::_Mpunct<_Elem>': '4' bytes padding added after data member 'std::_Mpunct<_Elem>::_Kseparator' -#pragma warning(disable : 5026) // warning C5026 : 'std::_Generic_error_category' : move constructor was implicitly defined as deleted -#pragma warning(disable : 5027) // warning C5027 : 'std::_Generic_error_category' : move assignment operator was implicitly defined as deleted -#endif - -// enable the mathematical constants in cmath -#define USE_MATH_DEFINES - -#include // uint8_t, etc. -#include // for frexp/frexpf -#include // for DBL_EPSILON, etc. -// containers -#include -#include -#include -#include -#include -// I/O -#include -#include -#include -// algorithms -#include -#include -#include - -#ifdef _WINDOWS -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include -#endif // _WINDOWS - -#if defined(__GNUC__) -#if __GNUC__ < 5 -#define hexfloat scientific -#define defaultfloat scientific -#endif -#endif - diff --git a/applications/stl/sequential_containers.cpp b/applications/stl/sequential_containers.cpp index 1419a1a09..32b58f34d 100644 --- a/applications/stl/sequential_containers.cpp +++ b/applications/stl/sequential_containers.cpp @@ -1,7 +1,25 @@ // sequential_containers.cpp: Using STL containers and algorithms with posits -#include "common.hpp" -// configure the number system -// simply use defaults +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +// I/O +#include +#include +#include +// algorithms +#include +#include +#include +// containers +#include +#include +#include +#include +#include +// desired number systems to use #include // generic template function for all integer types diff --git a/benchmark/performance/arithmetic/native/performance.cpp b/benchmark/performance/arithmetic/native/performance.cpp index 055dee131..b81ba19b0 100644 --- a/benchmark/performance/arithmetic/native/performance.cpp +++ b/benchmark/performance/arithmetic/native/performance.cpp @@ -1,6 +1,7 @@ // performance.cpp : performance benchmarking for native floating-point // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/c_api/shim/posit/posit_c_api.cpp b/c_api/shim/posit/posit_c_api.cpp index d810b2c2b..acac271b3 100644 --- a/c_api/shim/posit/posit_c_api.cpp +++ b/c_api/shim/posit/posit_c_api.cpp @@ -1,6 +1,7 @@ // posit_c_api.cpp: implementation of the posit API for C programs // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/docker/Dockerfile.clang11builder b/docker/Dockerfile.clang11builder index 06721617c..f5369b9b2 100644 --- a/docker/Dockerfile.clang11builder +++ b/docker/Dockerfile.clang11builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang12builder b/docker/Dockerfile.clang12builder index ae4bcd7a9..668bcb291 100644 --- a/docker/Dockerfile.clang12builder +++ b/docker/Dockerfile.clang12builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang13builder b/docker/Dockerfile.clang13builder index 69445abe4..a69316529 100644 --- a/docker/Dockerfile.clang13builder +++ b/docker/Dockerfile.clang13builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang14builder b/docker/Dockerfile.clang14builder index e278e6bae..e2e6bb044 100644 --- a/docker/Dockerfile.clang14builder +++ b/docker/Dockerfile.clang14builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang15builder b/docker/Dockerfile.clang15builder index ebdd755e9..58a8b45d3 100644 --- a/docker/Dockerfile.clang15builder +++ b/docker/Dockerfile.clang15builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang16builder b/docker/Dockerfile.clang16builder index 5568238bf..9e8d7943d 100644 --- a/docker/Dockerfile.clang16builder +++ b/docker/Dockerfile.clang16builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang17builder b/docker/Dockerfile.clang17builder index 856389a8a..f089c3327 100644 --- a/docker/Dockerfile.clang17builder +++ b/docker/Dockerfile.clang17builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.clang18builder b/docker/Dockerfile.clang18builder index 40f9290f6..2ba204efa 100644 --- a/docker/Dockerfile.clang18builder +++ b/docker/Dockerfile.clang18builder @@ -13,6 +13,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends -V \ build-essential \ curl \ vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.gcc10builder b/docker/Dockerfile.gcc10builder index bb8f5e930..f27f12aa4 100644 --- a/docker/Dockerfile.gcc10builder +++ b/docker/Dockerfile.gcc10builder @@ -12,6 +12,9 @@ LABEL maintainer="Theodore Omtzigt" RUN apt-get update && apt-get install -y --no-install-recommends -V \ apt-utils \ build-essential \ + curl \ + vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.gcc11builder b/docker/Dockerfile.gcc11builder index 0d518ee20..cd9e9ef74 100644 --- a/docker/Dockerfile.gcc11builder +++ b/docker/Dockerfile.gcc11builder @@ -11,6 +11,9 @@ LABEL maintainer="Theodore Omtzigt" RUN apt-get update && apt-get install -y --no-install-recommends -V \ apt-utils \ build-essential \ + curl \ + vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.gcc12builder b/docker/Dockerfile.gcc12builder index 518eca6eb..908f3890e 100644 --- a/docker/Dockerfile.gcc12builder +++ b/docker/Dockerfile.gcc12builder @@ -11,6 +11,9 @@ LABEL maintainer="Theodore Omtzigt" RUN apt-get update && apt-get install -y --no-install-recommends -V \ apt-utils \ build-essential \ + curl \ + vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.gcc13builder b/docker/Dockerfile.gcc13builder index be5921f7b..f2dffb64c 100644 --- a/docker/Dockerfile.gcc13builder +++ b/docker/Dockerfile.gcc13builder @@ -11,6 +11,9 @@ LABEL maintainer="Theodore Omtzigt" RUN apt-get update && apt-get install -y --no-install-recommends -V \ apt-utils \ build-essential \ + curl \ + vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/Dockerfile.gcc9builder b/docker/Dockerfile.gcc9builder index 14cfdc4cf..233934f1c 100644 --- a/docker/Dockerfile.gcc9builder +++ b/docker/Dockerfile.gcc9builder @@ -12,6 +12,9 @@ LABEL maintainer="Theodore Omtzigt" RUN apt-get update && apt-get install -y --no-install-recommends -V \ apt-utils \ build-essential \ + curl \ + vim \ + gdb \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* diff --git a/docker/build_release_container.sh b/docker/build_release_container.sh index ae9714f65..b0a586c4e 100755 --- a/docker/build_release_container.sh +++ b/docker/build_release_container.sh @@ -5,7 +5,7 @@ # example would be to strace an executable to find its dependencies MAJOR=v3 -MINOR=77 +MINOR=78 VERSION="$MAJOR.$MINOR" if [[ $# == 0 ]]; then diff --git a/docker/build_test_container.sh b/docker/build_test_container.sh index 1d07e5e8a..c83f2bb3a 100755 --- a/docker/build_test_container.sh +++ b/docker/build_test_container.sh @@ -11,7 +11,7 @@ # example would be to strace an executable to find its dependencies MAJOR=v3 -MINOR=77 +MINOR=78 VERSION="$MAJOR.$MINOR" if [[ $# == 0 ]]; then diff --git a/elastic/efloat/add.cpp b/elastic/efloat/add.cpp index 08a14b955..bfafcb5cc 100644 --- a/elastic/efloat/add.cpp +++ b/elastic/efloat/add.cpp @@ -1,6 +1,7 @@ // add.cpp: test runner for addition on adaptive precision binary floating-point // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/api/api.cpp b/elastic/einteger/api/api.cpp index 6567e9b54..e01c5a4b7 100644 --- a/elastic/einteger/api/api.cpp +++ b/elastic/einteger/api/api.cpp @@ -1,6 +1,7 @@ // api.cpp: application programming interface tests for einteger // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/api/exceptions.cpp b/elastic/einteger/api/exceptions.cpp index 861bc1016..ec54c8f22 100644 --- a/elastic/einteger/api/exceptions.cpp +++ b/elastic/einteger/api/exceptions.cpp @@ -1,6 +1,7 @@ // exceptions.cpp: test suite runner for exceptions on adaptive precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/arithmetic/addition.cpp b/elastic/einteger/arithmetic/addition.cpp index 109cdda54..dcfaf68b7 100644 --- a/elastic/einteger/arithmetic/addition.cpp +++ b/elastic/einteger/arithmetic/addition.cpp @@ -1,6 +1,7 @@ -// addition.cpp: test suite runner for addition on elastic precision binary integers +// addition.cpp: test suite runner for addition of elastic precision binary integers // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/arithmetic/division.cpp b/elastic/einteger/arithmetic/division.cpp index 793f1cb6d..efdd1f2fe 100644 --- a/elastic/einteger/arithmetic/division.cpp +++ b/elastic/einteger/arithmetic/division.cpp @@ -1,6 +1,7 @@ -// division.cpp: test suite runner for division on elastic precision binary integers +// division.cpp: test suite runner for division of elastic precision binary integers // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/arithmetic/multiplication.cpp b/elastic/einteger/arithmetic/multiplication.cpp index 952116245..06d541dc2 100644 --- a/elastic/einteger/arithmetic/multiplication.cpp +++ b/elastic/einteger/arithmetic/multiplication.cpp @@ -1,6 +1,7 @@ -// multiplication.cpp: test suite runner for multiplicationon elastic precision binary integers +// multiplication.cpp: test suite runner for multiplication of elastic precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/arithmetic/subtraction.cpp b/elastic/einteger/arithmetic/subtraction.cpp index 04a903389..754b9f41c 100644 --- a/elastic/einteger/arithmetic/subtraction.cpp +++ b/elastic/einteger/arithmetic/subtraction.cpp @@ -1,6 +1,7 @@ -// subtraction.cpp: test suite runner for subtractionon elastic precision binary integers +// subtraction.cpp: test suite runner for subtraction of elastic precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/conversion/assignment.cpp b/elastic/einteger/conversion/assignment.cpp index 35bc18293..3c48394e3 100644 --- a/elastic/einteger/conversion/assignment.cpp +++ b/elastic/einteger/conversion/assignment.cpp @@ -1,6 +1,7 @@ // assignment.cpp: test suite runner for assignment on adaptive precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/logic/comparison.cpp b/elastic/einteger/logic/comparison.cpp index 543f11bab..e16afa2af 100644 --- a/elastic/einteger/logic/comparison.cpp +++ b/elastic/einteger/logic/comparison.cpp @@ -1,6 +1,7 @@ // comparison.cpp: test suite runner for logic comparisons on adaptive precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/math/factorial.cpp b/elastic/einteger/math/factorial.cpp index 17a5fcef5..3e4e1f84b 100644 --- a/elastic/einteger/math/factorial.cpp +++ b/elastic/einteger/math/factorial.cpp @@ -1,6 +1,7 @@ // factorial.cpp: test suite runner for factorials on adaptive precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/einteger/performance/performance.cpp b/elastic/einteger/performance/performance.cpp index 18db5054a..feffcae63 100644 --- a/elastic/einteger/performance/performance.cpp +++ b/elastic/einteger/performance/performance.cpp @@ -1,6 +1,7 @@ // performance.cpp: test suite runner for measuring performance off adaptive precision binary integers // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/eposit/add.cpp b/elastic/eposit/add.cpp index 7701f6258..5c4cd0bfe 100644 --- a/elastic/eposit/add.cpp +++ b/elastic/eposit/add.cpp @@ -1,6 +1,7 @@ // add.cpp: functional tests for addition on adaptive precision tapered floating-point // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/unum/api.cpp b/elastic/unum/api.cpp index 2a695c661..bdc6339a3 100644 --- a/elastic/unum/api.cpp +++ b/elastic/unum/api.cpp @@ -1,6 +1,7 @@ // api.cpp: class interface tests for arbitrary configuration unum types // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/elastic/unum/construct.cpp b/elastic/unum/construct.cpp index a909a86bd..7a00567db 100644 --- a/elastic/unum/construct.cpp +++ b/elastic/unum/construct.cpp @@ -1,6 +1,7 @@ // construct.cpp: functional tests to construct arbitrary configuration unums // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/include/universal/blas/generators/magic.hpp b/include/universal/blas/generators/magic.hpp index 3bfdd3a7a..533fdd624 100644 --- a/include/universal/blas/generators/magic.hpp +++ b/include/universal/blas/generators/magic.hpp @@ -11,10 +11,10 @@ namespace sw { namespace universal { namespace blas { // fill a dense (N, N) matrix with linear index values in row order template -matrix magic(int N) { +matrix magic(unsigned N) { using Matrix = matrix; // precondition tests - if (N <= 0) return matrix{}; + if (N == 0) return matrix{}; if (N % 2 == 0) { std::cerr << "matrix size N is even, must be odd" << std::endl; return matrix{}; @@ -28,20 +28,22 @@ matrix magic(int N) { // 2- if number exists at new position, redo calculation as rowIndex+2, colIndex-2 // 3- if row is 1 and column is N, new position is (0, n-2) // - int i = N / 2; - int j = N - 1; + int n = static_cast(N); + int nsqr = n*n; + int i = n / 2; + int j = n - 1; // generate the indices - for (int e = 1; e <= N * N; /* increment in body */) { - if (i == -1 && j == N) { + for (int e = 1; e <= nsqr; /* increment in body */) { + if (i == -1 && j == n) { i = 0; - j = N - 2; + j = n - 2; } else { // first condition helper if next row index wraps around - if (i < 0) i = N - 1;; + if (i < 0) i = n - 1;; // first condition helper if next column index wraps around - if (j == N) j = 0; + if (j == n) j = 0; } if (A(i, j) > Scalar(0)) { // second condition ++i; j -= 2; diff --git a/include/universal/blas/solvers/lu.hpp b/include/universal/blas/solvers/lu.hpp index f9572e69f..07999ad8c 100644 --- a/include/universal/blas/solvers/lu.hpp +++ b/include/universal/blas/solvers/lu.hpp @@ -87,10 +87,10 @@ void Crout(const Matrix& S, Matrix& D) { template void SolveCrout(const Matrix& LU, const Vector& b, Vector& x) { assert(num_cols(LU) == size(b)); - size_t N = size(b); + unsigned N = size(b); using value_type = typename Matrix::value_type; sw::universal::blas::vector y(N); - for (size_t i = 0; i < N; ++i) { + for (unsigned i = 0; i < N; ++i) { value_type sum = 0.0; for (size_t k = 0; k < size_t(i); ++k) sum += LU[i][k] * y[k]; y[i] = (b[i] - sum) / LU[i][i]; @@ -98,7 +98,7 @@ void SolveCrout(const Matrix& LU, const Vector& b, Vector& x) { } for (int i = static_cast(N) - 1; i >= 0; --i) { value_type sum = 0.0; - for (int k = i + 1; k < static_cast(N); ++k) { + for (unsigned k = i + 1; k < N; ++k) { //cout << "lu[] = " << LU[i][k] << " x[" << k << "] = " << x[k] << endl; sum += LU[i][k] * x[k]; } diff --git a/include/universal/blas/squeeze.hpp b/include/universal/blas/squeeze.hpp index 4019b0e2b..1b8207e93 100644 --- a/include/universal/blas/squeeze.hpp +++ b/include/universal/blas/squeeze.hpp @@ -138,7 +138,7 @@ void ScaleAndRound(blas::matrix& Aw, blas::matrix #include #include #include - -// should be defined by calling environment, just catching it here just in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif #include namespace sw { namespace universal { diff --git a/include/universal/internal/blockdecimal/blockdecimal.hpp b/include/universal/internal/blockdecimal/blockdecimal.hpp index 0ee68cb9d..7da235f69 100644 --- a/include/universal/internal/blockdecimal/blockdecimal.hpp +++ b/include/universal/internal/blockdecimal/blockdecimal.hpp @@ -1,18 +1,13 @@ #pragma once // blockdecimal.hpp: parameterized blocked decimal number system representing a fixed-sized decimal integer number // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include #include #include - -// should be defined by calling environment, catching it here just in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif #include namespace sw { namespace universal { diff --git a/include/universal/internal/blockfraction/blockfraction.hpp b/include/universal/internal/blockfraction/blockfraction.hpp index 4abe65d7b..7585bb5af 100644 --- a/include/universal/internal/blockfraction/blockfraction.hpp +++ b/include/universal/internal/blockfraction/blockfraction.hpp @@ -1,7 +1,8 @@ #pragma once // blockfraction.hpp: parameterized blocked binary number system representing the bits of the floating-point fraction scaled for the different arithmetic operations {+,-,*,/} // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -12,12 +13,6 @@ #include -// should be defined by calling environment, just catching it here in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif - namespace sw { namespace universal { // structure for blockfraction to capture quotient and remainder during long division diff --git a/include/universal/internal/blocksignificant/blocksignificant.hpp b/include/universal/internal/blocksignificant/blocksignificant.hpp index 8bc65444f..1db373b7d 100644 --- a/include/universal/internal/blocksignificant/blocksignificant.hpp +++ b/include/universal/internal/blocksignificant/blocksignificant.hpp @@ -1,7 +1,8 @@ #pragma once // blocksignificant.hpp: parameterized blocked binary number system representing the bits of the floating-point significant scaled for the different arithmetic operations {+,-,*,/} // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -12,12 +13,6 @@ #include -// should be defined by calling environment, just catching it here in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif - /* The fraction bits in a floating-point representation benefit from different representations for different operators: @@ -180,9 +175,7 @@ class blocksignificant { #if LONG_DOUBLE_SUPPORT explicit constexpr operator long double() const noexcept { return (long double)to_long_double(); } - constexpr long double to_long_double() const noexcept { - return (long double)to_double(); - } + constexpr long double to_long_double() const noexcept { return (long double)to_double(); } #endif /// prefix operators diff --git a/include/universal/internal/blocktriple/blocktriple.hpp b/include/universal/internal/blocktriple/blocktriple.hpp index 186b29b03..771eeb87f 100644 --- a/include/universal/internal/blocktriple/blocktriple.hpp +++ b/include/universal/internal/blocktriple/blocktriple.hpp @@ -1,7 +1,8 @@ #pragma once // blocktriple.hpp: definition of a (sign, scale, significant) representation of a generic floating-point value that goes into an arithmetic operation // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -9,20 +10,6 @@ #include #include -// check on required compilation guards -// should be defined by calling environment, just catching it here just in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif -#if !defined(BIT_CAST_SUPPORT) -#pragma message("BIT_CAST_SUPPORT is not defined") -#define BIT_CAST_SUPPORT 0 -#endif -#if !defined(CONSTEXPRESSION) -#define CONSTEXPRESSION -#endif - // dependent types for stand-alone use of this class #include // to_binary(uint64_t) #include @@ -252,14 +239,14 @@ class blocktriple { } // explicit conversion operators - explicit operator float() const noexcept { return to_native(); } - explicit operator double() const noexcept { return to_native(); } + explicit operator float() const noexcept { return to_native(); } + explicit operator double() const noexcept { return to_native(); } // guard long double support to enable ARM and RISC-V embedded environments #if LONG_DOUBLE_SUPPORT - CONSTEXPRESSION blocktriple(long double iv) noexcept { *this = iv; } - CONSTEXPRESSION blocktriple& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } - explicit operator long double() const noexcept { return to_native(); } + explicit operator long double() const noexcept { return to_native(); } + BIT_CAST_CONSTEXPR blocktriple(long double iv) noexcept { *this = iv; } + BIT_CAST_CONSTEXPR blocktriple& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } #endif // logical bit shift operators @@ -720,7 +707,7 @@ class blocktriple { raw <<= shift; } else { -#if !BIT_CAST_SUPPORT +#if !BIT_CAST_IS_CONSTEXPR std::cerr << "round: shift " << shift << " is too large (>= 64)\n"; #endif } @@ -857,7 +844,9 @@ class blocktriple { } if (rawExponent == 0ull) { // value is a subnormal: TBD +#if ! BIT_CAST_IS_CONSTEXPR std::cerr << "subnormal value TBD\n"; +#endif } else { int exponent = static_cast(rawExponent) - ieee754_parameter::bias; // unbias the exponent diff --git a/include/universal/internal/f2s/f2s.hpp b/include/universal/internal/f2s/f2s.hpp index 079805ab9..acbffb10e 100644 --- a/include/universal/internal/f2s/f2s.hpp +++ b/include/universal/internal/f2s/f2s.hpp @@ -1,19 +1,14 @@ #pragma once // f2s.hpp: simplified floating-point to support generating fast decimal representations of floating-points // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include #include #include #include - -// should be defined by calling environment, catching it here just in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif #include namespace sw { diff --git a/include/universal/internal/gfp/gfp.hpp b/include/universal/internal/gfp/gfp.hpp index 39eed0dc9..636e3ac9e 100644 --- a/include/universal/internal/gfp/gfp.hpp +++ b/include/universal/internal/gfp/gfp.hpp @@ -1,7 +1,8 @@ #pragma once // gfp.hpp: simplified floating-point to support generating fast decimal representations of floating-points // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -9,11 +10,6 @@ #include #include -// should be defined by calling environment, catching it here just in case it is not -#ifndef LONG_DOUBLE_SUPPORT -#pragma message("LONG_DOUBLE_SUPPORT is not defined") -#define LONG_DOUBLE_SUPPORT 0 -#endif #include namespace sw { diff --git a/include/universal/internal/value/value b/include/universal/internal/value/value index 54dc7a704..c6311166f 100644 --- a/include/universal/internal/value/value +++ b/include/universal/internal/value/value @@ -1,7 +1,8 @@ #pragma once // value standard header // -// Copyright (C) 2017-2020 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifndef _VALUE_ diff --git a/include/universal/internal/value/value.hpp b/include/universal/internal/value/value.hpp index 8d4ae125d..cc632d197 100644 --- a/include/universal/internal/value/value.hpp +++ b/include/universal/internal/value/value.hpp @@ -1,7 +1,8 @@ #pragma once // value.hpp: definition of a (sign, scale, significant) representation of an approximation to a real value // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/native/attributes.hpp b/include/universal/native/attributes.hpp index 41ddca996..d33a91e7d 100644 --- a/include/universal/native/attributes.hpp +++ b/include/universal/native/attributes.hpp @@ -72,7 +72,7 @@ namespace sw { namespace universal { return ieee754_range(); } -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR #include // C++20 bit_cast inline bool is_subnormal(float value) { uint32_t bc = std::bit_cast(value); diff --git a/include/universal/native/error_free_ops.hpp b/include/universal/native/error_free_ops.hpp new file mode 100644 index 000000000..2202f5d26 --- /dev/null +++ b/include/universal/native/error_free_ops.hpp @@ -0,0 +1,332 @@ +#pragma once +// error_free_ops.hpp: definition of error free arithmetic functions for native floating-point types +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +/* +A key property of faithful floating-point arithmetic is that rounding error of an arithmetic operation +can be correctly represented by the arithmetic. + +We have the assertion that a + b = s + r + + */ + + /* If fused multiply-add is available, define to correct macro for + using it. It is invoked as QD_FMA(a, b, c) to compute fl(a * b + c). + If correctly rounded multiply-add is not available (or if unsure), + keep it undefined.*/ +#ifndef QD_FMA + /* #undef QD_FMA */ +#endif + +/* If fused multiply-subtract is available, define to correct macro for + using it. It is invoked as QD_FMS(a, b, c) to compute fl(a * b - c). + If correctly rounded multiply-add is not available (or if unsure), + keep it undefined.*/ +#ifndef QD_FMS + /* #undef QD_FMS */ +#endif + +namespace sw { namespace universal { + + // TwoSums + + /// + /// quick_two_sum computes the relationship a + b = s + r + /// requires its arguments to be |a| >= |b| + /// + /// input + /// input + /// reference to the residual + /// the sum s + inline double quick_two_sum(double a, double b, volatile double& r) { + volatile double s = a + b; + r = (std::isfinite(s) ? b - (s - a) : 0.0); + return s; + } + + /// + /// two_sum computes the relationship a + b = s + r + /// + /// input + /// input + /// reference to the residual + /// the sum s + inline double two_sum(double a, double b, volatile double& r) { + volatile double s = a + b; + if (std::isfinite(s)) { + volatile double bb = s - a; + r = (a - (s - bb)) + (b - bb); + } + else { + r = 0.0; + } + return s; + } + + + // TwoDiff + + /// + /// quick_two_diff computes the relationship a - b = s + r + /// notice the sign of s + r, this determines the sign of the residual + /// requires its arguments to be |a| >= |b| + /// + /// input + /// input + /// reference to the residual + /// the sum s + inline double quick_two_diff(double a, double b, volatile double& r) { + volatile double s = a - b; + r = (std::isfinite(s) ? (a - s) - b : 0.0); + return s; + } + + /// + /// two_diff computes the relationship a - b = s + r + /// notice the sign of s + r, this determines the sign of the residual + /// + /// + /// input + /// input + /// reference to the residual + /// the difference s + inline double two_diff(double a, double b, volatile double& r) { + volatile double s = a - b; + if (std::isfinite(s)) { + volatile double bb = s - a; + r = (a - (s - bb)) - (b + bb); + } + else { + r = 0.0; + } + return s; + } + + // ThreeSum + + /// + /// three_sum computes the relationship a + b + c = s + r + /// + /// input + /// input + /// input value, output residual + inline void three_sum(volatile double& a, volatile double& b, volatile double& c) { + volatile double t1, t2, t3; + + t1 = two_sum(a, b, t2); + a = two_sum(c, t1, t3); + b = two_sum(t2, t3, c); + } + + + // Split + +#if !defined( QD_FMS ) + /* Computes high word and lo word of a */ + inline void split(double a, volatile double& hi, volatile double& lo) { + int const QD_BITS = (std::numeric_limits< double >::digits + 1) / 2; + static double const QD_SPLITTER = std::ldexp(1.0, QD_BITS) + 1.0; + static double const QD_SPLIT_THRESHOLD = std::ldexp((std::numeric_limits< double >::max)(), -QD_BITS - 1); + + volatile double temp; + + if (std::abs(a) > QD_SPLIT_THRESHOLD) + { + a = std::ldexp(a, -QD_BITS - 1); + temp = QD_SPLITTER * a; + hi = temp - (temp - a); + lo = a - hi; + hi = std::ldexp(hi, QD_BITS + 1); + lo = std::ldexp(lo, QD_BITS + 1); + } + else + { + temp = QD_SPLITTER * a; + hi = temp - (temp - a); + lo = a - hi; + } + } +#endif + + // TwoProd + + /// + /// two_prod computes the relationship a * b = p + r + /// + /// input + /// input + /// reference to the residual + /// the product of a * b + inline double two_prod(double a, double b, volatile double& r) + { + volatile double p = a * b; + if (std::isfinite(p)) { +#if defined( QD_FMS ) + r = QD_FMS(a, b, p); +#else + double a_hi, a_lo, b_hi, b_lo; + split(a, a_hi, a_lo); + split(b, b_hi, b_lo); + r = ((a_hi * b_hi - p) + a_hi * b_lo + a_lo * b_hi) + a_lo * b_lo; +#endif + } + else + r = 0.0; + return p; + } + + /// + /// two_sqr computes the relationship a * a = square + r + /// two_sqr is faster than two_prod when calculating the square product + /// + /// input + /// reference to the residual + /// the square product of a + inline double two_sqr(double a, volatile double& r) { + volatile double p = a * a; + if (std::isfinite(p)) + { +#if defined( QD_FMS ) + err = QD_FMS(a, a, p); +#else + volatile double hi, lo; + split(a, hi, lo); + r = ((hi * hi - p) + 2.0 * hi * lo) + lo * lo; +#endif + } + else + r = 0.0; + return p; + } + + + /// + /// renorm adjusts the quad-double to a canonical form + /// A quad-double number is an unevaluated sum of four IEEE double numbers. + /// The quad-double (a0 a1 a2 a3) represents the exact sum a = a0 + a1 + a2 + a3. + /// Note that for any given representable number x, there can be many representations + /// as an unevaluated sum of four doubles. + /// Hence we require that the quadruple(a0 a1 a2 a3) to satisfy + /// | a_(i+1) | leq ulp(a_i) / 2 + /// for i =0, 1, 2, with equality only occuring when ai = 0, or the last bit of ai is 0 + /// Note that the first a0 is the double precision approximation of the quad-double number, + /// accurate to almost half an ulp. + /// + /// + /// + /// + /// + inline void renorm(volatile double& a0, volatile double& a1, volatile double& a2, volatile double& a3) { + volatile double s0, s1, s2 = 0.0, s3 = 0.0; + + if (std::isinf(a0)) return; + + s0 = quick_two_sum(a2, a3, a3); + s0 = quick_two_sum(a1, s0, a2); + a0 = quick_two_sum(a0, s0, a1); + + s0 = a0; + s1 = a1; + if (s1 != 0.0) { + s1 = quick_two_sum(s1, a2, s2); + if (s2 != 0.0) + s2 = quick_two_sum(s2, a3, s3); + else + s1 = quick_two_sum(s1, a3, s2); + } + else { + s0 = quick_two_sum(s0, a2, s1); + if (s1 != 0.0) + s1 = quick_two_sum(s1, a3, s2); + else + s0 = quick_two_sum(s0, a3, s1); + } + + a0 = s0; + a1 = s1; + a2 = s2; + a3 = s3; + } + + /// + /// renorm adjusts an intermediate five-element double to a quad-double in canonical form + /// A quad-double number is an unevaluated sum of four IEEE double numbers. + /// The quad-double (a0 a1 a2 a3) represents the exact sum a = a0 + a1 + a2 + a3. + /// Note that for any given representable number x, there can be many representations + /// as an unevaluated sum of four doubles. + /// Hence we require that the quadruple(a0 a1 a2 a3) to satisfy + /// | a_(i+1) | leq ulp(a_i) / 2 + /// for i =0, 1, 2, with equality only occuring when ai = 0, or the last bit of ai is 0 + /// Note that the first a0 is the double precision approximation of the quad-double number, + /// accurate to almost half an ulp. + /// + /// reference to a0 + /// reference to a1 + /// reference to a2 + /// reference to a3 + /// reference to a4 + inline void renorm(volatile double& a0, volatile double& a1, volatile double& a2, volatile double& a3, volatile double& a4) { + volatile double s0, s1, s2 = 0.0, s3 = 0.0; + + if (std::isinf(a0)) return; + + s0 = quick_two_sum(a3, a4, a4); + s0 = quick_two_sum(a2, s0, a3); + s0 = quick_two_sum(a1, s0, a2); + a0 = quick_two_sum(a0, s0, a1); + + s0 = a0; + s1 = a1; + + s0 = quick_two_sum(a0, a1, s1); + if (s1 != 0.0) { + s1 = quick_two_sum(s1, a2, s2); + if (s2 != 0.0) { + s2 = quick_two_sum(s2, a3, s3); + if (s3 != 0.0) + s3 += a4; + else + s2 += a4; + } + else { + s1 = quick_two_sum(s1, a3, s2); + if (s2 != 0.0) + s2 = quick_two_sum(s2, a4, s3); + else + s1 = quick_two_sum(s1, a4, s2); + } + } + else { + s0 = quick_two_sum(s0, a2, s1); + if (s1 != 0.0) { + s1 = quick_two_sum(s1, a3, s2); + if (s2 != 0.0) + s2 = quick_two_sum(s2, a4, s3); + else + s1 = quick_two_sum(s1, a4, s2); + } + else { + s0 = quick_two_sum(s0, a3, s1); + if (s1 != 0.0) + s1 = quick_two_sum(s1, a4, s2); + else + s0 = quick_two_sum(s0, a4, s1); + } + } + + a0 = s0; + a1 = s1; + a2 = s2; + a3 = s3; + } + + +}} // namespace sw::universal diff --git a/include/universal/native/extract_fields.hpp b/include/universal/native/extract_fields.hpp index 8fe0699ce..66348ae8f 100644 --- a/include/universal/native/extract_fields.hpp +++ b/include/universal/native/extract_fields.hpp @@ -5,14 +5,16 @@ // SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include namespace sw { namespace universal { -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR #include // C++20 bit_cast template - inline constexpr void extractFields(Real value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + inline BIT_CAST_CONSTEXPR void extractFields(Real value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { if (value == 0) { s = false; rawExponentBits = 0ull; @@ -23,7 +25,7 @@ namespace sw { namespace universal { // specialization to extract fields from a float template<> - inline constexpr void extractFields(float value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + inline BIT_CAST_CONSTEXPR void extractFields(float value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { uint32_t bc = std::bit_cast(value); s = (ieee754_parameter::smask & bc); rawExponentBits = (ieee754_parameter::emask & bc) >> ieee754_parameter::fbits; @@ -33,7 +35,7 @@ namespace sw { namespace universal { // specialization to extract fields from a double template<> - inline constexpr void extractFields(double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + inline BIT_CAST_CONSTEXPR void extractFields(double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { uint64_t bc = std::bit_cast(value); s = (ieee754_parameter::smask & bc); rawExponentBits = (ieee754_parameter::emask & bc) >> ieee754_parameter::fbits; @@ -43,24 +45,11 @@ namespace sw { namespace universal { #if LONG_DOUBLE_SUPPORT -//#pragma message("LONG_DOUBLE_SUPPORT is configured in extract_fields") +// Clang bit_cast<> can't deal with long double - // specialization to extract fields from a long double - template<> - inline constexpr void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { - uint64_t bc = std::bit_cast(value); - s = (ieee754_parameter::smask & bc); - rawExponentBits = (ieee754_parameter::emask & bc) >> ieee754_parameter::fbits; - rawFractionBits = (ieee754_parameter::fmask & bc); - } -#else - -//#pragma message("LONG_DOUBLE_SUPPORT is not configured in extract_fields") - -#define LONG_DOUBLE_DOWNCAST -#ifdef LONG_DOUBLE_DOWNCAST +#if defined(LONG_DOUBLE_DOWNCAST) template<> - inline constexpr void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + inline BIT_CAST_CONSTEXPR void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { double d = static_cast(value); uint64_t bc = std::bit_cast(d); s = (ieee754_parameter::smask & bc); @@ -68,11 +57,38 @@ namespace sw { namespace universal { rawFractionBits = (ieee754_parameter::fmask & bc); bits = bc; } +#else // !DOWNCAST +/* + ETLO 8/1/2024: not able to make std::bit_cast<> work for long double + // specialization to extract fields from a long double + template<> + inline BIT_CAST_CONSTEXPR void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + struct blob { + std::uint64_t hi; + std::uint64_t fraction; + } raw; + raw = std::bit_cast(value); + s = (ieee754_parameter::smask & raw.hi); + rawExponentBits = (ieee754_parameter::emask & raw.hi); + rawFractionBits = (ieee754_parameter::fmask & raw.fraction); + } + */ + // falling back to non-constexpr + // specialization to extract fields from a long double + inline void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + long_double_decoder decoder; + decoder.ld = value; + s = decoder.parts.sign ? true : false; + rawExponentBits = decoder.parts.exponent; + rawFractionBits = decoder.parts.fraction; + bits = decoder.bits[0]; // communicate the lower order bits which represent the fraction bits + } + #endif // LONG_DOUBLE_DOWNCAST #endif // LONG_DOUBLE_SUPPORT -#else // BIT_CAST_SUPPORT - +#else // !BIT_CAST_IS_CONSTEXPR + //////////////////////////////////////////////////////////////////////// // nonconst extractFields for single precision floating-point @@ -98,9 +114,13 @@ namespace sw { namespace universal { } #if LONG_DOUBLE_SUPPORT - -//#pragma message("LONG_DOUBLE_SUPPORT is configured in extract_fields") - +// Clang bit_cast<> can't deal with long double +#define LONG_DOUBLE_DOWNCAST +#ifdef LONG_DOUBLE_DOWNCAST + inline void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { + extractFields(double(value), s, rawExponentBits, rawFractionBits, bits); + } +#else // specialization to extract fields from a long double inline void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { long_double_decoder decoder; @@ -110,21 +130,134 @@ namespace sw { namespace universal { rawFractionBits = decoder.parts.fraction; bits = decoder.bits[0]; // communicate the lower order bits which represent the fraction bits } -#else +#endif // LONG_DOUBLE_DOWNCAST +#endif // LONG_DOUBLE_SUPPORT +#endif // BIT_CAST_IS_CONSTEXPR -//#pragma message("LONG_DOUBLE_SUPPORT is not configured in extract_fields") +template + inline BIT_CAST_CONSTEXPR bool checkNaN(Real value, int& nan_type) { + nan_type = NAN_TYPE_NEITHER; + return false; + } -#define LONG_DOUBLE_DOWNCAST -#ifdef LONG_DOUBLE_DOWNCAST - inline void extractFields(long double value, bool& s, uint64_t& rawExponentBits, uint64_t& rawFractionBits, uint64_t& bits) noexcept { - extractFields(double(value), s, rawExponentBits, rawFractionBits, bits); + template<> + inline BIT_CAST_CONSTEXPR bool checkNaN(float value, int& nan_type) { + bool bIsNaN{ false }; + bool s{ false }; + uint64_t rawExponent{ 0 }; + uint64_t rawFraction{ 0 }; + uint64_t bits{ 0 }; + extractFields(value, s, rawExponent, rawFraction, bits); + if (rawExponent == ieee754_parameter::eallset) { // nan and inf need to be remapped + if (rawFraction == (ieee754_parameter::fmask & ieee754_parameter::snanmask) || + rawFraction == (ieee754_parameter::fmask & (ieee754_parameter::qnanmask | ieee754_parameter::snanmask))) { + // 1.11111111.00000000.......00000001 signalling nan + // 0.11111111.00000000000000000000001 signalling nan + // MSVC + // 1.11111111.10000000.......00000001 signalling nan + // 0.11111111.10000000.......00000001 signalling nan + nan_type = NAN_TYPE_SIGNALLING; + bIsNaN = true; + } + else if (rawFraction == (ieee754_parameter::fmask & ieee754_parameter::qnanmask)) { + // 1.11111111.10000000.......00000000 quiet nan + // 0.11111111.10000000.......00000000 quiet nan + nan_type = NAN_TYPE_QUIET; + bIsNaN = true; + } + else { + nan_type = NAN_TYPE_NEITHER; + bIsNaN = false; + } + } + return bIsNaN; } -#endif // LONG_DOUBLE_DOWNCAST -#endif // LONG_DOUBLE_SUPPORT + template<> + inline BIT_CAST_CONSTEXPR bool checkNaN(double value, int& nan_type) { + bool bIsNaN{ false }; + bool s{ false }; + uint64_t rawExponent{ 0 }; + uint64_t rawFraction{ 0 }; + uint64_t bits{ 0 }; + extractFields(value, s, rawExponent, rawFraction, bits); + if (rawExponent == ieee754_parameter::eallset) { // nan and inf need to be remapped + if (rawFraction == (ieee754_parameter::fmask & ieee754_parameter::snanmask) || + rawFraction == (ieee754_parameter::fmask & (ieee754_parameter::qnanmask | ieee754_parameter::snanmask))) { + // 1.11111111.00000000.......00000001 signalling nan + // 0.11111111.00000000000000000000001 signalling nan + // MSVC + // 1.11111111.10000000.......00000001 signalling nan + // 0.11111111.10000000.......00000001 signalling nan + nan_type = NAN_TYPE_SIGNALLING; + bIsNaN = true; + } + else if (rawFraction == (ieee754_parameter::fmask & ieee754_parameter::qnanmask)) { + // 1.11111111.10000000.......00000000 quiet nan + // 0.11111111.10000000.......00000000 quiet nan + nan_type = NAN_TYPE_QUIET; + bIsNaN = true; + } + else { + nan_type = NAN_TYPE_NEITHER; + bIsNaN = false; + } + } + return bIsNaN; + } -#endif // BIT_CAST_SUPPORT + template + inline BIT_CAST_CONSTEXPR bool checkInf(Real value, int& inf_type) { + inf_type = INF_TYPE_NEITHER; + return false; + } + template<> + inline BIT_CAST_CONSTEXPR bool checkInf(float value, int& inf_type) { + bool bIsInf{ false }; + bool s{ false }; + uint64_t rawExponent{ 0 }; + uint64_t rawFraction{ 0 }; + uint64_t bits{ 0 }; + extractFields(value, s, rawExponent, rawFraction, bits); + if (rawExponent == ieee754_parameter::eallset) { // nan and inf need to be remapped + if (rawFraction == 0ull) { + // 1.11111111.0000000.......000000000 -inf + // 0.11111111.0000000.......000000000 +inf + inf_type = (s ? INF_TYPE_NEGATIVE : INF_TYPE_POSITIVE); + bIsInf = true; + } + else { + inf_type = INF_TYPE_NEITHER; + bIsInf = false; + } + } + return bIsInf; + } + + template<> + inline BIT_CAST_CONSTEXPR bool checkInf(double value, int& inf_type) { + bool bIsInf{ false }; + bool s{ false }; + uint64_t rawExponent{ 0 }; + uint64_t rawFraction{ 0 }; + uint64_t bits{ 0 }; + extractFields(value, s, rawExponent, rawFraction, bits); + if (rawExponent == ieee754_parameter::eallset) { // nan and inf need to be remapped + if (rawFraction == 0ull) { + // 1.11111111.0000000.......000000000 -inf + // 0.11111111.0000000.......000000000 +inf + inf_type = (s ? INF_TYPE_NEGATIVE : INF_TYPE_POSITIVE); + bIsInf = true; + } + else { + inf_type = INF_TYPE_NEITHER; + bIsInf = false; + } + } + return bIsInf; + } + inline void setFields(float& value, bool s, uint64_t rawExponentBits, uint64_t rawFractionBits) noexcept { float_decoder decoder; decoder.parts.sign = s; diff --git a/include/universal/native/ieee754.hpp b/include/universal/native/ieee754.hpp index 614d693e7..d6b8de1be 100644 --- a/include/universal/native/ieee754.hpp +++ b/include/universal/native/ieee754.hpp @@ -51,3 +51,6 @@ // numeric helpers #include + +// error-free operations +#include diff --git a/include/universal/native/integers.hpp b/include/universal/native/integers.hpp index eb68fefc1..fecabe858 100644 --- a/include/universal/native/integers.hpp +++ b/include/universal/native/integers.hpp @@ -146,7 +146,7 @@ inline int64_t fastipow(int64_t base, uint8_t exp) { template::value, Integer >::type > -inline std::string to_binary(const Integer& number, int nbits = 0, bool bNibbleMarker = true) { +inline std::string to_binary(const Integer& number, bool bNibbleMarker = true, int nbits = 0) { std::stringstream s; if (nbits == 0) nbits = 8*sizeof(number); s << "0b"; diff --git a/include/universal/native/manipulators.hpp b/include/universal/native/manipulators.hpp index 679239104..22be964bc 100644 --- a/include/universal/native/manipulators.hpp +++ b/include/universal/native/manipulators.hpp @@ -26,7 +26,7 @@ namespace sw { namespace universal { // internal function to extract exponent template - int _extractExponent(Real v) { + constexpr int _extractExponent(Real v) { static_assert(sizeof(Real) == sizeof(Uint), "mismatched sizes"); Uint raw{ BitCast(v) }; raw &= static_cast(~ieee754_parameter::smask); diff --git a/include/universal/number/areal/areal.hpp b/include/universal/number/areal/areal.hpp index a06ee347e..603e1fffb 100644 --- a/include/universal/number/areal/areal.hpp +++ b/include/universal/number/areal/areal.hpp @@ -1,6 +1,7 @@ // : arbitrary real arithmetic type standard header // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifndef _AREAL_STANDARD_HEADER_ diff --git a/include/universal/number/areal/areal_impl.hpp b/include/universal/number/areal/areal_impl.hpp index 8210f430c..086c278fe 100644 --- a/include/universal/number/areal/areal_impl.hpp +++ b/include/universal/number/areal/areal_impl.hpp @@ -1,7 +1,8 @@ #pragma once // areal_impl.hpp: implementation of an arbitrary configuration fixed-size floating-point representation with an uncertainty bit to represent a faithful floating-point system // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -17,49 +18,6 @@ #include #include -// compiler specific operators -#if defined(__clang__) -/* Clang/LLVM. ---------------------------------------------- */ -#define BIT_CAST_SUPPORT 0 -#define CONSTEXPRESSION - -#elif defined(__ICC) || defined(__INTEL_COMPILER) -/* Intel ICC/ICPC. ------------------------------------------ */ - -#elif defined(__GNUC__) || defined(__GNUG__) -/* GNU GCC/G++. --------------------------------------------- */ -#define BIT_CAST_SUPPORT 0 -#define CONSTEXPRESSION - -#elif defined(__HP_cc) || defined(__HP_aCC) -/* Hewlett-Packard C/aC++. ---------------------------------- */ - -#elif defined(__IBMC__) || defined(__IBMCPP__) -/* IBM XL C/C++. -------------------------------------------- */ - -#elif defined(_MSC_VER) -/* Microsoft Visual Studio. --------------------------------- */ -//#pragma warning(disable : 4310) // cast truncates constant value - -// TODO: does this collide with the definitions in blocktriple? -#ifndef BIT_CAST_SUPPORT -#define BIT_CAST_SUPPORT 1 -#define CONSTEXPRESSION constexpr -#include -#else -#ifndef CONSTEXPRESSION -#define CONSTEXPRESSION -#endif -#endif - -#elif defined(__PGI) -/* Portland Group PGCC/PGCPP. ------------------------------- */ - -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) -/* Oracle Solaris Studio. ----------------------------------- */ - -#endif - #ifndef THROW_ARITHMETIC_EXCEPTION #define THROW_ARITHMETIC_EXCEPTION 0 #endif @@ -280,19 +238,19 @@ class areal { CONSTEXPRESSION areal& operator=(float rhs) { clear(); -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR // normal number uint32_t bc = std::bit_cast(rhs); bool s = (0x8000'0000u & bc); uint32_t raw_exp = uint32_t((0x7F80'0000u & bc) >> 23u); uint32_t raw = (0x007F'FFFFu & bc); -#else // !BIT_CAST_SUPPORT +#else // !BIT_CAST_IS_CONSTEXPR float_decoder decoder; decoder.f = rhs; bool s = decoder.parts.sign ? true : false; uint32_t raw_exp = decoder.parts.exponent; uint32_t raw = decoder.parts.fraction; -#endif // !BIT_CAST_SUPPORT +#endif // !BIT_CAST_IS_CONSTEXPR // special case handling if (raw_exp == 0xFFu) { // special cases @@ -441,19 +399,19 @@ class areal { } CONSTEXPRESSION areal& operator=(double rhs) { clear(); -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR // normal number uint64_t bc = std::bit_cast(rhs); bool s = (0x8000'0000'0000'0000ull & bc); uint32_t raw_exp = static_cast((0x7FF0'0000'0000'0000ull & bc) >> 52); uint64_t raw = (0x000F'FFFF'FFFF'FFFFull & bc); -#else // !BIT_CAST_SUPPORT +#else // !BIT_CAST_IS_CONSTEXPR double_decoder decoder; decoder.d = rhs; bool s = decoder.parts.sign ? true : false; uint32_t raw_exp = static_cast(decoder.parts.exponent); uint64_t raw = decoder.parts.fraction; -#endif // !BIT_CAST_SUPPORT +#endif // BIT_CAST_IS_CONSTEXPR if (raw_exp == 0x7FFul) { // special cases if (raw == 1ull) { // 1.11111111111.0000000000000000000000000000000000000000000000000001 signalling nan diff --git a/include/universal/number/areal/exceptions.hpp b/include/universal/number/areal/exceptions.hpp index fde9f17d4..bf19bc353 100644 --- a/include/universal/number/areal/exceptions.hpp +++ b/include/universal/number/areal/exceptions.hpp @@ -1,7 +1,8 @@ #pragma once // exceptions.hpp: definition of arbitrary configuration areal exceptions // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/areal/manipulators.hpp b/include/universal/number/areal/manipulators.hpp index df333a072..d9a9d420d 100644 --- a/include/universal/number/areal/manipulators.hpp +++ b/include/universal/number/areal/manipulators.hpp @@ -1,7 +1,8 @@ #pragma once // manipulators.hpp: definitions of helper functions for areal type manipulation // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/areal/math_functions.hpp b/include/universal/number/areal/math_functions.hpp index a2e8cf0d1..19ea741f7 100644 --- a/include/universal/number/areal/math_functions.hpp +++ b/include/universal/number/areal/math_functions.hpp @@ -1,7 +1,8 @@ #pragma once // math_functions.hpp: definition of arbitrary real mathematical functions // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/include/universal/number/areal/numeric_limits.hpp b/include/universal/number/areal/numeric_limits.hpp index 6418d180e..12f2f6f6f 100644 --- a/include/universal/number/areal/numeric_limits.hpp +++ b/include/universal/number/areal/numeric_limits.hpp @@ -1,7 +1,8 @@ #pragma once // numeric_limits.hpp: definition of numeric_limits for arbitrary real types // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/areal/table.hpp b/include/universal/number/areal/table.hpp index 5139d2e12..b623ade5d 100644 --- a/include/universal/number/areal/table.hpp +++ b/include/universal/number/areal/table.hpp @@ -1,7 +1,8 @@ #pragma once // table.hpp: generate a table for an areal<> configuration // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/include/universal/number/bfloat/attributes.hpp b/include/universal/number/bfloat/attributes.hpp index 15f973bc6..576f24d39 100644 --- a/include/universal/number/bfloat/attributes.hpp +++ b/include/universal/number/bfloat/attributes.hpp @@ -1,7 +1,8 @@ #pragma once // attributes.hpp: functions to query number system attributes // -// Copyright (C) 2022-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/bfloat/bfloat.hpp b/include/universal/number/bfloat/bfloat.hpp index 5c4b17514..e638a0b77 100644 --- a/include/universal/number/bfloat/bfloat.hpp +++ b/include/universal/number/bfloat/bfloat.hpp @@ -1,10 +1,11 @@ // bfloat arithmetic type standard header // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. -#ifndef _BFLOAT_STANDARD_HEADER_ -#define _BFLOAT_STANDARD_HEADER_ +#ifndef _BFLOAT16_STANDARD_HEADER_ +#define _BFLOAT16_STANDARD_HEADER_ //////////////////////////////////////////////////////////////////////////////////////// /// COMPILATION DIRECTIVES TO DIFFERENT COMPILERS diff --git a/include/universal/number/bfloat/bfloat16_impl.hpp b/include/universal/number/bfloat/bfloat16_impl.hpp index fc86a2e5d..f97cce9de 100644 --- a/include/universal/number/bfloat/bfloat16_impl.hpp +++ b/include/universal/number/bfloat/bfloat16_impl.hpp @@ -1,7 +1,8 @@ #pragma once // bfloat16_impl.hpp: definition of the Google Brain Float number system // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -117,19 +118,19 @@ class bfloat16 { } // initializers for native types - constexpr bfloat16(signed char initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(short initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(int initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(long initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(long long initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(char initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(unsigned short initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(unsigned int initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(unsigned long initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(unsigned long long initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(float initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(double initial_value) noexcept : _bits{} { *this = initial_value; } - constexpr bfloat16(long double initial_value) noexcept : _bits{} { *this = initial_value; } + constexpr bfloat16(signed char iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(short iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(int iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(long iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(long long iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(char iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(unsigned short iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(unsigned int iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(unsigned long iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(unsigned long long iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(float iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(double iv) noexcept : _bits{} { *this = iv; } + constexpr bfloat16(long double iv) noexcept : _bits{} { *this = iv; } // assignment operators for native types constexpr bfloat16& operator=(signed char rhs) noexcept { return convert_signed(rhs); } @@ -252,7 +253,7 @@ class bfloat16 { /// decimal scientific notation of a real number to be assigned /// reference to this cfloat /// Clang doesn't support constexpr yet on string manipulations, so we need to make it conditional - CONSTEXPRESSION bfloat16& assign(const std::string& str) noexcept { + bfloat16& assign(const std::string& str) noexcept { clear(); unsigned nrChars = static_cast(str.size()); unsigned nrBits = 0; diff --git a/include/universal/number/bfloat/bfloat8_impl.hpp b/include/universal/number/bfloat/bfloat8_impl.hpp index 9487f1ca0..1f2e74ca7 100644 --- a/include/universal/number/bfloat/bfloat8_impl.hpp +++ b/include/universal/number/bfloat/bfloat8_impl.hpp @@ -1,7 +1,8 @@ #pragma once // bfloat8_impl.hpp: definition of the Google Brain Float number system // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -252,7 +253,7 @@ class bfloat8 { /// decimal scientific notation of a real number to be assigned /// reference to this cfloat /// Clang doesn't support constexpr yet on string manipulations, so we need to make it conditional - CONSTEXPRESSION bfloat8& assign(const std::string& str) noexcept { + bfloat8& assign(const std::string& str) noexcept { clear(); unsigned nrChars = static_cast(str.size()); unsigned nrBits = 0; diff --git a/include/universal/number/bfloat/exceptions.hpp b/include/universal/number/bfloat/exceptions.hpp index 6f50373c6..715038fa4 100644 --- a/include/universal/number/bfloat/exceptions.hpp +++ b/include/universal/number/bfloat/exceptions.hpp @@ -1,7 +1,8 @@ #pragma once // exceptions.hpp: definition of bfloat exceptions // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/bfloat/manipulators.hpp b/include/universal/number/bfloat/manipulators.hpp index 4f9830b07..9b12629ef 100644 --- a/include/universal/number/bfloat/manipulators.hpp +++ b/include/universal/number/bfloat/manipulators.hpp @@ -1,7 +1,8 @@ #pragma once // manipulators.hpp: definition of manipulation functions for bfloat // -// Copyright (C) 2022-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/bfloat/numeric_limits.hpp b/include/universal/number/bfloat/numeric_limits.hpp index aa5af025d..dc3e3940c 100644 --- a/include/universal/number/bfloat/numeric_limits.hpp +++ b/include/universal/number/bfloat/numeric_limits.hpp @@ -1,7 +1,8 @@ #pragma once // numeric_limits.hpp: definition of numeric_limits for bfloat types // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/cfloat/cfloat.hpp b/include/universal/number/cfloat/cfloat.hpp index f482df0f9..bd069a833 100644 --- a/include/universal/number/cfloat/cfloat.hpp +++ b/include/universal/number/cfloat/cfloat.hpp @@ -30,7 +30,7 @@ #endif //////////////////////////////////////////////////////////////////////////////////////// -// enable throwing specific exceptions for integer arithmetic errors +// enable throwing specific exceptions for arithmetic errors // left to application to enable #if !defined(CFLOAT_THROW_ARITHMETIC_EXCEPTION) // default is to use std::cerr for signalling an error diff --git a/include/universal/number/cfloat/cfloat_impl.hpp b/include/universal/number/cfloat/cfloat_impl.hpp index 654b88e87..9252a698d 100644 --- a/include/universal/number/cfloat/cfloat_impl.hpp +++ b/include/universal/number/cfloat/cfloat_impl.hpp @@ -464,15 +464,15 @@ class cfloat { constexpr cfloat& operator=(unsigned long rhs) noexcept { return convert_unsigned_integer(rhs); } constexpr cfloat& operator=(unsigned long long rhs) noexcept { return convert_unsigned_integer(rhs); } - CONSTEXPRESSION cfloat& operator=(float rhs) noexcept { return convert_ieee754(rhs); } - CONSTEXPRESSION cfloat& operator=(double rhs) noexcept { return convert_ieee754(rhs); } + BIT_CAST_CONSTEXPR cfloat& operator=(float rhs) noexcept { return convert_ieee754(rhs); } + BIT_CAST_CONSTEXPR cfloat& operator=(double rhs) noexcept { return convert_ieee754(rhs); } // guard long double support to enable ARM and RISC-V embedded environments -//#if LONG_DOUBLE_SUPPORT - CONSTEXPRESSION cfloat(long double iv) noexcept : _block{} { *this = iv; } - CONSTEXPRESSION cfloat& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } +#if LONG_DOUBLE_SUPPORT explicit operator long double() const noexcept { return to_native(); } -//#endif + BIT_CAST_CONSTEXPR cfloat(long double iv) noexcept : _block{} { *this = iv; } + BIT_CAST_CONSTEXPR cfloat& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } +#endif // arithmetic operators // prefix operator diff --git a/include/universal/number/cfloat/math/classify.hpp b/include/universal/number/cfloat/math/classify.hpp index 85f5e56c4..e63f6f304 100644 --- a/include/universal/number/cfloat/math/classify.hpp +++ b/include/universal/number/cfloat/math/classify.hpp @@ -11,11 +11,7 @@ namespace sw { namespace universal { // STD LIB function for IEEE floats: Categorizes floating point value arg into the following categories: zero, subnormal, normal, infinite, NAN, or implementation-defined category. template int fpclassify(const cfloat& a) { -#if LONG_DOUBLE_SUPPORT - return std::fpclassify((long double)(a)); -#else return std::fpclassify(double(a)); -#endif } // STD LIB function for IEEE floats: Determines if the given floating point number arg has finite value i.e. it is normal, subnormal or zero, but not infinite or NaN. diff --git a/include/universal/number/cfloat/numeric_limits.hpp b/include/universal/number/cfloat/numeric_limits.hpp index 18bd42320..3264f2a72 100644 --- a/include/universal/number/cfloat/numeric_limits.hpp +++ b/include/universal/number/cfloat/numeric_limits.hpp @@ -45,33 +45,33 @@ class numeric_limits< sw::universal::cfloat(digits / 3.3f); - static constexpr int max_digits10 = digits10 + 1; - static constexpr bool is_signed = true; - static constexpr bool is_integer = false; - static constexpr bool is_exact = false; - static constexpr int radix = 2; + static constexpr int digits = nbits - 1 - es + 1; + static constexpr int digits10 = static_cast(digits / 3.3f); + static constexpr int max_digits10 = digits10 + 1; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr int radix = 2; // C++ specification: min_exponent is one more than the smallest negative power // of the radix that is a valid normalized number - static constexpr int min_exponent = Cfloat::MIN_EXP_NORMAL + 1; - static constexpr int min_exponent10 = static_cast(min_exponent / 3.3f); + static constexpr int min_exponent = Cfloat::MIN_EXP_NORMAL + 1; + static constexpr int min_exponent10 = static_cast(min_exponent / 3.3f); // C++ specification: max_exponent is one more than the largest integer power // of the radix that is a valid finite floating-point number - static constexpr int max_exponent = Cfloat::MAX_EXP; - static constexpr int max_exponent10 = static_cast(max_exponent / 3.3f); - static constexpr bool has_infinity = true; - static constexpr bool has_quiet_NaN = true; - static constexpr bool has_signaling_NaN = true; + static constexpr int max_exponent = Cfloat::MAX_EXP; + static constexpr int max_exponent10 = static_cast(max_exponent / 3.3f); + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; static constexpr float_denorm_style has_denorm = (hasSubnormals ? denorm_present : denorm_absent); - static constexpr bool has_denorm_loss = false; + static constexpr bool has_denorm_loss = false; - static constexpr bool is_iec559 = false; - static constexpr bool is_bounded = false; - static constexpr bool is_modulo = false; - static constexpr bool traps = false; - static constexpr bool tinyness_before = false; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = false; + static constexpr bool is_modulo = false; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; static constexpr float_round_style round_style = round_toward_zero; }; diff --git a/include/universal/number/dbns/dbns_impl.hpp b/include/universal/number/dbns/dbns_impl.hpp index 275e99f34..5a45a1b53 100644 --- a/include/universal/number/dbns/dbns_impl.hpp +++ b/include/universal/number/dbns/dbns_impl.hpp @@ -594,9 +594,9 @@ class dbns { // guard long double support to enable ARM and RISC-V embedded environments #if LONG_DOUBLE_SUPPORT - dbns(long double initial_value) noexcept { *this = initial_value; } - CONSTEXPRESSION dbns& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } explicit operator long double() const noexcept { return to_ieee754(); } + dbns(long double initial_value) noexcept { *this = initial_value; } + dbns& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } #endif void debugConstexprParameters() { diff --git a/include/universal/number/dd/attributes.hpp b/include/universal/number/dd/attributes.hpp new file mode 100644 index 000000000..6760d00d6 --- /dev/null +++ b/include/universal/number/dd/attributes.hpp @@ -0,0 +1,65 @@ +#pragma once +// attributes.hpp: information functions for decimal floating-point type and value attributes +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + +// functions to provide details about the properties of a doubledouble (dd) configuration + inline bool sign(const dd& a) { + return a.sign(); + } + + inline int scale(const dd& a) { + return a.scale(); + } + + // generate the maxneg through maxpos value range of a doubledouble configuration + std::string dd_range() { + dd v; + std::stringstream s; + s << std::setw(80) << type_tag(v) << " : [ " + << v.maxneg() << " ... " + << v.minneg() << " " + << "0 " + << v.minpos() << " ... " + << v.maxpos() << " ]"; + return s.str(); + } + + /* + // report dynamic range of a type, specialized for a doubledouble + std::string dynamic_range(const dd& a) { + std::stringstream s; + dd b(SpecificValue::maxneg), c(SpecificValue::minneg), d(SpecificValue::minpos), e(SpecificValue::maxpos); + s << type_tag(a) << ": "; + s << "minpos scale " << std::setw(10) << d.scale() << " "; + s << "maxpos scale " << std::setw(10) << e.scale() << '\n'; + s << "[" << b << " ... " << c << ", -0, +0, " << d << " ... " << e << "]\n"; + s << "[" << to_binary(b) << " ... " << to_binary(c) << ", -0, +0, " << to_binary(d) << " ... " << to_binary(e) << "]\n"; + dd ninf(SpecificValue::infneg), pinf(SpecificValue::infpos); + s << "inclusive range = (" << to_binary(ninf) << ", " << to_binary(pinf) << ")\n"; + s << "inclusive range = (" << ninf << ", " << pinf << ")\n"; + return s.str(); + } + */ + + int minpos_scale(const dd& b) { + dd c(b); + return c.minpos().scale(); + } + + int maxpos_scale(const dd& b) { + dd c(b); + return c.maxpos().scale(); + } + + int max_negative_scale(const dd& b) { + dd c(b); + return c.maxneg().scale(); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/dd.hpp b/include/universal/number/dd/dd.hpp new file mode 100644 index 000000000..70336e491 --- /dev/null +++ b/include/universal/number/dd/dd.hpp @@ -0,0 +1,76 @@ +// arbitrary configuration decimal floating-point arithmetic standard header +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#ifndef _DOUBLEDOUBLE_STANDARD_HEADER_ +#define _DOUBLEDOUBLE_STANDARD_HEADER_ + +//////////////////////////////////////////////////////////////////////////////////////// +/// COMPILATION DIRECTIVES TO DIFFERENT COMPILERS +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////// +/// required std libraries +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////// +/// BEHAVIORAL COMPILATION SWITCHES + +//////////////////////////////////////////////////////////////////////////////////////// +// enable/disable the ability to use literals in binary logic and arithmetic operators +#if !defined(DOUBLEDOUBLE_ENABLE_LITERALS) +// default is to enable them +#define DOUBLEDOUBLE_ENABLE_LITERALS 1 +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// enable throwing specific exceptions for arithmetic errors +// left to application to enable +#if !defined(DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION) +// default is to use std::cerr for signalling an error +#define DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION 0 +#define DOUBLEDOUBLE_EXCEPT noexcept +#else +#if DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION +#define DOUBLEDOUBLE_EXCEPT +#else +#define DOUBLEDOUBLE_EXCEPT noexcept +#endif +#endif + +//////////////////////////////////////////////////////////////////////////////////////// +// enable native sqrt implementation +// +#if !defined(DOUBLEDOUBLE_NATIVE_SQRT) +#define DOUBLEDOUBLE_NATIVE_SQRT 0 +#endif + +/////////////////////////////////////////////////////////////////////////////////////// +// bring in the trait functions +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////// +/// INCLUDE FILES that make up the library +#include +#include +#include +#include +#include + +// useful functions to work with doubledoubles +#include +#include + +/////////////////////////////////////////////////////////////////////////////////////// +/// elementary math functions library +#include + +#endif diff --git a/include/universal/number/dd/dd_fwd.hpp b/include/universal/number/dd/dd_fwd.hpp new file mode 100644 index 000000000..30aaec8eb --- /dev/null +++ b/include/universal/number/dd/dd_fwd.hpp @@ -0,0 +1,24 @@ +#pragma once +// dfloat_fwd.hpp : forward declarations of the decimal floating-point dfloat environment +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +namespace sw { namespace universal { + + // forward references + class dd; + + bool parse(const std::string& number, dd& v); + + dd abs(dd); + dd sqrt(dd); + dd fabs(dd); + + dd fma(dd const&, dd const&, dd const&); + +}} // namespace sw::universal + diff --git a/include/universal/number/dd/dd_impl.hpp b/include/universal/number/dd/dd_impl.hpp new file mode 100644 index 000000000..dc16437ff --- /dev/null +++ b/include/universal/number/dd/dd_impl.hpp @@ -0,0 +1,1339 @@ +#pragma once +// dd_impl.hpp: implementation of the double-double floating-point number system described in +// +// Sherry Li, David Bailey, LBNL, "Library for Double-Double and Quad-Double Arithmetic", 2008 +// https://www.researchgate.net/publication/228570156_Library_for_Double-Double_and_Quad-Double_Arithmetic +// +// Adapted core subroutines from QD library by Yozo Hida +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include +#include + +// supporting types and functions +#include +#include +#include +#include +// dd exception structure +#include +#include + +namespace sw { namespace universal { + + struct uint128_t { + uint128_t() : limb{ 0 } {} + uint64_t limb[2]; + }; + +// fwd references to free functions used in to_digits() +dd operator*(const dd& lhs, const dd&); +dd pown(dd const&, int); + +// dd is an unevaluated pair of IEEE-754 doubles that provides a (1,11,106) floating-point triple +class dd { +public: + static constexpr unsigned nbits = 128; + static constexpr unsigned es = 11; + static constexpr unsigned fbits = 106; // number of fraction digits + // exponent characteristics are the same as native double precision floating-point + static constexpr int EXP_BIAS = ((1 << (es - 1u)) - 1l); + static constexpr int MAX_EXP = (es == 1) ? 1 : ((1 << es) - EXP_BIAS - 1); + static constexpr int MIN_EXP_NORMAL = 1 - EXP_BIAS; + static constexpr int MIN_EXP_SUBNORMAL = 1 - EXP_BIAS - int(fbits); // the scale of smallest ULP + + /// trivial constructor + dd() = default; + + dd(const dd&) = default; + dd(dd&&) = default; + + dd& operator=(const dd&) = default; + dd& operator=(dd&&) = default; + + // converting constructors + dd(const std::string& stringRep) : hi{0.0}, lo{0.0} { assign(stringRep); } + + // specific value constructor + constexpr dd(const SpecificValue code) noexcept : hi{0.0}, lo{0.0} { + switch (code) { + case SpecificValue::maxpos: + maxpos(); + break; + case SpecificValue::minpos: + minpos(); + break; + case SpecificValue::zero: + default: + zero(); + break; + case SpecificValue::minneg: + minneg(); + break; + case SpecificValue::maxneg: + maxneg(); + break; + case SpecificValue::infpos: + setinf(false); + break; + case SpecificValue::infneg: + setinf(true); + break; + case SpecificValue::nar: // approximation as dds don't have a NaR + case SpecificValue::qnan: + setnan(NAN_TYPE_QUIET); + break; + case SpecificValue::snan: + setnan(NAN_TYPE_SIGNALLING); + break; + } + } + + // raw limb constructor: no argument checking + constexpr dd(double h, double l) noexcept : hi{ h }, lo{ l } {} + + // initializers for native types + constexpr dd(signed char iv) noexcept : hi{ static_cast(iv) }, lo{ 0.0 } {} + constexpr dd(short iv) noexcept : hi{ static_cast(iv) }, lo{ 0.0 } {} + constexpr dd(int iv) noexcept : hi{ static_cast(iv) }, lo{ 0.0 } {} + constexpr dd(long iv) noexcept { *this = iv; } + constexpr dd(long long iv) noexcept { *this = iv; } + constexpr dd(char iv) noexcept : hi{ static_cast(iv) }, lo{ 0.0 } {} + constexpr dd(unsigned short iv) noexcept : hi{ static_cast(iv) }, lo{ 0.0 } {} + constexpr dd(unsigned int iv) noexcept : hi{ static_cast(iv) }, lo{ 0.0 } {} + constexpr dd(unsigned long iv) noexcept { *this = iv; } + constexpr dd(unsigned long long iv) noexcept { *this = iv; } + constexpr dd(float iv) noexcept : hi{ iv }, lo{ 0.0 } {} + constexpr dd(double iv) noexcept : hi{ iv }, lo{ 0.0 } {} + + // assignment operators for native types + constexpr dd& operator=(signed char rhs) noexcept { return convert_signed(rhs); } + constexpr dd& operator=(short rhs) noexcept { return convert_signed(rhs); } + constexpr dd& operator=(int rhs) noexcept { return convert_signed(rhs); } + constexpr dd& operator=(long rhs) noexcept { return convert_signed(rhs); } + constexpr dd& operator=(long long rhs) noexcept { return convert_signed(rhs); } + constexpr dd& operator=(unsigned char rhs) noexcept { return convert_unsigned(rhs); } + constexpr dd& operator=(unsigned short rhs) noexcept { return convert_unsigned(rhs); } + constexpr dd& operator=(unsigned int rhs) noexcept { return convert_unsigned(rhs); } + constexpr dd& operator=(unsigned long rhs) noexcept { return convert_unsigned(rhs); } + constexpr dd& operator=(unsigned long long rhs) noexcept { return convert_unsigned(rhs); } + constexpr dd& operator=(float rhs) noexcept { return convert_ieee754(rhs); } + constexpr dd& operator=(double rhs) noexcept { return convert_ieee754(rhs); } + + // conversion operators + explicit operator int() const noexcept { return convert_to_signed(); } + explicit operator long() const noexcept { return convert_to_signed(); } + explicit operator long long() const noexcept { return convert_to_signed(); } + explicit operator unsigned int() const noexcept { return convert_to_unsigned(); } + explicit operator unsigned long() const noexcept { return convert_to_unsigned(); } + explicit operator unsigned long long() const noexcept { return convert_to_unsigned(); } + explicit operator float() const noexcept { return convert_to_ieee754(); } + explicit operator double() const noexcept { return convert_to_ieee754(); } + + +#if LONG_DOUBLE_SUPPORT + // can't be constexpr as remainder calculation requires volatile designation + dd(long double iv) noexcept { *this = iv; } + dd& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } + explicit operator long double() const noexcept { return convert_to_ieee754(); } +#endif + + // prefix operators + constexpr dd operator-() const noexcept { + dd negated(*this); + negated.hi = -negated.hi; + negated.lo = -negated.lo; + return negated; + } + + + // arithmetic operators + dd& operator+=(const dd& rhs) { + double s2; + hi = two_sum(hi, rhs.hi, s2); + if (std::isfinite(hi)) { + double t2, t1 = two_sum(lo, rhs.lo, t2); + lo = two_sum(s2, t1, t1); + t1 += t2; + three_sum(hi, lo, t1); + } + else { + lo = 0.0; + } + return *this; + } + dd& operator+=(double rhs) { + return operator+=(dd(rhs)); + } + dd& operator-=(const dd& rhs) { + double s2; + hi = two_sum(hi, -rhs.hi, s2); + if (std::isfinite(hi)) { + double t2, t1 = two_sum(lo, -rhs.lo, t2); + lo = two_sum(s2, t1, t1); + t1 += t2; + three_sum(hi, lo, t1); + } + else { + lo = 0.0; + } + return *this; + } + dd& operator-=(double rhs) { + return operator-=(dd(rhs)); + } + dd& operator*=(const dd& rhs) { + double p[7]; + // e powers in p = 0, 1, 1, 1, 2, 2, 2 + p[0] = two_prod(hi, rhs.hi, p[1]); + if (std::isfinite(p[0])) { + p[2] = two_prod(hi, rhs.lo, p[4]); + p[3] = two_prod(lo, rhs.hi, p[5]); + p[6] = lo * rhs.lo; + + // e powers in p = 0, 1, 2, 3, 2, 2, 2 + three_sum(p[1], p[2], p[3]); + + // e powers in p = 0, 1, 2, 3, 2, 3, 4 + p[2] += p[4] + p[5] + p[6]; + + three_sum(p[0], p[1], p[2]); + + hi = p[0]; + lo = p[1]; + } + else { + hi = p[0]; + lo = 0.0; + } + return *this; + } + dd& operator*=(double rhs) { + return operator*=(dd(rhs)); + } + dd& operator/=(const dd& rhs) { + if (isnan()) return *this; + + if (rhs.isnan()) { + *this = rhs; + return *this; + } + + if (rhs.iszero()) { + if (iszero()) { + *this = dd(SpecificValue::qnan); + } + else { + // auto signA = std::copysign(1.0, hi); + // auto signB = std::copysign(1.0, rhs.hi); + // *this = (signA * signB) * dd(SpecificValue::infpos); + *this = dd(SpecificValue::infpos); + } + return *this; + } + + double q1 = hi / rhs.hi; // approximate quotient + if (std::isfinite(q1)) { + dd r = fma(-q1, rhs, *this); + + double q2 = r.hi / rhs.hi; + r = fma(-q2, rhs, r); + + double q3 = r.hi / rhs.hi; + + three_sum(q1, q2, q3); + hi = q1; + lo = q2; + } + else { + hi = q1; + lo = 0.0; + } + + return *this; + } + dd& operator/=(double rhs) { + return operator/=(dd(rhs)); + } + + // unary operators + dd& operator++() { + return *this; + } + dd operator++(int) { + dd tmp(*this); + operator++(); + return tmp; + } + dd& operator--() { + return *this; + } + dd operator--(int) { + dd tmp(*this); + operator--(); + return tmp; + } + + // modifiers + constexpr void clear() noexcept { hi = 0.0; lo = 0.0; } + constexpr void setzero() noexcept { hi = 0.0; lo = 0.0; } + constexpr void setinf(bool sign = true) noexcept { hi = (sign ? -INFINITY : INFINITY); lo = 0.0; } + constexpr void setnan(int NaNType = NAN_TYPE_SIGNALLING) noexcept { hi = (NaNType == NAN_TYPE_SIGNALLING ? std::numeric_limits::signaling_NaN() : std::numeric_limits::quiet_NaN()); lo = 0.0; } + constexpr void setsign(bool sign = true) noexcept { if (sign && hi > 0.0) hi = -hi; } + + constexpr void setbit(unsigned index, bool b = true) noexcept { + if (index < 64) { // set bit in lower limb + uint64_t raw = std::bit_cast(lo); + uint64_t mask = (1ull << index); + if (b) raw |= mask; else raw &= ~mask; + lo = std::bit_cast(raw); + } + else if (index < 128) { // set bit in upper limb + uint64_t raw = std::bit_cast(hi); + uint64_t mask = (1ull << (index - 64)); + if (b) raw |= mask; else raw &= ~mask; + hi = std::bit_cast(raw); + } + else { + // NOP if index out of bounds + } + } + constexpr void setbits(uint64_t value) noexcept { + hi = static_cast(value); + lo = 0.0; + } + + // create specific number system values of interest + constexpr dd& maxpos() noexcept { + hi = 1.7976931348623157e+308; + lo = 1.9958403095347196e+292; + return *this; + } + constexpr dd& minpos() noexcept { + hi = 1.0f; + lo = 0.0f; + return *this; + } + constexpr dd& zero() noexcept { + // the zero value + clear(); + return *this; + } + constexpr dd& minneg() noexcept { + hi = 1.0f; + lo = 0.0f; + return *this; + } + constexpr dd& maxneg() noexcept { + hi = 1.0f; + lo = 0.0f; + return *this; + } + + dd& assign(const std::string& txt) { + dd v; + if (parse(txt, v)) *this = v; + return *this; // Is this what we want? when the string is not valid, keep the current value? + } + + // selectors + constexpr bool iszero() const noexcept { return hi == 0.0; } + constexpr bool isone() const noexcept { return hi == 1.0 && lo == 0.0; } + constexpr bool ispos() const noexcept { return hi > 0.0; } + constexpr bool isneg() const noexcept { return hi < 0.0; } + constexpr bool isnan(int NaNType = NAN_TYPE_EITHER) const noexcept { + bool negative = isneg(); + int nan_type; + bool isNaN = checkNaN(hi, nan_type); + bool isNegNaN = isNaN && negative; + bool isPosNaN = isNaN && !negative; + return (NaNType == NAN_TYPE_EITHER ? (isNegNaN || isPosNaN) : + (NaNType == NAN_TYPE_SIGNALLING ? isNegNaN : + (NaNType == NAN_TYPE_QUIET ? isPosNaN : false))); + } + constexpr bool isinf(int InfType = INF_TYPE_EITHER) const noexcept { + bool negative = isneg(); + int inf_type; + bool isInf = checkInf(hi, inf_type); + bool isNegInf = isInf && negative; + bool isPosInf = isInf && !negative; + return (InfType == INF_TYPE_EITHER ? (isNegInf || isPosInf) : + (InfType == INF_TYPE_NEGATIVE ? isNegInf : + (InfType == INF_TYPE_POSITIVE ? isPosInf : false))); + } + + constexpr bool sign() const noexcept { return (hi < 0.0); } + constexpr int scale() const noexcept { return _extractExponent(hi); } + constexpr int exponent() const noexcept { return _extractExponent(hi); } + uint128_t fraction() const noexcept { + uint128_t frac{ }; + int e; + double l = std::frexp(lo, &e); + frac.limb[0] = static_cast(l); + + return frac; + } + constexpr double high() const noexcept { return hi; } + constexpr double low() const noexcept { return lo; } + + // precondition: string s must be all digits + void round_string(char* s, int precision, int* decimalPoint) const { + int nrDigits = precision; + // round decimal string and propagate carry + int lastDigit = nrDigits - 1; + if (s[lastDigit] >= '5') { + int i = nrDigits - 2; + s[i]++; + while (i > 0 && s[i] > '9') { + s[i] -= 10; + s[--i]++; + } + } + + // if first digit is 10, shift everything. + if (s[0] > '9') { + for (int i = precision; i >= 2; i--) s[i] = s[i - 1]; + s[0] = '1'; + s[1] = '0'; + + (*decimalPoint)++; // increment decimal point + ++precision; + } + + s[precision] = 0; // add termination null + } + + void append_exponent(std::string& str, int e) const { + str += (e < 0 ? '-' : '+'); + e = std::abs(e); + int k; + if (e >= 100) { + k = (e / 100); + str += static_cast('0' + k); + e -= 100 * k; + } + + k = (e / 10); + str += static_cast('0' + k); + e -= 10 * k; + + str += static_cast('0' + e); + } + + // convert to string containing digits number of digits + std::string to_string(std::streamsize precision = 7, std::streamsize width = 15, bool fixed = false, bool scientific = true, bool internal = false, bool left = false, bool showpos = false, bool uppercase = false, char fill = ' ') const { + std::string s; + bool negative = sign() ? true : false; + int e{ 0 }; + if (fixed && scientific) fixed = false; // scientific format takes precedence + if (isnan()) { + s = uppercase ? "NAN" : "nan"; + negative = false; + } + else { + if (negative) { s += '-'; } else { if (showpos) s += '+'; } + + if (isinf()) { + s += uppercase ? "INF" : "inf"; + } + else if (iszero()) { + s += '0'; + if (precision > 0) { + s += '.'; + s.append(static_cast(precision), '0'); + } + } + else { + int powerOfTenScale = static_cast(std::log10(std::fabs(hi))); + int integerDigits = (fixed ? (powerOfTenScale + 1) : 1); + int nrDigits = integerDigits + static_cast(precision); + + int nrDigitsForFixedFormat = nrDigits; + if (fixed) + nrDigitsForFixedFormat = std::max(60, nrDigits); // can be much longer than the max accuracy for double-double + + // a number in the range of [0.5, 1.0) to be printed with zero precision + // must be rounded up to 1 to print correctly + if (fixed && (precision == 0) && (std::abs(high()) < 1.0)) { + s += (std::abs(hi) >= 0.5) ? '1' : '0'; + return s; + } + + if (fixed && nrDigits <= 0) { + // process values with negative exponents (powerOfTenScale < 0) + s += '0'; + if (precision > 0) { + s += '.'; + s.append(static_cast(precision), '0'); + } + } + else { + char* t; + + if (fixed) { + t = new char[static_cast(nrDigitsForFixedFormat + 1)]; + to_digits(t, e, nrDigitsForFixedFormat); + } + else { + t = new char[static_cast(nrDigits + 1)]; + to_digits(t, e, nrDigits); + } + + if (fixed) { + // round the decimal string + round_string(t, nrDigits, &integerDigits); + + if (integerDigits > 0) { + int i; + for (i = 0; i < integerDigits; ++i) s += t[i]; + if (precision > 0) { + s += '.'; + for (int j = 0; j < precision; ++j, ++i) s += t[i]; + } + } + else { + s += "0."; + if (integerDigits < 0) s.append(static_cast(-integerDigits), '0'); + for (int i = 0; i < nrDigits; ++i) s += t[i]; + } + } + else { + s += t[0]; + if (precision > 0) s += '.'; + + for (int i = 1; i <= precision; ++i) + s += t[i]; + + } + delete[] t; + } + } + + // trap for improper offset with large values + // without this trap, output of values of the for 10^j - 1 fail for j > 28 + // and are output with the point in the wrong place, leading to a dramatically off value + if (fixed && (precision > 0)) { + // make sure that the value isn't dramatically larger + double from_string = atof(s.c_str()); + + // if this ratio is large, then we've got problems + if (std::fabs(from_string / this->hi) > 3.0) { + + // loop on the string, find the point, move it up one + // don't act on the first character + for (std::string::size_type i = 1; i < s.length(); ++i) { + if (s[i] == '.') { + s[i] = s[i - 1]; + s[i - 1] = '.'; + break; + } + } + + from_string = atof(s.c_str()); + // if this ratio is large, then the string has not been fixed + if (std::fabs(from_string / this->hi) > 3.0) { + //error("Re-rounding unsuccessful in large number fixed point trap."); + } + } + } + + if (!fixed && !isinf()) { + // construct the exponent + s += uppercase ? 'E' : 'e'; + append_exponent(s, e); + } + } + + // process any fill + size_t strLength = s.length(); + if (strLength < static_cast(width)) { + size_t nrCharsToFill = (width - strLength); + if (internal) { + if (negative) + s.insert(static_cast(1), nrCharsToFill, fill); + else + s.insert(static_cast(0), nrCharsToFill, fill); + } + else if (left) { + s.append(nrCharsToFill, fill); + } + else { + s.insert(static_cast(0), nrCharsToFill, fill); + } + } + + return s; + } + +protected: + double hi, lo; + + // HELPER methods + + constexpr dd& convert_signed(int64_t v) noexcept { + if (0 == v) { + setzero(); + } + else { + hi = static_cast(v); + lo = static_cast(v - static_cast(hi)); + } + return *this; + } + + constexpr dd& convert_unsigned(uint64_t v) noexcept { + if (0 == v) { + setzero(); + } + else { + hi = static_cast(v); + lo = static_cast(v - static_cast(hi)); // difference is always positive + } + return *this; + } + + // no need to SFINAE this as it is an internal method that we ONLY call when we know the argument type is a native float + constexpr dd& convert_ieee754(float rhs) noexcept { + hi = double(rhs); + lo = 0.0; + return *this; + } + constexpr dd& convert_ieee754(double rhs) noexcept { + hi = rhs; + lo = 0.0; + return *this; + } +#if LONG_DOUBLE_SUPPORT + dd& convert_ieee754(long double rhs) { + volatile long double truncated = static_cast(double(rhs)); + volatile double remainder = static_cast(rhs - truncated); + hi = static_cast(truncated); + lo = remainder; + return *this; + } +#endif + + // convert to native unsigned integer, use C++ conversion rules to cast down to float and double + template + Unsigned convert_to_unsigned() const noexcept { + int64_t h = static_cast(hi); + int64_t l = static_cast(lo); + return Unsigned(h + l); + } + + // convert to native unsigned integer, use C++ conversion rules to cast down to float and double + template + Signed convert_to_signed() const noexcept { + int64_t h = static_cast(hi); + int64_t l = static_cast(lo); + return Signed(h + l); + } + + // convert to native floating-point, use C++ conversion rules to cast down to float and double + template + Real convert_to_ieee754() const noexcept { + return Real(hi + lo); + } + + /// + /// to_digits generates the decimal digits representing + /// + /// + /// + /// + void to_digits(char* s, int& exponent, int precision) const { + constexpr dd _one(1.0), _ten(10.0); + constexpr double _log2(0.301029995663981); + + if (iszero()) { + std::cout << "I am zero\n"; + exponent = 0; + for (int i = 0; i < precision; ++i) s[i] = '0'; + s[precision] = 0; // termination null + return; + } + + // First determine the (approximate) exponent. + // std::frexp(*this, &e); // e is appropriate for 0.5 <= x < 1 + int e; + std::frexp(hi, &e); + --e; // adjust e as frexp gives a binary e that is 1 too big + e = static_cast(_log2 * e); // estimate the power of ten exponent + dd r = abs(*this); + if (e < 0) { + if (e < -300) { + r = dd(std::ldexp(r.high(), 53), std::ldexp(r.low(), 53)); + r *= pown(_ten, -e); + r = dd(std::ldexp(r.high(), -53), std::ldexp(r.low(), -53)); + } + else { + r *= pown(_ten, -e); + } + } + else { + if (e > 0) { + if (e > 300) { + r = dd(std::ldexp(r.high(), -53), std::ldexp(r.low(), -53)); + r /= pown(_ten, e); + r = dd(std::ldexp(r.high(), 53), std::ldexp(r.low(), 53)); + } + else { + r /= pown(_ten, e); + } + } + } + + // Fix exponent if we have gone too far + if (r >= _ten) { + r /= _ten; + ++e; + } + else { + if (r < 1.0) { + r *= _ten; + --e; + } + } + + if ((r >= _ten) || (r < _one)) { + std::cerr << "to_digits() failed to compute exponent\n"; + return; + } + + // at this point the value is normalized to a decimal value between (0, 10) + // generate the digits + int nrDigits = precision + 1; + for (int i = 0; i < nrDigits; ++i) { + int mostSignificantDigit = static_cast(r.hi); + r -= mostSignificantDigit; + r *= 10.0; + + s[i] = static_cast(mostSignificantDigit + '0'); + } + + // Fix out of range digits + for (int i = nrDigits - 1; i > 0; --i) { + if (s[i] < '0') { + s[i - 1]--; + s[i] += 10; + } + else { + if (s[i] > '9') { + s[i - 1]++; + s[i] -= 10; + } + } + } + + if (s[0] <= '0') { + std::cerr << "to_digits() non-positive leading digit\n"; + return; + } + + // Round and propagate carry + int lastDigit = nrDigits - 1; + if (s[lastDigit] >= '5') { + int i = nrDigits - 2; + s[i]++; + while (i > 0 && s[i] > '9') { + s[i] -= 10; + s[--i]++; + } + } + + // If first digit is 10, shift left and increment exponent + if (s[0] > '9') { + ++e; + for (int i = precision; i >= 2; --i) { + s[i] = s[i - 1]; + } + s[0] = '1'; + s[1] = '0'; + } + + s[precision] = 0; // termination null + exponent = e; + } + +private: + + // dd - dd logic comparisons + friend bool operator==(const dd& lhs, const dd& rhs); + friend bool operator!=(const dd& lhs, const dd& rhs); + friend bool operator<=(const dd& lhs, const dd& rhs); + friend bool operator>=(const dd& lhs, const dd& rhs); + friend bool operator<(const dd& lhs, const dd& rhs); + friend bool operator>(const dd& lhs, const dd& rhs); + + // dd - literal logic comparisons + friend bool operator==(const dd& lhs, const double rhs); + + // literal - dd logic comparisons + friend bool operator==(const double lhs, const dd& rhs); + + friend bool operator<(const dd& lhs, const dd& rhs); + +}; + +//////////////////////// precomputed constants of note ///////////////////////////////// + +// precomputed double-double constants courtesy Scibuilders, Jack Poulson + +constexpr dd dd_2pi (6.283185307179586232e+00, 2.449293598294706414e-16); +constexpr dd dd_pi (3.141592653589793116e+00, 1.224646799147353207e-16); +constexpr dd dd_pi2 (1.570796326794896558e+00, 6.123233995736766036e-17); +constexpr dd dd_pi4 (7.853981633974482790e-01, 3.061616997868383018e-17); +constexpr dd dd_3pi4 (2.356194490192344837e+00, 9.1848509936051484375e-17); +constexpr dd dd_e (2.718281828459045091e+00, 1.445646891729250158e-16); +constexpr dd dd_log2 (6.931471805599452862e-01, 2.319046813846299558e-17); +constexpr dd dd_log10 (2.302585092994045901e+00, -2.170756223382249351e-16); + +constexpr dd dd_eps = 4.93038065763132e-32; // 2^-104 +constexpr dd dd_min_normalized = 2.0041683600089728e-292; // = 2^(-1022 + 53) +constexpr dd dd_max(1.79769313486231570815e+308, 9.97920154767359795037e+291); +constexpr dd dd_safe_max(1.7976931080746007281e+308, 9.97920154767359795037e+291); + + +// precomputed double-double constants courtesy of constants example program, Theodore Omtzigt + +constexpr dd dd_ln2 (0.69314718055994529e+00, 2.3190468138462996e-17); +constexpr dd dd_ln10 (2.30258509299404590e+00, -2.1707562233822494e-16); +constexpr dd dd_lge (1.44269504088896340e+00, 2.0355273740931027e-17); +constexpr dd dd_lg10 (3.32192809488736220e+00, 1.6616175169735918e-16); +constexpr dd dd_loge (0.43429448190325182e+00, 1.0983196502167652e-17); + +constexpr dd dd_sqrt2 (1.41421356237309510e+00, -9.6672933134529122e-17); + +constexpr dd dd_inv_pi (0.31830988618379069e+00, -1.9678676675182486e-17); +constexpr dd dd_inv_pi2 (0.63661977236758138e+00, -3.9357353350364972e-17); +constexpr dd dd_inv_e (0.36787944117144233e+00, -1.2428753672788364e-17); +constexpr dd dd_inv_sqrt2(0.70710678118654757e+00, -4.8336466567264561e-17); + +//////////////////////// helper functions ///////////////////////////////// + +inline std::string to_pair(const dd& v, int precision = 17) { + std::stringstream s; + // 53 bits = 16 decimal digits, 17 to include last, 15 typical valid digits + s << std::setprecision(precision) << "( " << v.high() << ", " << v.low() << ')'; + return s.str(); +} + +inline std::string to_binary(const dd& number, bool bNibbleMarker = false) { + std::stringstream s; + double_decoder decoder; + decoder.d = number.high(); + + s << "0b"; + // print sign bit + s << (decoder.parts.sign ? '1' : '0') << '.'; + + // print exponent bits + { + uint64_t mask = 0x400; + for (int i = 10; i >= 0; --i) { + s << ((decoder.parts.exponent & mask) ? '1' : '0'); + if (bNibbleMarker && i != 0 && (i % 4) == 0) s << '\''; + mask >>= 1; + } + } + + s << '.'; + + // print hi fraction bits + uint64_t mask = (uint64_t(1) << 51); + for (int i = 51; i >= 0; --i) { + s << ((decoder.parts.fraction & mask) ? '1' : '0'); + if (bNibbleMarker && i != 0 && (i % 4) == 0) s << '\''; + mask >>= 1; + } + + // print lo fraction bits + decoder.d = number.low(); + if (bNibbleMarker) { + s << (decoder.parts.exponent == 0 ? "\'0\'" : "\'1\'"); // articulate the hidden bit, e == 0 covers both denorm and zero hidden bit status + } + else { + // still delineate the two segments so you can quickly pick up the hidden bit value and start of the second segment + s << (decoder.parts.exponent == 0 ? "\'0" : "\'1"); // articulate the hidden bit, e == 0 covers both denorm and zero hidden bit status + } + mask = (uint64_t(1) << 51); + for (int i = 51; i >= 0; --i) { + s << ((decoder.parts.fraction & mask) ? '1' : '0'); + if (bNibbleMarker && i != 0 && (i % 4) == 0) s << '\''; + mask >>= 1; + } + + return s.str(); +} + +//////////////////////// math functions ///////////////////////////////// + +inline dd abs(dd a) { + double hi = a.high(); + double lo = a.low(); + if (hi < 0) { // flip the pair with respect to 0 + hi = -hi; + lo = -lo; + } + return dd(hi, lo); +} + +inline dd ceil(dd const& a) +{ + if (a.isnan()) return a; + + double hi = std::ceil(a.high()); + double lo = 0.0; + + if (hi == a.high()) { // High segment was already an integer, thus just round the low segment + lo = std::ceil(a.low()); + hi = quick_two_sum(hi, lo, lo); + } + + return dd(hi, lo); +} + +inline dd floor(dd const& a) { + if (a.isnan()) return a; + + double hi = std::floor(a.high()); + double lo = 0.0; + + if (hi == a.high()) { + // High word is integer already. Round the low word. + // + lo = std::floor(a.low()); + hi = quick_two_sum(hi, lo, lo); + } + + return dd(hi, lo); +} + +// double times double yielding a double-double +inline dd mul(double a, double b) { + double p, e; + p = two_prod(a, b, e); + return dd(p, e); +} + +// double-double * double, where double is a power of 2. */ +inline dd mul_pwr2(const dd& a, double b) { + return dd(a.high() * b, a.low() * b); +} + +// quad-double operators + +// quad-double + double-double +void qd_add(double const a[4], dd const& b, double s[4]) { + double t[5]; + s[0] = two_sum(a[0], b.high(), t[0]); // s0 - O( 1 ); t0 - O( e ) + s[1] = two_sum(a[1], b.low(), t[1]); // s1 - O( e ); t1 - O( e^2 ) + + s[1] = two_sum(s[1], t[0], t[0]); // s1 - O( e ); t0 - O( e^2 ) + + s[2] = a[2]; // s2 - O( e^2 ) + three_sum(s[2], t[0], t[1]); // s2 - O( e^2 ); t0 - O( e^3 ); t1 = O( e^4 ) + + s[3] = two_sum(a[3], t[0], t[0]); // s3 - O( e^3 ); t0 - O( e^4 ) + t[0] += t[1]; // fl( t0 + t1 ) - accuracy less important + + renorm(s[0], s[1], s[2], s[3], t[0]); +} + +// quad-double = double-double * double-double +void qd_mul(dd const& a, dd const& b, double p[4]) { + double p4, p5, p6, p7; + + // powers of e - 0, 1, 1, 1, 2, 2, 2, 3 + p[0] = two_prod(a.high(), b.high(), p[1]); + if (std::isfinite(p[0])) { + p[2] = two_prod(a.high(), b.low(), p4); + p[3] = two_prod(a.low(), b.high(), p5); + p6 = two_prod(a.low(), b.low(), p7); + + // powers of e - 0, 1, 2, 3, 2, 2, 2, 3 + three_sum(p[1], p[2], p[3]); + + // powers of e - 0, 1, 2, 3, 2, 3, 4, 3 + three_sum(p4, p5, p6); + + // powers of e - 0, 1, 2, 3, 3, 3, 4, 3 + p[2] = two_sum(p[2], p4, p4); + + // powers of e - 0, 1, 2, 3, 4, 5, 4, 3 + three_sum(p[3], p4, p5); + + // powers of e - 0, 1, 2, 3, 4, 5, 4, 4 + p[3] = two_sum(p[3], p7, p7); + + p4 += (p6 + p7); + + renorm(p[0], p[1], p[2], p[3], p4); + } + else { + p[1] = p[2] = p[3] = 0.0; + } +} + +inline dd fma(dd const& a, dd const& b, dd const& c) { + double p[4]; + qd_mul(a, b, p); + qd_add(p, c, p); + p[0] = two_sum(p[0], p[1] + p[2] + p[3], p[1]); + return dd(p[0], p[1]); +} + +inline dd sqr(dd const& a) { + if (a.isnan()) return a; + + double p2, p1 = two_sqr(a.high(), p2); + p2 += 2.0 * a.high() * a.low(); + p2 += a.low() * a.low(); + + double s2, s1 = quick_two_sum(p1, p2, s2); + return dd(s1, s2); +} + +inline dd reciprocal(dd const& a) { + if (a.iszero()) return dd(SpecificValue::infpos); + + if (a.isinf()) return dd(0.0); + + double q1 = 1.0 / a.high(); /* approximate quotient */ + if (std::isfinite(q1)) { + dd r = fma(-q1, a, 1.0); + + double q2 = r.high() / a.high(); + r = fma(-q2, a, r); + + double q3 = r.high() / a.high(); + three_sum(q1, q2, q3); + return dd(q1, q2); + } + else { + return dd(q1, 0.0); + } +} + +inline dd pown(dd const& a, int n) { + if (a.isnan()) return a; + + int N = (n < 0) ? -n : n; + dd s; + + switch (N) { + case 0: + if (a.iszero()) { +// error("(dd_real::pown): Invalid argument."); + errno = EDOM; + return dd(SpecificValue::qnan); + } + return 1.0; + + case 1: + s = a; + break; + + case 2: + s = sqr(a); + + default: // Use binary exponentiation + { + dd r{ a }; + + s = 1.0; + while (N > 0) { + if (N % 2 == 1) { + s *= r; + } + N /= 2; + if (N > 0) r = sqr(r); + } + } + break; + } + + // Compute the reciprocal if n is negative. + return n < 0 ? reciprocal(s) : s; +} + +//////////////////////// stream operators ///////////////////////////////// + + +// stream out a decimal floating-point representation of the double-double +inline std::ostream& operator<<(std::ostream& ostr, const dd& v) { + std::ios_base::fmtflags fmt = ostr.flags(); + std::streamsize precision = ostr.precision(); + std::streamsize width = ostr.width(); + char fillChar = ostr.fill(); + bool showpos = fmt & std::ios_base::showpos; + bool uppercase = fmt & std::ios_base::uppercase; + bool fixed = fmt & std::ios_base::fixed; + bool scientific = fmt & std::ios_base::scientific; + bool internal = fmt & std::ios_base::internal; + bool left = fmt & std::ios_base::left; + return ostr << v.to_string(precision, width, fixed, scientific, internal, left, showpos, uppercase, fillChar); +} + +// stream in an ASCII decimal floating-point format and assign it to a double-double +inline std::istream& operator>>(std::istream& istr, dd& v) { + std::string txt; + istr >> txt; + if (!parse(txt, v)) { + std::cerr << "unable to parse -" << txt << "- into a double-double value\n"; + } + return istr; +} + +////////////////// string operators + +// parse a decimal ASCII floating-point format and make a doubledouble (dd) out of it +bool parse(const std::string& number, dd& value) { + char const* p = number.c_str(); + + // Skip any leading spaces + while (std::isspace(*p)) ++p; + + dd r{ 0.0 }; + int nrDigits{ 0 }; + int decimalPoint{ -1 }; + int sign{ 0 }, eSign{ 1 }; + int e{ 0 }; + bool done{ false }, parsingMantissa{ true }; + char ch; + while (!done && (ch = *p) != '\0') { + if (std::isdigit(ch)) { + if (parsingMantissa) { + int digit = ch - '0'; + r *= 10.0; + r += static_cast(digit); + ++nrDigits; + } + else { // parsing exponent section + int digit = ch - '0'; + e *= 10; + e += digit; + } + } + else { + switch (ch) { + case '.': + if (decimalPoint >= 0) return false; + decimalPoint = nrDigits; + break; + + case '-': + case '+': + if (parsingMantissa) { + if (sign != 0 || nrDigits > 0) return false; + sign = (ch == '-' ? -1 : 1); + } + else { + eSign = (ch == '-' ? -1 : 1); + } + break; + + case 'E': + case 'e': + parsingMantissa = false; + break; + + default: + return false; + } + } + + ++p; + } + e *= eSign; + + if (decimalPoint >= 0) e -= (nrDigits - decimalPoint); + dd _ten(10.0, 0.0); + if (e > 0) { + r *= pown(_ten, e); + } + else { + if (e < 0) r /= pown(_ten, -e); + } + value = (sign == -1) ? -r : r; + return true; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// dd - dd binary logic operators + +// equal: precondition is that the storage is properly nulled in all arithmetic paths +inline bool operator==(const dd& lhs, const dd& rhs) { + return (lhs.hi == rhs.hi) && (lhs.lo == rhs.lo); +} + +inline bool operator!=(const dd& lhs, const dd& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator< (const dd& lhs, const dd& rhs) { + if (lhs.hi < rhs.hi) { + return true; + } + else if (lhs.hi > rhs.hi) { + return false; + } + else { + // hi limbs are the same + if (lhs.lo < rhs.lo) { + return true; + } + else if (lhs.lo > rhs.lo) { + return false; + } + else { + // lhs and rhs are the same + return false; + } + } +} + +inline bool operator> (const dd& lhs, const dd& rhs) { + return operator< (rhs, lhs); +} + +inline bool operator<=(const dd& lhs, const dd& rhs) { + return operator< (lhs, rhs) || operator==(lhs, rhs); +} + +inline bool operator>=(const dd& lhs, const dd& rhs) { + return !operator< (lhs, rhs); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// dd - literal binary logic operators +// equal: precondition is that the byte-storage is properly nulled in all arithmetic paths +inline bool operator==(const dd& lhs, double rhs) { + return operator==(lhs, dd(rhs)); +} + +inline bool operator!=(const dd& lhs, double rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator< (const dd& lhs, double rhs) { + return operator<(lhs, dd(rhs)); +} + +inline bool operator> (const dd& lhs, double rhs) { + return operator< (dd(rhs), lhs); +} + +inline bool operator<=(const dd& lhs, double rhs) { + return operator< (lhs, rhs) || operator==(lhs, rhs); +} + +inline bool operator>=(const dd& lhs, double rhs) { + return !operator< (lhs, rhs); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// literal - dd binary logic operators +// precondition is that the byte-storage is properly nulled in all arithmetic paths + +inline bool operator==(double lhs, const dd& rhs) { + return operator==(dd(lhs), rhs); +} + +inline bool operator!=(double lhs, const dd& rhs) { + return !operator==(lhs, rhs); +} + +inline bool operator< (double lhs, const dd& rhs) { + return operator<(dd(lhs), rhs); +} + +inline bool operator> (double lhs, const dd& rhs) { + return operator< (rhs, lhs); +} + +inline bool operator<=(double lhs, const dd& rhs) { + return operator< (lhs, rhs) || operator==(lhs, rhs); +} + +inline bool operator>=(double lhs, const dd& rhs) { + return !operator< (lhs, rhs); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// dd - dd binary arithmetic operators +// BINARY ADDITION +inline dd operator+(const dd& lhs, const dd& rhs) { + dd sum = lhs; + sum += rhs; + return sum; +} +// BINARY SUBTRACTION +inline dd operator-(const dd& lhs, const dd& rhs) { + dd diff = lhs; + diff -= rhs; + return diff; +} +// BINARY MULTIPLICATION +inline dd operator*(const dd& lhs, const dd& rhs) { + dd mul = lhs; + mul *= rhs; + return mul; +} +// BINARY DIVISION +inline dd operator/(const dd& lhs, const dd& rhs) { + dd ratio = lhs; + ratio /= rhs; + return ratio; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// dd - literal binary arithmetic operators +// BINARY ADDITION +inline dd operator+(const dd& lhs, double rhs) { + return operator+(lhs, dd(rhs)); +} +// BINARY SUBTRACTION +inline dd operator-(const dd& lhs, double rhs) { + return operator-(lhs, dd(rhs)); +} +// BINARY MULTIPLICATION +inline dd operator*(const dd& lhs, double rhs) { + return operator*(lhs, dd(rhs)); +} +// BINARY DIVISION +inline dd operator/(const dd& lhs, double rhs) { + return operator/(lhs, dd(rhs)); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////// +// literal - dd binary arithmetic operators +// BINARY ADDITION +inline dd operator+(double lhs, const dd& rhs) { + return operator+(dd(lhs), rhs); +} +// BINARY SUBTRACTION +inline dd operator-(double lhs, const dd& rhs) { + return operator-(dd(lhs), rhs); +} +// BINARY MULTIPLICATION +inline dd operator*(double lhs, const dd& rhs) { + return operator*(dd(lhs), rhs); +} +// BINARY DIVISION +inline dd operator/(double lhs, const dd& rhs) { + return operator/(dd(lhs), rhs); +} + +}} // namespace sw::universal diff --git a/include/universal/number/dd/exceptions.hpp b/include/universal/number/dd/exceptions.hpp new file mode 100644 index 000000000..31f6d3ce1 --- /dev/null +++ b/include/universal/number/dd/exceptions.hpp @@ -0,0 +1,75 @@ +#pragma once +// exceptions.hpp: definition of arbitrary configuration doubledouble exceptions +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +namespace sw { namespace universal { + +// base class for doubledouble arithmetic exceptions +struct dd_arithmetic_exception : public universal_arithmetic_exception { + dd_arithmetic_exception(const std::string& err) : universal_arithmetic_exception(std::string("doubledouble arithmetic exception: ") + err) {}; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////// +/// specialized exceptions to aid application level exception handling + +// invalid_argument is thrown when a mathematical function argument is invalid +struct dd_invalid_argument : public dd_arithmetic_exception { + dd_invalid_argument() : dd_arithmetic_exception("invalid argument") {} +}; + +// not_a_number is thrown when a rvar is NaN +struct dd_not_a_number : public dd_arithmetic_exception { + dd_not_a_number() : dd_arithmetic_exception("not a number") {} +}; + +// divide by zero arithmetic exception for reals +struct dd_divide_by_zero : public dd_arithmetic_exception { + dd_divide_by_zero() : dd_arithmetic_exception("divide by zero") {} +}; + +// divide_by_nan is thrown when the denominator in a division operator is NaN +struct dd_divide_by_nan : public dd_arithmetic_exception { + dd_divide_by_nan() : dd_arithmetic_exception("divide by nan") {} +}; + +// operand_is_nan is thrown when an rvar in a binary operator is NaN +struct dd_operand_is_nan : public dd_arithmetic_exception { + dd_operand_is_nan() : dd_arithmetic_exception("operand is nan") {} +}; + +// negative argument to sqrt +struct dd_negative_sqrt_arg : public dd_arithmetic_exception { + dd_negative_sqrt_arg() : dd_arithmetic_exception("negative sqrt argument") {} +}; + +// negative argument to nroot +struct dd_negative_nroot_arg : public dd_arithmetic_exception { + dd_negative_nroot_arg() : dd_arithmetic_exception("negative nroot argument") {} +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/// REAL INTERNAL OPERATION EXCEPTIONS + +struct dd_internal_exception : public universal_internal_exception { + dd_internal_exception(const std::string& err) : universal_internal_exception(std::string("doubledouble internal exception: ") + err) {}; +}; + +struct dd_shift_too_large : public dd_internal_exception { + dd_shift_too_large() : dd_internal_exception("shift value too large for given doubledouble") {} +}; + +struct dd_hpos_too_large : public dd_internal_exception { + dd_hpos_too_large() : dd_internal_exception("position of hidden bit too large for given doubledouble") {} +}; + +//struct dd_rbits_too_large : dd_internal_exception { +// dd_rbits_too_large(const std::string& error = "number of remaining bits too large for this fraction") :dd_internal_exception(error) {} +//}; + +}} // namespace sw::universal diff --git a/include/universal/number/dd/manipulators.hpp b/include/universal/number/dd/manipulators.hpp new file mode 100644 index 000000000..f196e10ab --- /dev/null +++ b/include/universal/number/dd/manipulators.hpp @@ -0,0 +1,61 @@ +// manipulators.hpp: definitions of helper functions for doubledouble type manipulation +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +// pull in the color printing for shells utility +#include + +namespace sw { namespace universal { + + // Generate a type tag for a doubledouble + std::string type_tag(const dd& = {}) { + return std::string("doubledouble"); + } + + // generate a binary, color-coded representation of the doubledouble + std::string color_print(const dd& r, bool nibbleMarker = false) { + constexpr unsigned es = 11; + constexpr unsigned fbits = 106; + std::stringstream s; + bool sign{ false }; + blockbinary e{ 0 }; + blockbinary f{ 0 }; + sign = r.sign(); + e = r.exponent(); + uint128_t raw = r.fraction(); + f.setbits(raw.limb[0]); + + Color red(ColorCode::FG_RED); + Color yellow(ColorCode::FG_YELLOW); + Color blue(ColorCode::FG_BLUE); + Color magenta(ColorCode::FG_MAGENTA); + Color cyan(ColorCode::FG_CYAN); + Color white(ColorCode::FG_WHITE); + Color def(ColorCode::FG_DEFAULT); + + // sign bit + s << red << (sign ? '1' : '0'); + + // exponent bits + for (int i = int(es) - 1; i >= 0; --i) { + s << cyan << (e.test(static_cast(i)) ? '1' : '0'); + if ((i - es) > 0 && ((i - es) % 4) == 0 && nibbleMarker) s << yellow << '\''; + } + + // fraction bits + for (int i = int(fbits) - 1; i >= 0; --i) { + s << magenta << (f.test(static_cast(i)) ? '1' : '0'); + if (i > 0 && (i % 4) == 0 && nibbleMarker) s << yellow << '\''; + } + + s << def; + return s.str(); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/classify.hpp b/include/universal/number/dd/math/classify.hpp new file mode 100644 index 000000000..d9ff3bc7e --- /dev/null +++ b/include/universal/number/dd/math/classify.hpp @@ -0,0 +1,55 @@ +#pragma once +// classify.hpp: classification functions for doubledouble (dd) floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + +// STD LIB function for IEEE floats: Categorizes floating point value arg into the following categories: zero, subnormal, normal, infinite, NAN, or implementation-defined category. +int fpclassify(const dd& a) { + return (std::fpclassify(a.high())); +} + +// STD LIB function for IEEE floats: Determines if the given floating point number arg is a cfloative or negative infinity. +// specialized for doubledouble (dd) +inline bool isinf(const dd& a) { + return (std::fpclassify(a.high()) == FP_INFINITE); +} + +// STD LIB function for IEEE floats: Determines if the given floating point number arg is a not-a-number (NaN) value. +// specialized for doubledouble (dd) +inline bool isnan(const dd& a) { + return (std::fpclassify(a.high()) == FP_NAN); +} + +// STD LIB function for IEEE floats: Determines if the given floating point number arg has finite value i.e. it is normal, subnormal or zero, but not infinite or NaN. +// specialized for doubledouble (dd) +inline bool isfinite(const dd& a) { + return (std::fpclassify(a.high()) != FP_INFINITE) && (std::fpclassify(a.high()) != FP_NAN); +} + +// STD LIB function for IEEE floats: Determines if the given floating point number arg is normal, i.e. is neither zero, subnormal, infinite, nor NaN. +// specialized for doubledouble (dd) +inline bool isnormal(const dd& a) { + return (std::fpclassify(a.high()) == FP_NORMAL); +} + +// STD LIB function for IEEE floats: Determines if the given floating point number arg is denormal, i.e. is neither zero, normal, infinite, nor NaN. +// specialized for doubledouble (dd) +inline bool isdenorm(const dd& a) { + return (std::fpclassify(a.high()) == FP_SUBNORMAL); +} + +inline bool iszero(const dd& a) { + return (std::fpclassify(a.high()) == FP_ZERO); +} + +bool signbit(dd const& a) { + auto signA = std::copysign(1.0, a.high()); + return signA < 0.0; +} + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/complex.hpp b/include/universal/number/dd/math/complex.hpp new file mode 100644 index 000000000..79adf6c46 --- /dev/null +++ b/include/universal/number/dd/math/complex.hpp @@ -0,0 +1,12 @@ +#pragma once +// complex.hpp: complex support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/error_and_gamma.hpp b/include/universal/number/dd/math/error_and_gamma.hpp new file mode 100644 index 000000000..663df96b0 --- /dev/null +++ b/include/universal/number/dd/math/error_and_gamma.hpp @@ -0,0 +1,21 @@ +#pragma once +// error_and_gamma.hpp: error/gamma function support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + // Compute the error function erf(x) = 2 over sqrt(PI) times Integral from 0 to x of e ^ (-t)^2 dt + dd erf(dd x) { + return dd(std::erf(double(x.high()))); + } + + // Compute the complementary error function: 1 - erf(x) + dd erfc(dd x) { + return dd(std::erfc(double(x.high()))); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/exponent.hpp b/include/universal/number/dd/math/exponent.hpp new file mode 100644 index 000000000..81f10a900 --- /dev/null +++ b/include/universal/number/dd/math/exponent.hpp @@ -0,0 +1,100 @@ +#pragma once +// exponent.hpp: exponent functions for double-double floating-point +// +// algorithms courtesy Scibuilders, Jack Poulson +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + // fwd reference + dd ldexp(dd const&, int); + +static const int n_inv_fact = 15; +static const double inv_fact[n_inv_fact][2] = { + { 1.66666666666666657e-01, 9.25185853854297066e-18}, + { 4.16666666666666644e-02, 2.31296463463574266e-18}, + { 8.33333333333333322e-03, 1.15648231731787138e-19}, + { 1.38888888888888894e-03, -5.30054395437357706e-20}, + { 1.98412698412698413e-04, 1.72095582934207053e-22}, + { 2.48015873015873016e-05, 2.15119478667758816e-23}, + { 2.75573192239858925e-06, -1.85839327404647208e-22}, + { 2.75573192239858883e-07, 2.37677146222502973e-23}, + { 2.50521083854417202e-08, -1.44881407093591197e-24}, + { 2.08767569878681002e-09, -1.20734505911325997e-25}, + { 1.60590438368216133e-10, 1.25852945887520981e-26}, + { 1.14707455977297245e-11, 2.06555127528307454e-28}, + { 7.64716373181981641e-13, 7.03872877733453001e-30}, + { 4.77947733238738525e-14, 4.39920548583408126e-31}, + { 2.81145725434552060e-15, 1.65088427308614326e-31} +}; + +// Base-e exponential function +dd exp(const dd& a) { + /* Strategy: We first reduce the size of x by noting that + + exp(kr + m * log(2)) = 2^m * exp(r)^k + + where m and k are integers. By choosing m appropriately + we can make |kr| <= log(2) / 2 = 0.347. Then exp(r) is + evaluated using the familiar Taylor series. Reducing the + argument substantially speeds up the convergence. */ + + const double k = 512.0; + const double inv_k = 1.0 / k; + + if (a.high() <= -709.0) return dd(0.0); + + if (a.high() >= 709.0) return dd(SpecificValue::infpos); + + if (a.iszero()) return dd(1.0); + + if (a.isone()) return dd_e; + + double m = std::floor(a.high() / dd_log2.high() + 0.5); + dd r = mul_pwr2(a - dd_log2 * m, inv_k); + dd s, t, p; + + p = sqr(r); + s = r + mul_pwr2(p, 0.5); + p *= r; + t = p * dd(inv_fact[0][0], inv_fact[0][1]); + int i = 0; + do { + s += t; + p *= r; + ++i; + t = p * dd(inv_fact[i][0], inv_fact[i][1]); + } while (std::abs(double(t)) > inv_k * dd_eps && i < 5); + + s += t; + + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s = mul_pwr2(s, 2.0) + sqr(s); + s += 1.0; + + return ldexp(s, static_cast(m)); +} + + +// Base-2 exponential function + +// Base-10 exponential function + +// Base-e exponential function exp(x)-1 +dd expm1(dd x) { + return dd(std::expm1(double(x))); +} + + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/fractional.hpp b/include/universal/number/dd/math/fractional.hpp new file mode 100644 index 000000000..15148342e --- /dev/null +++ b/include/universal/number/dd/math/fractional.hpp @@ -0,0 +1,21 @@ +#pragma once +// fractional.hpp: fractional support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + // fmod retuns x - n*y where n = x/y with the fractional part truncated + dd fmod(dd x, dd y) { + return dd(std::fmod(double(x), double(y))); + } + + // shim to stdlib + dd remainder(dd x, dd y) { + return dd(std::remainder(double(x), double(y))); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/hyperbolic.hpp b/include/universal/number/dd/math/hyperbolic.hpp new file mode 100644 index 000000000..1793be766 --- /dev/null +++ b/include/universal/number/dd/math/hyperbolic.hpp @@ -0,0 +1,41 @@ +#pragma once +// hyperbolic.hpp: hyperbolic function support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + // hyperbolic sine of an angle of x radians + dd sinh(dd x) { + return dd(std::sinh(double(x))); + } + + // hyperbolic cosine of an angle of x radians + dd cosh(dd x) { + return dd(std::cosh(double(x))); + } + + // hyperbolic tangent of an angle of x radians + dd tanh(dd x) { + return dd(std::tanh(double(x))); + } + + // hyperbolic cotangent of an angle of x radians + dd atanh(dd x) { + return dd(std::atanh(double(x))); + } + + // hyperbolic cosecant of an angle of x radians + dd acosh(dd x) { + return dd(std::acosh(double(x))); + } + + // hyperbolic secant of an angle of x radians + dd asinh(dd x) { + return dd(std::asinh(double(x))); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/hypot.hpp b/include/universal/number/dd/math/hypot.hpp new file mode 100644 index 000000000..99bcc4636 --- /dev/null +++ b/include/universal/number/dd/math/hypot.hpp @@ -0,0 +1,15 @@ +#pragma once +// hypot.hpp: hypot support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + dd hypot(dd x, dd y) { + return dd(std::hypot(double(x), double(y))); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/logarithm.hpp b/include/universal/number/dd/math/logarithm.hpp new file mode 100644 index 000000000..37d0fee86 --- /dev/null +++ b/include/universal/number/dd/math/logarithm.hpp @@ -0,0 +1,209 @@ +#pragma once +// logarithm.hpp: logarithm functions for doubledouble (dd) floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +namespace sw { namespace universal { + + + +// assumes 0.0 < a < inf +dd _log(dd const& a) { +#ifdef LATER + int k; + dd f = std::frexp(a, &k); // 0.5 <= |f| < 1.0 + if (f < _inv_sqrt2) { + f = std::ldexp(f, 1); + --k; + } + + // sqrt( 0.5 ) <= f < sqrt( 2.0 ) + // -0.1715... <= s < 0.1715... + // + double res[3]; + res[0] = two_sum(f.high(), 1.0, res[1]); + res[1] = two_sum(f.high(), res[1], res[2]); + dd f_plus = res[0] == 0.0 ? dd(res[1], res[2]) : dd(res[0], res[1]); + res[0] = two_sum(f.high(), -1.0, res[1]); + res[1] = two_sum(f.low(), res[1], res[2]); + dd f_minus = res[0] == 0.0 ? dd_real(res[1], res[2]) : dd(res[0], res[1]); + + dd s = f_minus / f_plus; + + // calculate log( f ) = log( 1 + s ) - log( 1 - s ) + // + // log( 1+s ) = s - s^2/2 + s^3/3 - s^4/4 ... + // log( 1-s ) = -s + s^2/2 - s^3/3 - s^4/4 ... + // log( f ) = 2*s + 2s^3/3 + 2s^5/5 + ... + // + dd s2 = s * s; + + // TODO - economize the power series using Chebyshev polynomials + // + dd x = inv_int[41]; + for (int i = 41; i > 1; i -= 2) { + x = std::Fma(x, s2, inv_int[i - 2]); + } + x *= std::ldexp(s, 1); // x *= 2*s + + return std::Fma(k, _ln2, x); +#endif + return dd(std::log(a.high()), 0.0); +} + +// assumes -1.0 < a < 2.0 +// +dd _log1p(dd const& a) { +#ifdef LATER + static const dd a_max = _sqrt2 - 1.0; + static const dd a_min = _inv_sqrt2 - 1.0; + + int ilog = std::ilogb(a) + 1; // 0.5 <= frac < 1.0 + + if (ilog < -std::numeric_limits
::digits / 2) // |a| <= 2^-54 - error O( 2^-108) + return a; + if (ilog < -std::numeric_limits
::digits / 3) // |a| <= 2^-36 - error O( 2^-108) + return a * std::Fma(a, -0.5, 1.0); + if (ilog < -std::numeric_limits
::digits / 4) // |a| <= 2^-27 - error O( 2^-108) + return a * std::Fma(a, -std::Fma(a, -_third, 0.5), 1.0); + + dd f_minus = a; + int k = 0; + + if ((a > a_max) || (a < a_min)) + { + double res[3]; + res[0] = two_sum(a.high(), 1.0, res[1]); + res[1] = two_sum(a.low(), res[1], res[2]); + dd f_p1 = res[0] == 0.0 ? dd(res[1], res[2]) : dd_real(res[0], res[1]); + + f_p1 = std::frexp(f_p1, &k); // 0.5 <= |f_p1| < 1.0; k <= 2 + if (f_p1 < _inv_sqrt2) { + --k; + std::ldexp(f_p1, 1); + } + + // at this point, we have 2^k * ( 1.0 + f ) = 1.0 + a + // sqrt( 0.5 ) <= 1.0 + f <= sqrt( 2.0 ) + // + // f = 2^-k * a - ( 1.0 - 2^-k ) + double df[2]; + df[0] = two_sum(1.0, -std::ldexp(1.0, -k), df[1]); + f_minus = std::ldexp(a, -k) - dd_real(df[0], df[1]); + } + + dd f_plus = f_minus + 2.0; + dd s = f_minus / f_plus; + + // calculate log( f ) = log( 1 + s ) - log( 1 - s ) + // + // log( 1+s ) = s - s^2/2 + s^3/3 - s^4/4 ... + // log( 1-s ) = -s + s^2/2 - s^3/3 - s^4/4 ... + // log( f ) = 2*s + 2s^3/3 + 2s^5/5 + ... + // + dd s2 = s * s; + + // TODO - economize the power series using Chebyshev polynomials + // + dd x = inv_int[41]; + for (int i = 41; i > 1; i -= 2) { + x = std::Fma(x, s2, inv_int[i - 2]); + } + x *= std::ldexp(s, 1); // x *= 2*s + + return std::Fma(k, _ln2, x); +#endif + return dd(std::log1p(a.high()), 0.0); +} + +// Natural logarithm of x +dd log(dd const& a) { + if (a.isnan()) return a; + + if (a.iszero()) return -std::numeric_limits< dd >::infinity(); + + if (a.isone()) return 0.0; + + if (a.sign()) { +// error("(dd::log): Non-positive argument."); + errno = EDOM; + return std::numeric_limits< dd >::quiet_NaN(); + } + + if (a.isinf()) return a; + + return _log(a); +} + +// Binary logarithm of x +dd log2(dd const& a) +{ + if (a.isnan()) return a; + + if (a.iszero()) return -std::numeric_limits< dd >::infinity(); + + if (a.isone()) return 0.0; + + if (a.sign()) { +// error("(dd_real::log2): Non-positive argument."); + errno = EDOM; + return std::numeric_limits< dd >::quiet_NaN(); + } + + if (a.isinf()) return a; + + dd _lge{}; + return _lge * _log(a); +} + +// Decimal logarithm of x +dd log10(dd const& a) { + if (a.isnan()) return a; + + if (a.iszero()) return -std::numeric_limits< dd >::infinity(); + + if (a.isone()) return 0.0; + + if (a.sign()) { +// error("(dd_real::log10): Non-positive argument."); + errno = EDOM; + return std::numeric_limits< dd >::quiet_NaN(); + } + + if (a.isinf()) return a; + + dd _loge{}; + return _loge * _log(a); +} + +// Natural logarithm of 1+x +dd log1p(dd const& a) +{ + if (a.isnan()) return a; + + if (a.iszero()) return 0.0; + + if (a == -1.0) return -std::numeric_limits< dd >::infinity(); + + if (a < -1.0) { +// error("(dd_real::log): Non-positive argument."); + errno = EDOM; + return std::numeric_limits< dd >::quiet_NaN(); + } + + if (a.isinf()) return a; + + + if ((a >= 2.0) || (a <= -0.5)) // a >= 2.0 - no loss of significant bits - use log() + return _log(1.0 + a); + + // at this point, -1.0 < a < 2.0 + // + return _log1p(a); +} + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/minmax.hpp b/include/universal/number/dd/math/minmax.hpp new file mode 100644 index 000000000..a4771bde8 --- /dev/null +++ b/include/universal/number/dd/math/minmax.hpp @@ -0,0 +1,19 @@ +#pragma once +// minmax.hpp: minmax support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + dd min(dd x, dd y) { + return dd(std::min(double(x), double(y))); + } + + dd max(dd x, dd y) { + return dd(std::max(double(x), double(y))); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/next.hpp b/include/universal/number/dd/math/next.hpp new file mode 100644 index 000000000..9c2e54e7f --- /dev/null +++ b/include/universal/number/dd/math/next.hpp @@ -0,0 +1,73 @@ +#pragma once +// next.hpp: nextafter/nexttoward functions for doubledouble floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + +/* +Parameters + x Base value. + t Value toward which the return value is approximated. +If both parameters compare equal, the function returns t. + +Return Value + The next representable value after x in the direction of t. + + If x is the largest finite value representable in the type, + and the result is infinite or not representable, an overflow range error occurs. + + If an overflow range error occurs: + - And math_errhandling has MATH_ERRNO set: the global variable errno is set to ERANGE. + - And math_errhandling has MATH_ERREXCEPT set: FE_OVERFLOW is raised. + */ +dd nextafter(dd x, dd target) { + if (x == target) return target; + if (target.isnan()) { + if (x.isneg()) { + --x; + } + else { + ++x; + } + } + else { + if (x > target) { + --x; + } + else { + ++x; + } + } + return x; +} + +/* TODO +dd nexttoward(dd x, dd target) { + double _x(x); + if (_x == target) return x; + if (target.isnan()) { + if (_x.isneg()) { + --_x; + } + else { + ++_x; + } + } + else { + if (_x > target) { + --_x; + } + else { + ++_x; + } + } + x = _x; + return x; +} +*/ + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/numerics.hpp b/include/universal/number/dd/math/numerics.hpp new file mode 100644 index 000000000..c3a473630 --- /dev/null +++ b/include/universal/number/dd/math/numerics.hpp @@ -0,0 +1,38 @@ +#pragma once +// numerics.hpp: numerics functions for double-double (dd) floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +namespace sw { namespace universal { + + // clang implementation is calling these functions so we need implementations for doubledouble (dd) + + + // copysign returns a value with the magnitude of a, and the sign of b + dd copysign(dd const& a, dd const& b) { + auto signA = std::copysign(1.0, a.high()); + auto signB = std::copysign(1.0, b.high()); + + return signA != signB ? -a : a; + } + + // decompose doubledouble into a fraction and an exponent + dd frexp(dd const& a, int* pexp) { + double hi = std::frexp(a.high(), pexp); + double lo = std::ldexp(a.low(), -*pexp); + return dd(hi, lo); + } + + // recompose doubledouble from a fraction and an exponent + dd ldexp(dd const& a, int exp) { + static_assert(std::numeric_limits< dd >::radix == 2, "CONFIGURATION: dd radix must be 2!"); + static_assert(std::numeric_limits< double >::radix == 2, "CONFIGURATION: double radix must be 2!"); + + return dd(std::ldexp(a.high(), exp), std::ldexp(a.low(), exp)); + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/pow.hpp b/include/universal/number/dd/math/pow.hpp new file mode 100644 index 000000000..285a8263e --- /dev/null +++ b/include/universal/number/dd/math/pow.hpp @@ -0,0 +1,69 @@ +#pragma once +// pow.hpp: pow functions for double-double (dd) floating-point +// +// algorithms courtesy Scibuilders, Jack Poulson +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +namespace sw { namespace universal { + + // fwd reference + dd exp(const dd&); + + // power function + dd pow(const dd& a, const dd& b) { + return exp(b * log(a)); + } + + // power function of a dd to double + dd pow(dd x, double y) { + return pow(x, dd(y)); + } + + // Computes the n-th power of a double-double number. + // NOTE: 0^0 causes an error. + dd npwr(const dd& a, int n) { + if (n == 0) { +#if DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (a.iszero()) throw dd_invalid_argument(); +#else // ! DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (a.iszero()) { + std::cerr << "(npwr): Invalid argument\n"; + return dd(SpecificValue::snan); + } +#endif // ! DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + return 1.0; + } + + dd r = a; + dd s = 1.0; + int N = std::abs(n); + + if (N > 1) { + // Use binary exponentiation + while (N > 0) { + if (N % 2 == 1) { + s *= r; + } + N /= 2; + if (N > 0) r = sqr(r); + } + } else { + s = r; + } + + // if n is negative then compute the reciprocal + if (n < 0) return (1.0 / s); + return s; + } + + dd pow(const dd& a, int n) { + return npwr(a, n); + } + + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/sqrt.hpp b/include/universal/number/dd/math/sqrt.hpp new file mode 100644 index 000000000..f75315a3a --- /dev/null +++ b/include/universal/number/dd/math/sqrt.hpp @@ -0,0 +1,120 @@ +#pragma once +// sqrt.hpp: sqrt functions for doubledouble (dd) floats +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +#ifndef DOUBLEDOUBLE_NATIVE_SQRT +#define DOUBLEDOUBLE_NATIVE_SQRT 1 +#endif + +namespace sw { namespace universal { + +#if DOUBLEDOUBLE_NATIVE_SQRT + + /* Computes the square root of the double-double number dd. + NOTE: dd must be a non-negative number. */ + inline dd sqrt(const dd& a) { + /* Strategy: Use Karp's trick: if x is an approximation + to sqrt(a), then + + sqrt(a) = a*x + [a - (a*x)^2] * x / 2 (approx) + + The approximation is accurate to twice the accuracy of x. + Also, the multiplication (a*x) and [-]*x can be done with + only half the precision. + */ + + if (a.iszero()) return dd{}; + +#if DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (a.isneg()) throw dd_negative_sqrt_arg(); +#else + if (a.isneg()) std::cerr << "doubledouble argument to sqrt is negative: " << a << std::endl; +#endif + + double x = 1.0 / std::sqrt(a.high()); + double ax = a.high() * x; + return add(ax, (a - sqr(dd(ax))).high() * (x * 0.5)); + } + +#else + + // sqrt shim for doubledouble + inline dd sqrt(dd a) { +#if DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (a.isneg()) throw dd_negative_sqrt_arg(); +#else // ! DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (a.isneg()) std::cerr << "doubledouble argument to sqrt is negative: " << a << std::endl; +#endif // ! DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (a.iszero()) return a; + return dd(std::sqrt(a.high())); + } + +#endif // ! DOUBLEDOUBLE_NATIVE_SQRT + + // Computes the square root of a double in double-double precision. + dd sqrt(double d) { + return sw::universal::sqrt(dd(d)); + } + + // reciprocal sqrt + inline dd rsqrt(dd a) { + dd v = sw::universal::sqrt(a); + return reciprocal(v); + } + + + /* Computes the n-th root of the double-double number a. + NOTE: n must be a positive integer. + NOTE: If n is even, then a must not be negative. */ + dd nroot(const dd& a, int n) { + /* Strategy: Use Newton iteration for the function + + f(x) = x^(-n) - a + + to find its root a^{-1/n}. The iteration is thus + + x' = x + x * (1 - a * x^n) / n + + which converges quadratically. We can then find + a^{1/n} by taking the reciprocal. + */ + +#if DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (n <= 0) throw dd_negative_nroot_arg(); + + if (n % 2 == 0 && a.isneg()) throw dd_negative_nroot_arg(); + +#else // ! DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + if (n <= 0) { + std::cerr << "doubledouble nroot argument is negative: " << n << std::endl; + } + + if (n % 2 == 0 && a.isneg()) { + std::cerr << "doubledouble nroot argument is negative: " << n << std::endl; + return dd(SpecificValue::snan); + } + +#endif // ! DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION + + if (n == 1) return a; + if (n == 2) return sqrt(a); + + if (a.iszero()) return dd(0.0); + + // Note a^{-1/n} = exp(-log(a)/n) + dd r = abs(a); + dd x = std::exp(-std::log(r.high()) / n); + + // Perform Newton's iteration. + x += x * (1.0 - r * npwr(x, n)) / static_cast(n); + if (a.high() < 0.0) x = -x; + + return 1.0/x; + } + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/trigonometry.hpp b/include/universal/number/dd/math/trigonometry.hpp new file mode 100644 index 000000000..38da2c8db --- /dev/null +++ b/include/universal/number/dd/math/trigonometry.hpp @@ -0,0 +1,12 @@ +#pragma once +// trigonometry.hpp: trigonometry support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + +}} // namespace sw::universal diff --git a/include/universal/number/dd/math/truncate.hpp b/include/universal/number/dd/math/truncate.hpp new file mode 100644 index 000000000..85fed9e30 --- /dev/null +++ b/include/universal/number/dd/math/truncate.hpp @@ -0,0 +1,24 @@ +#pragma once +// truncate.hpp: truncate support for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + + // Truncate value by rounding toward zero, returning the nearest integral value that is not larger in magnitude than x + dd trunc(dd x) { + return dd(std::trunc(double(x))); + } + + // Round to nearest: returns the integral value that is nearest to x, with halfway cases rounded away from zero + dd round(dd x) { + return dd(std::round(double(x))); + } + + + // floor and ceil are being used in the class definition and are defined in that file + +}} // namespace sw::universal diff --git a/include/universal/number/dd/mathlib.hpp b/include/universal/number/dd/mathlib.hpp new file mode 100644 index 000000000..982b15611 --- /dev/null +++ b/include/universal/number/dd/mathlib.hpp @@ -0,0 +1,24 @@ +#pragma once +// mathlib.hpp: definition of mathematical functions for the double-double floats +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/include/universal/number/dd/numeric_limits.hpp b/include/universal/number/dd/numeric_limits.hpp new file mode 100644 index 000000000..8e8643ce7 --- /dev/null +++ b/include/universal/number/dd/numeric_limits.hpp @@ -0,0 +1,82 @@ +#pragma once +// numeric_limits.hpp: definition of numeric_limits for doubledouble types +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +namespace std { + +template<> +class numeric_limits< sw::universal::dd > { +public: + using DoubleDouble = sw::universal::dd; + static constexpr bool is_specialized = true; + static constexpr DoubleDouble min() { // return minimum value + // return DoubleDouble(sw::universal::SpecificValue::minpos); + return DoubleDouble(radix * (numeric_limits< double >::min() / numeric_limits< double >::epsilon())); + } + static constexpr DoubleDouble max() { // return maximum value + //return DoubleDouble(sw::universal::SpecificValue::maxpos); + return DoubleDouble(numeric_limits< double >::max()); + } + static constexpr DoubleDouble lowest() { // return most negative value + //return DoubleDouble(sw::universal::SpecificValue::maxneg); + return (-(max)()); + } + static constexpr DoubleDouble epsilon() { // return smallest effective increment from 1.0 + return numeric_limits< double >::epsilon() * numeric_limits< double >::epsilon() / radix; + } + static constexpr DoubleDouble round_error() { // return largest rounding error + return DoubleDouble(1.0 / radix); + } + static constexpr DoubleDouble denorm_min() { // return minimum denormalized value + // return DoubleDouble(sw::universal::SpecificValue::minpos); + return 0.0; + } + static constexpr DoubleDouble infinity() { // return positive infinity + return DoubleDouble(sw::universal::SpecificValue::infpos); + //return numeric_limits< double >::infinity(); + } + static constexpr DoubleDouble quiet_NaN() { // return non-signaling NaN + return DoubleDouble(sw::universal::SpecificValue::qnan); + //return numeric_limits< double >::quiet_NaN(); + } + static constexpr DoubleDouble signaling_NaN() { // return signaling NaN + return DoubleDouble(sw::universal::SpecificValue::snan); + //return numeric_limits< double >::signaling_NaN(); + } + + static constexpr int digits = 2 * std::numeric_limits::digits; + static constexpr int digits10 = static_cast(digits * 0.30103); + static constexpr int max_digits10 = digits10; + static constexpr bool is_signed = true; + static constexpr bool is_integer = false; + static constexpr bool is_exact = false; + static constexpr int radix = 2; + + // C++ specification: min_exponent is one more than the smallest negative power + // of the radix that is a valid normalized number + static constexpr int min_exponent = DoubleDouble::MIN_EXP_NORMAL + 1; + static constexpr int min_exponent10 = static_cast(min_exponent * 0.30103); + // C++ specification: max_exponent is one more than the largest integer power + // of the radix that is a valid finite floating-point number + static constexpr int max_exponent = DoubleDouble::MAX_EXP; + static constexpr int max_exponent10 = static_cast(max_exponent * 0.30103); + static constexpr bool has_infinity = true; + static constexpr bool has_quiet_NaN = true; + static constexpr bool has_signaling_NaN = true; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr bool has_denorm_loss = false; + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = false; + static constexpr bool is_modulo = false; + static constexpr bool traps = false; + static constexpr bool tinyness_before = false; + static constexpr float_round_style round_style = round_toward_zero; +}; + +} diff --git a/include/universal/number/dfloat/attributes.hpp b/include/universal/number/dfloat/attributes.hpp new file mode 100644 index 000000000..1596139c2 --- /dev/null +++ b/include/universal/number/dfloat/attributes.hpp @@ -0,0 +1,71 @@ +#pragma once +// attributes.hpp: information functions for decimal floating-point type and value attributes +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. + +namespace sw { namespace universal { + +// functions to provide details about +// the properties of a dfloat configuration +// in terms of native types. + +// generate the maxneg through maxpos value range of a dfloat configuration +// TODO: needs SFINAE +template +std::string dfloat_range() { + constexpr unsigned ndigits = DfloatConfiguration::nbits; + constexpr unsigned es = DfloatConfiguration::es; + using BlockType = typename DfloatConfiguration::BlockType; + + using Dfloat = dfloat; + Dfloat v; + std::stringstream s; + s << std::setw(80) << type_tag(v) << " : [ " + << v.maxneg() << " ... " + << v.minneg() << " " + << "0 " + << v.minpos() << " ... " + << v.maxpos() << " ]"; + return s.str(); +} + + +// report dynamic range of a type, specialized for a dfloat +template +std::string dynamic_range(const dfloat& a) { + std::stringstream s; + dfloat b(SpecificValue::maxneg), c(SpecificValue::minneg), d(SpecificValue::minpos), e(SpecificValue::maxpos); + s << type_tag(a) << ": "; + s << "minpos scale " << std::setw(10) << d.scale() << " "; + s << "maxpos scale " << std::setw(10) << e.scale() << '\n'; + s << "[" << b << " ... " << c << ", -0, +0, " << d << " ... " << e << "]\n"; + s << "[" << to_binary(b) << " ... " << to_binary(c) << ", -0, +0, " << to_binary(d) << " ... " << to_binary(e) << "]\n"; + dfloat ninf(SpecificValue::infneg), pinf(SpecificValue::infpos); + s << "inclusive range = (" << to_binary(ninf) << ", " << to_binary(pinf) << ")\n"; + s << "inclusive range = (" << ninf << ", " << pinf << ")\n"; + return s.str(); +} + + +template +int minpos_scale(const dfloat& b) { + dfloat c(b); + return c.minpos().scale(); +} + +template +int maxpos_scale(const dfloat& b) { + dfloat c(b); + return c.maxpos().scale(); +} + +template +int max_negative_scale(const dfloat& b) { + dfloat c(b); + return c.maxneg().scale(); +} + +}} // namespace sw::universal diff --git a/include/universal/number/dfloat/dfloat.hpp b/include/universal/number/dfloat/dfloat.hpp index 963495f32..d06fdafb3 100644 --- a/include/universal/number/dfloat/dfloat.hpp +++ b/include/universal/number/dfloat/dfloat.hpp @@ -1,18 +1,18 @@ // arbitrary configuration decimal floating-point arithmetic standard header // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. -#ifndef _CFLOAT_STANDARD_HEADER_ -#define _CFLOAT_STANDARD_HEADER_ +#ifndef _DFLOAT_STANDARD_HEADER_ +#define _DFLOAT_STANDARD_HEADER_ //////////////////////////////////////////////////////////////////////////////////////// /// COMPILATION DIRECTIVES TO DIFFERENT COMPILERS - -// compiler specific configuration for long double support -#include -// compiler specific configuration for C++20 bit_cast +#include +#include #include +#include //////////////////////////////////////////////////////////////////////////////////////// /// required std libraries @@ -30,11 +30,18 @@ #endif //////////////////////////////////////////////////////////////////////////////////////// -// enable throwing specific exceptions for integer arithmetic errors +// enable throwing specific exceptions for arithmetic errors // left to application to enable #if !defined(DFLOAT_THROW_ARITHMETIC_EXCEPTION) // default is to use std::cerr for signalling an error #define DFLOAT_THROW_ARITHMETIC_EXCEPTION 0 +#define DFLOAT_EXCEPT noexcept +#else +#if DFLOAT_THROW_ARITHMETIC_EXCEPTION +#define DFLOAT_EXCEPT +#else +#define DFLOAT_EXCEPT noexcept +#endif #endif //////////////////////////////////////////////////////////////////////////////////////// @@ -44,6 +51,12 @@ #define DFLOAT_NATIVE_SQRT 0 #endif +/////////////////////////////////////////////////////////////////////////////////////// +// bring in the trait functions +#include +#include +#include + //////////////////////////////////////////////////////////////////////////////////////// /// INCLUDE FILES that make up the library #include @@ -53,7 +66,7 @@ //#include // useful functions to work with cfloats -//#include +#include #include /////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/universal/number/dfloat/dfloat_fwd.hpp b/include/universal/number/dfloat/dfloat_fwd.hpp index f106fd7ef..2dca619da 100644 --- a/include/universal/number/dfloat/dfloat_fwd.hpp +++ b/include/universal/number/dfloat/dfloat_fwd.hpp @@ -1,7 +1,8 @@ #pragma once // dfloat_fwd.hpp : forward declarations of the decimal floating-point dfloat environment // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -11,14 +12,6 @@ namespace sw { namespace universal { // forward references template class dfloat; - template - dfloat& - convert(NativeFloat v, dfloat& result); - - template - dfloat& - convert_unsigned(std::uint64_t v, dfloat& result); - template bool parse(const std::string& number, dfloat& v); diff --git a/include/universal/number/dfloat/dfloat_impl.hpp b/include/universal/number/dfloat/dfloat_impl.hpp index 9c4616010..1ff2bced2 100644 --- a/include/universal/number/dfloat/dfloat_impl.hpp +++ b/include/universal/number/dfloat/dfloat_impl.hpp @@ -1,7 +1,8 @@ #pragma once // dfloat_impl.hpp: implementation of a fixed-size, arbitrary configuration decimal floating-point number system // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -11,6 +12,12 @@ #include #include +// supporting types and functions +#include +#include +#include +#include +// dfloat exception structure #include namespace sw { namespace universal { @@ -43,35 +50,73 @@ class dfloat { dfloat& operator=(const dfloat&) = default; dfloat& operator=(dfloat&&) = default; + // converting constructors + constexpr dfloat(const std::string& stringRep) : _block{} { assign(stringRep); } + + // specific value constructor + constexpr dfloat(const SpecificValue code) noexcept : _block{} { + switch (code) { + case SpecificValue::maxpos: + maxpos(); + break; + case SpecificValue::minpos: + minpos(); + break; + case SpecificValue::zero: + default: + zero(); + break; + case SpecificValue::minneg: + minneg(); + break; + case SpecificValue::maxneg: + maxneg(); + break; + case SpecificValue::infpos: + setinf(false); + break; + case SpecificValue::infneg: + setinf(true); + break; + case SpecificValue::nar: // approximation as dfloats don't have a NaR + case SpecificValue::qnan: + setnan(NAN_TYPE_QUIET); + break; + case SpecificValue::snan: + setnan(NAN_TYPE_SIGNALLING); + break; + } + } + // initializers for native types - explicit dfloat(const signed char initial_value) { *this = initial_value; } - explicit dfloat(const short initial_value) { *this = initial_value; } - explicit dfloat(const int initial_value) { *this = initial_value; } - explicit dfloat(const long initial_value) { *this = initial_value; } - explicit dfloat(const long long initial_value) { *this = initial_value; } - explicit dfloat(const char initial_value) { *this = initial_value; } - explicit dfloat(const unsigned short initial_value) { *this = initial_value; } - explicit dfloat(const unsigned int initial_value) { *this = initial_value; } - explicit dfloat(const unsigned long initial_value) { *this = initial_value; } - explicit dfloat(const unsigned long long initial_value) { *this = initial_value; } - explicit dfloat(const float initial_value) { *this = initial_value; } - explicit dfloat(const double initial_value) { *this = initial_value; } - explicit dfloat(const long double initial_value) { *this = initial_value; } + explicit dfloat(signed char iv) { *this = iv; } + explicit dfloat(short iv) { *this = iv; } + explicit dfloat(int iv) { *this = iv; } + explicit dfloat(long iv) { *this = iv; } + explicit dfloat(long long iv) { *this = iv; } + explicit dfloat(char iv) { *this = iv; } + explicit dfloat(unsigned short iv) { *this = iv; } + explicit dfloat(unsigned int iv) { *this = iv; } + explicit dfloat(unsigned long iv) { *this = iv; } + explicit dfloat(unsigned long long iv) { *this = iv; } + explicit dfloat(float iv) { *this = iv; } + explicit dfloat(double iv) { *this = iv; } + explicit dfloat(long double iv) { *this = iv; } // assignment operators for native types - dfloat& operator=(const signed char rhs) { return convert(rhs, *this); } - dfloat& operator=(const short rhs) { return convert(rhs, *this); } - dfloat& operator=(const int rhs) { return convert(rhs, *this); } - dfloat& operator=(const long rhs) { return convert(rhs, *this); } - dfloat& operator=(const long long rhs) { return convert(rhs, *this); } - dfloat& operator=(const char rhs) { return convert_unsigned(rhs, *this); } - dfloat& operator=(const unsigned short rhs) { return convert_unsigned(rhs, *this); } - dfloat& operator=(const unsigned int rhs) { return convert_unsigned(rhs, *this); } - dfloat& operator=(const unsigned long rhs) { return convert_unsigned(rhs, *this); } - dfloat& operator=(const unsigned long long rhs) { return convert_unsigned(rhs, *this); } - dfloat& operator=(const float rhs) { return convert_ieee754(rhs); } - dfloat& operator=(const double rhs) { return convert_ieee754(rhs); } - dfloat& operator=(const long double rhs) { return convert_ieee754(rhs); } + dfloat& operator=(signed char rhs) { return convert_signed(rhs); } + dfloat& operator=(short rhs) { return convert_signed(rhs); } + dfloat& operator=(int rhs) { return convert_signed(rhs); } + dfloat& operator=(long rhs) { return convert_signed(rhs); } + dfloat& operator=(long long rhs) { return convert_signed(rhs); } + dfloat& operator=(char rhs) { return convert_unsigned(rhs); } + dfloat& operator=(unsigned short rhs) { return convert_unsigned(rhs); } + dfloat& operator=(unsigned int rhs) { return convert_unsigned(rhs); } + dfloat& operator=(unsigned long rhs) { return convert_unsigned(rhs); } + dfloat& operator=(unsigned long long rhs) { return convert_unsigned(rhs); } + dfloat& operator=(float rhs) { return convert_ieee754(rhs); } + dfloat& operator=(double rhs) { return convert_ieee754(rhs); } + dfloat& operator=(long double rhs) { return convert_ieee754(rhs); } // prefix operators dfloat operator-() const { @@ -98,25 +143,72 @@ class dfloat { return *this; } + // unary operators + dfloat& operator++() { + return *this; + } + dfloat operator++(int) { + dfloat tmp(*this); + operator++(); + return tmp; + } + dfloat& operator--() { + return *this; + } + dfloat operator--(int) { + dfloat tmp(*this); + operator--(); + return tmp; + } + // modifiers - inline void clear() { } - inline void setzero() { clear(); } - // use un-interpreted raw bits to set the bits of the dfloat - inline void setBits(unsigned long long value) { + void clear() noexcept { } + void setzero() noexcept { clear(); } + void setinf(bool sign = true) noexcept { } + void setnan(int NaNType = NAN_TYPE_SIGNALLING) noexcept { } + void setsign(bool sign = true) noexcept { } + void setexponent(const std::string& expDigits) noexcept { } + void setfraction(const std::string& fracDigits) noexcept { } + // use un-interpreted raw bits to set the value of the dfloat + inline void setbits(uint64_t value) { clear(); } - inline dfloat& assign(const std::string& txt) { + + // create specific number system values of interest + constexpr dfloat& maxpos() noexcept { + // maxpos is represented by the pattern 9.999e99 + return *this; + } + constexpr dfloat& minpos() noexcept { + // minpos is represented by the pattern 0.0001e-99 + return *this; + } + constexpr dfloat& zero() noexcept { + // the zero value + clear(); + return *this; + } + constexpr dfloat& minneg() noexcept { + // minneg is represented by the pattern -0.0001e-99 + return *this; + } + constexpr dfloat& maxneg() noexcept { + // maxneg is represented by the pattern -9.999e99 + return *this; + } + + dfloat& assign(const std::string& txt) { return *this; } // selectors - inline bool iszero() const { return false; } - inline bool isone() const { return true; } - inline bool isodd() const { return false; } - inline bool iseven() const { return !isodd(); } - inline bool ispos() const { return false; } - inline bool isneg() const { return false; } - inline int scale() const { return 0; } + bool iszero() const noexcept { return false; } + bool isone() const noexcept { return true; } + bool isodd() const noexcept { return false; } + bool iseven() const noexcept { return !isodd(); } + bool ispos() const noexcept { return false; } + bool isneg() const noexcept { return false; } + int scale() const noexcept { return 0; } // convert to string containing digits number of digits std::string str(size_t nrDigits = 0) const { @@ -125,7 +217,7 @@ class dfloat { int64_t magnitude = scale(); if (magnitude > 1 || magnitude < 0) { // use scientific notation for non-trivial exponent values - return sci_notation(nrDigits); + return std::string("TBD"); } std::string str; @@ -149,16 +241,18 @@ class dfloat { // now the digits after the radix point std::string after_decimal = str.substr((size_t)(str.size() + exponent), (size_t)-exponent); - if (isneg()) - return std::string("-") + before_decimal + "." + after_decimal; - else - return before_decimal + "." + after_decimal; - - return std::string("bad"); + std::string final; + if (isneg()) { + final = std::string("-") + before_decimal + "." + after_decimal; + } + else { + final = before_decimal + "." + after_decimal; + } + return final; } protected: - bt _blocks[nrBlocks]; + bt _block[nrBlocks]; // HELPER methods @@ -168,6 +262,26 @@ class dfloat { return ld; } + dfloat& convert_signed(int64_t v) { + if (0 == v) { + setzero(); + } + else { + // convert + } + return *this; + } + + dfloat& convert_unsigned(uint64_t v) { + if (0 == v) { + setzero(); + } + else { + // convert + } + return *this; + } + template dfloat& convert_ieee754(Ty& rhs) { clear(); @@ -183,10 +297,6 @@ class dfloat { return 0; } - std::string sci_notation(size_t nrDigits) const { - - return std::string("TBD"); - } private: @@ -204,55 +314,34 @@ class dfloat { }; -template -inline dfloat& convert(int64_t v, dfloat& result) { - if (0 == v) { - result.setzero(); - } - else { - // convert - } - return result; + +//////////////////////// helper functions ///////////////////////////////// + +// divide dfloat a and b and return result argument +template +void divide(const dfloat& a, const dfloat& b, dfloat& quotient) { } -template -inline dfloat& convert_unsigned(uint64_t v, dfloat& result) { - if (0 == v) { - result.setzero(); - } - else { - // convert - } - return result; +template +inline std::string to_binary(const dfloat& number) { + std::stringstream s; + s << "to_binary TBD"; + return s.str(); } -//////////////////////// MPFLOAT functions ///////////////////////////////// +//////////////////////// DFLOAT functions ///////////////////////////////// -template +template inline dfloat abs(const dfloat& a) { return a; // (a < 0 ? -a : a); } -//////////////////////// INTEGER operators ///////////////////////////////// - -// divide dfloat a and b and return result argument -template -void divide(const dfloat& a, const dfloat& b, dfloat& quotient) { -} - -/// stream operators - -// read a dfloat ASCII format and make a binary dfloat out of it -template -bool parse(const std::string& number, dfloat& value) { - bool bSuccess = false; +//////////////////////// stream operators ///////////////////////////////// - return bSuccess; -} // generate an dfloat format ASCII format -template +template inline std::ostream& operator<<(std::ostream& ostr, const dfloat& i) { // to make certain that setw and left/right operators work properly // we need to transform the dfloat into a string @@ -269,7 +358,7 @@ inline std::ostream& operator<<(std::ostream& ostr, const dfloat +template inline std::istream& operator>>(std::istream& istr, dfloat& p) { std::string txt; istr >> txt; @@ -281,37 +370,45 @@ inline std::istream& operator>>(std::istream& istr, dfloat +bool parse(const std::string& number, dfloat& value) { + bool bSuccess = false; + + return bSuccess; +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// // dfloat - dfloat binary logic operators // equal: precondition is that the storage is properly nulled in all arithmetic paths -template +template inline bool operator==(const dfloat& lhs, const dfloat& rhs) { return true; } -template +template inline bool operator!=(const dfloat& lhs, const dfloat& rhs) { return !operator==(lhs, rhs); } -template +template inline bool operator< (const dfloat& lhs, const dfloat& rhs) { return false; // lhs and rhs are the same } -template +template inline bool operator> (const dfloat& lhs, const dfloat& rhs) { return operator< (rhs, lhs); } -template +template inline bool operator<=(const dfloat& lhs, const dfloat& rhs) { return operator< (lhs, rhs) || operator==(lhs, rhs); } -template +template inline bool operator>=(const dfloat& lhs, const dfloat& rhs) { return !operator< (lhs, rhs); } @@ -319,32 +416,32 @@ inline bool operator>=(const dfloat& lhs, const dfloat +template inline bool operator==(const dfloat& lhs, const double rhs) { return operator==(lhs, dfloat(rhs)); } -template +template inline bool operator!=(const dfloat& lhs, const double rhs) { return !operator==(lhs, rhs); } -template +template inline bool operator< (const dfloat& lhs, const double rhs) { return operator<(lhs, dfloat(rhs)); } -template +template inline bool operator> (const dfloat& lhs, const double rhs) { return operator< (dfloat(rhs), lhs); } -template +template inline bool operator<=(const dfloat& lhs, const double rhs) { return operator< (lhs, rhs) || operator==(lhs, rhs); } -template +template inline bool operator>=(const dfloat& lhs, const double rhs) { return !operator< (lhs, rhs); } @@ -353,32 +450,32 @@ inline bool operator>=(const dfloat& lhs, const double r // literal - dfloat binary logic operators // precondition is that the byte-storage is properly nulled in all arithmetic paths -template +template inline bool operator==(const double lhs, const dfloat& rhs) { return operator==(dfloat(lhs), rhs); } -template +template inline bool operator!=(const double lhs, const dfloat& rhs) { return !operator==(lhs, rhs); } -template +template inline bool operator< (const double lhs, const dfloat& rhs) { return operator<(dfloat(lhs), rhs); } -template +template inline bool operator> (const double lhs, const dfloat& rhs) { return operator< (rhs, lhs); } -template +template inline bool operator<=(const double lhs, const dfloat& rhs) { return operator< (lhs, rhs) || operator==(lhs, rhs); } -template +template inline bool operator>=(const double lhs, const dfloat& rhs) { return !operator< (lhs, rhs); } @@ -388,28 +485,28 @@ inline bool operator>=(const double lhs, const dfloat& r ////////////////////////////////////////////////////////////////////////////////////////////////////// // dfloat - dfloat binary arithmetic operators // BINARY ADDITION -template +template inline dfloat operator+(const dfloat& lhs, const dfloat& rhs) { dfloat sum = lhs; sum += rhs; return sum; } // BINARY SUBTRACTION -template +template inline dfloat operator-(const dfloat& lhs, const dfloat& rhs) { dfloat diff = lhs; diff -= rhs; return diff; } // BINARY MULTIPLICATION -template +template inline dfloat operator*(const dfloat& lhs, const dfloat& rhs) { dfloat mul = lhs; mul *= rhs; return mul; } // BINARY DIVISION -template +template inline dfloat operator/(const dfloat& lhs, const dfloat& rhs) { dfloat ratio = lhs; ratio /= rhs; @@ -419,22 +516,22 @@ inline dfloat operator/(const dfloat +template inline dfloat operator+(const dfloat& lhs, const double rhs) { return operator+(lhs, dfloat(rhs)); } // BINARY SUBTRACTION -template +template inline dfloat operator-(const dfloat& lhs, const double rhs) { return operator-(lhs, dfloat(rhs)); } // BINARY MULTIPLICATION -template +template inline dfloat operator*(const dfloat& lhs, const double rhs) { return operator*(lhs, dfloat(rhs)); } // BINARY DIVISION -template +template inline dfloat operator/(const dfloat& lhs, const double rhs) { return operator/(lhs, dfloat(rhs)); } @@ -442,22 +539,22 @@ inline dfloat operator/(const dfloat +template inline dfloat operator+(const double lhs, const dfloat& rhs) { return operator+(dfloat(lhs), rhs); } // BINARY SUBTRACTION -template +template inline dfloat operator-(const double lhs, const dfloat& rhs) { return operator-(dfloat(lhs), rhs); } // BINARY MULTIPLICATION -template +template inline dfloat operator*(const double lhs, const dfloat& rhs) { return operator*(dfloat(lhs), rhs); } // BINARY DIVISION -template +template inline dfloat operator/(const double lhs, const dfloat& rhs) { return operator/(dfloat(lhs), rhs); } diff --git a/include/universal/number/dfloat/exceptions.hpp b/include/universal/number/dfloat/exceptions.hpp index 3dfcc3359..cfa0a2af4 100644 --- a/include/universal/number/dfloat/exceptions.hpp +++ b/include/universal/number/dfloat/exceptions.hpp @@ -1,7 +1,8 @@ #pragma once // exceptions.hpp: definition of arbitrary configuration dfloat exceptions // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/number/dfloat/manipulators.hpp b/include/universal/number/dfloat/manipulators.hpp index 090b2ad7d..f10117029 100644 --- a/include/universal/number/dfloat/manipulators.hpp +++ b/include/universal/number/dfloat/manipulators.hpp @@ -1,21 +1,21 @@ -// manipulators.hpp: definitions of helper functions for classic cfloat type manipulation +// manipulators.hpp: definitions of helper functions for decimal dfloat type manipulation // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. namespace sw { namespace universal { -// Generate a type tag for this dfloat -template -std::string type_tag(const dfloat& = {}) { - std::stringstream s; - s << "dfloat<" - << std::setw(3) << ndigits << ", " - << std::setw(3) << es << ", " - << typeid(bt).name() << ">"; - return s.str(); -} - + // Generate a type tag for this dfloat + template + std::string type_tag(const dfloat& = {}) { + std::stringstream s; + s << "dfloat<" + << std::setw(3) << ndigits << ", " + << std::setw(3) << es << ", " + << typeid(bt).name() << ">"; + return s.str(); + } }} // namespace sw::universal diff --git a/include/universal/number/fixpnt/fixpnt_impl.hpp b/include/universal/number/fixpnt/fixpnt_impl.hpp index 57704efc5..a954ff531 100644 --- a/include/universal/number/fixpnt/fixpnt_impl.hpp +++ b/include/universal/number/fixpnt/fixpnt_impl.hpp @@ -221,8 +221,8 @@ class fixpnt { constexpr fixpnt(unsigned int initial_value) noexcept : fixpnt{convert(initial_value)} {} constexpr fixpnt(unsigned long initial_value) noexcept : fixpnt{convert(initial_value)} {} constexpr fixpnt(unsigned long long initial_value) noexcept : fixpnt{convert(initial_value)} {} - CONSTEXPRESSION fixpnt(float initial_value) noexcept : fixpnt{convert(initial_value)} {} - CONSTEXPRESSION fixpnt(double initial_value) noexcept : fixpnt{convert(initial_value)} {} + BIT_CAST_CONSTEXPR fixpnt(float initial_value) noexcept : fixpnt{convert(initial_value)} {} + BIT_CAST_CONSTEXPR fixpnt(double initial_value) noexcept : fixpnt{convert(initial_value)} {} // access operator for bits // this needs a proxy to be able to create l-values @@ -241,14 +241,14 @@ class fixpnt { constexpr fixpnt& operator=(unsigned int rhs) noexcept { return *this = convert(rhs); } constexpr fixpnt& operator=(unsigned long rhs) noexcept { return *this = convert(rhs); } constexpr fixpnt& operator=(unsigned long long rhs) noexcept { return *this = convert(rhs); } - CONSTEXPRESSION fixpnt& operator=(float rhs) noexcept { return *this = convert(rhs); } - CONSTEXPRESSION fixpnt& operator=(double rhs) noexcept { return *this = convert(rhs); } + BIT_CAST_CONSTEXPR fixpnt& operator=(float rhs) noexcept { return *this = convert(rhs); } + BIT_CAST_CONSTEXPR fixpnt& operator=(double rhs) noexcept { return *this = convert(rhs); } // guard long double support to enable ARM and RISC-V embedded environments #if LONG_DOUBLE_SUPPORT - CONSTEXPRESSION fixpnt(long double initial_value) noexcept : fixpnt{ convert(initial_value) } {} - CONSTEXPRESSION fixpnt& operator=(long double rhs) noexcept { return convert(rhs); } - CONSTEXPRESSION explicit operator long double() const noexcept { return to_native(); } + fixpnt(long double initial_value) noexcept : fixpnt{ convert(initial_value) } {} + fixpnt& operator=(long double rhs) noexcept { return convert(rhs); } + explicit operator long double() const noexcept { return to_native(); } #endif // assign the value of the textual representation to the fixpnt: can be binary/octal/decimal/hexadecimal @@ -706,7 +706,7 @@ class fixpnt { int radixPoint = ieee754_parameter::fbits - (static_cast(unbiasedExponent) - ieee754_parameter::bias); // our fixed-point has its radixPoint at rbits - int shiftRight = radixPoint - int(rbits); + int shiftRight = std::min(radixPoint - int(rbits), 64); if (shiftRight > 0) { // we need to round the raw bits // collect guard, round, and sticky bits diff --git a/include/universal/number/integer/integer.hpp b/include/universal/number/integer/integer.hpp index 694452f68..e9689ead2 100644 --- a/include/universal/number/integer/integer.hpp +++ b/include/universal/number/integer/integer.hpp @@ -1,6 +1,7 @@ // : arbitrary integer arithmetic type standard header // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #ifndef _INTEGER_STANDARD_HEADER_ diff --git a/include/universal/number/integer/integer_impl.hpp b/include/universal/number/integer/integer_impl.hpp index 022e7ea4a..131832516 100644 --- a/include/universal/number/integer/integer_impl.hpp +++ b/include/universal/number/integer/integer_impl.hpp @@ -268,7 +268,7 @@ class integer { explicit operator float() const noexcept { return to_real(); } explicit operator double() const noexcept { return to_real(); } #if LONG_DOUBLE_SUPPORT - explicit operator long double() const { return to_real(); } + explicit operator long double() const noexcept { return to_real(); } #endif // arithmetic operators diff --git a/include/universal/number/lns/math/classify.hpp b/include/universal/number/lns/math/classify.hpp index 937173544..ca18e1365 100644 --- a/include/universal/number/lns/math/classify.hpp +++ b/include/universal/number/lns/math/classify.hpp @@ -11,19 +11,7 @@ namespace sw { namespace universal { // STD LIB function for IEEE floats: Categorizes floating point value arg into the following categories: zero, subnormal, normal, infinite, NAN, or implementation-defined category. template int fpclassify(const lns& a) { - if constexpr (nbits < 33) { - return std::fpclassify(float(a)); - } - else if constexpr (nbits < 65) { - return std::fpclassify(double(a)); - } - else { -#if LONG_DOUBLE_SUPPORT - return std::fpclassify((long double)(a)); -#else return std::fpclassify(double(a)); -#endif - } } // STD LIB function for IEEE floats: Determines if the given floating point number arg has finite value i.e. it is normal, subnormal or zero, but not infinite or NaN. diff --git a/include/universal/number/posit/specialized/posit_32_2.hpp b/include/universal/number/posit/specialized/posit_32_2.hpp index 0938e1286..9628c7002 100644 --- a/include/universal/number/posit/specialized/posit_32_2.hpp +++ b/include/universal/number/posit/specialized/posit_32_2.hpp @@ -907,9 +907,9 @@ class posit { std::cout << "reglen = " << reglen << std::endl; std::cout << "regime = " << to_binary(regime) << std::endl; std::cout << "exponent = " << exp << std::endl; - std::cout << "fraction raw = " << to_binary(frac64, 64, true) << std::endl; - std::cout << "fraction final = " << to_binary(fraction, 32, true) << std::endl; - std::cout << "posit bits = " << to_binary(bits, 32, true) << std::endl; + std::cout << "fraction raw = " << to_binary(frac64, true, 64) << std::endl; + std::cout << "fraction final = " << to_binary(fraction, true, 32) << std::endl; + std::cout << "posit bits = " << to_binary(bits, true, 32) << std::endl; #endif } return bits; diff --git a/include/universal/number/shared/infinite_encoding.hpp b/include/universal/number/shared/infinite_encoding.hpp index 6e3fa4e31..ae2521ad6 100644 --- a/include/universal/number/shared/infinite_encoding.hpp +++ b/include/universal/number/shared/infinite_encoding.hpp @@ -9,7 +9,8 @@ namespace sw { namespace universal { static constexpr int INF_TYPE_NEGATIVE = -1; // -inf - static constexpr int INF_TYPE_EITHER = 0; // any inf - static constexpr int INF_TYPE_POSITIVE = 1; // +inf + static constexpr int INF_TYPE_EITHER = 0; // any inf + static constexpr int INF_TYPE_POSITIVE = 1; // +inf + static constexpr int INF_TYPE_NEITHER = 2; // not an inf }} // namespace sw::universal diff --git a/include/universal/number/shared/nan_encoding.hpp b/include/universal/number/shared/nan_encoding.hpp index d3f456d2c..32062069c 100644 --- a/include/universal/number/shared/nan_encoding.hpp +++ b/include/universal/number/shared/nan_encoding.hpp @@ -9,7 +9,8 @@ namespace sw { namespace universal { static constexpr int NAN_TYPE_SIGNALLING = -1; // a Signalling NaN - static constexpr int NAN_TYPE_EITHER = 0; // any NaN - static constexpr int NAN_TYPE_QUIET = 1; // a Quiet NaN + static constexpr int NAN_TYPE_EITHER = 0; // any NaN + static constexpr int NAN_TYPE_QUIET = 1; // a Quiet NaN + static constexpr int NAN_TYPE_NEITHER = 2; // not a NaN }} // namespace sw::universal diff --git a/include/universal/number/takum/takum_impl.hpp b/include/universal/number/takum/takum_impl.hpp index 983ee2356..cfc38e1b1 100644 --- a/include/universal/number/takum/takum_impl.hpp +++ b/include/universal/number/takum/takum_impl.hpp @@ -127,7 +127,7 @@ class takum { // guard long double support to enable ARM and RISC-V embedded environments #if LONG_DOUBLE_SUPPORT takum(long double initial_value) noexcept { *this = initial_value; } - CONSTEXPRESSION takum& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } + takum& operator=(long double rhs) noexcept { return convert_ieee754(rhs); } explicit constexpr operator long double() const noexcept { return to_ieee754(); } #endif diff --git a/include/universal/traits/bfloat16_traits.hpp b/include/universal/traits/bfloat16_traits.hpp index f76fe7335..cf3dc407e 100644 --- a/include/universal/traits/bfloat16_traits.hpp +++ b/include/universal/traits/bfloat16_traits.hpp @@ -1,7 +1,8 @@ #pragma once // bfloat16_traits.hpp : traits for the bfloat16 number systems // -// Copyright (C) 2022-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/traits/bfloat8_traits.hpp b/include/universal/traits/bfloat8_traits.hpp index 2fad23ad9..63db94232 100644 --- a/include/universal/traits/bfloat8_traits.hpp +++ b/include/universal/traits/bfloat8_traits.hpp @@ -1,7 +1,8 @@ #pragma once // bfloat8_traits.hpp : traits for the bfloat8 number systems // -// Copyright (C) 2022-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/include/universal/traits/dd_traits.hpp b/include/universal/traits/dd_traits.hpp new file mode 100644 index 000000000..8ead7520c --- /dev/null +++ b/include/universal/traits/dd_traits.hpp @@ -0,0 +1,31 @@ +#pragma once +// lns_traits.hpp : traits for doubledouble (dd) arithmetic type +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +namespace sw { namespace universal { + +// define a trait for doubledouble (dd) types +template +struct is_dd_trait + : false_type +{ +}; + +template<> +struct is_dd_trait< dd > + : true_type +{ +}; + +template +constexpr bool is_dd = is_dd_trait<_Ty>::value; + +template +using enable_if_dd = std::enable_if_t, _Ty>; + +}} // namespace sw::universal diff --git a/include/universal/utility/bit_cast.hpp b/include/universal/utility/bit_cast.hpp index c313d5891..e9bd2f404 100644 --- a/include/universal/utility/bit_cast.hpp +++ b/include/universal/utility/bit_cast.hpp @@ -19,7 +19,7 @@ // clients to propagate constexpr on functions that depend on bit_cast, // and BIT_CAST_IS_CONSTEXPR symbol is defined as true or false. -// The earlier BIT_CAST_SUPPORT, and related CONSTEXRESSION, symbols are +// The earlier BIT_CAST_SUPPORT, and related CONSTEXPRESSION, symbols are // now redundant and can be deprecated. #if defined (BIT_CAST_SUPPORT) || defined (BIT_CAST) @@ -97,18 +97,13 @@ inline constexpr bool is_bit_cast_constexpr_v = BIT_CAST_IS_CONSTEXPR; #undef BIT_CAST -// BIT_CAST_SUPPORT is compiler env dependent and drives the algorith selection of ieee-754 decode +// BIT_CAST_IS_CONSTEXPR drives the algorithm selection of ieee-754 decode #if defined(__clang__) /* Clang/LLVM. ---------------------------------------------- */ -#ifndef BIT_CAST_SUPPORT -#define BIT_CAST_SUPPORT 0 -#define CONSTEXPRESSION -#endif - #ifndef CONSTEXPRESSION -#define CONSTEXPRESSION +#define CONSTEXPRESSION BIT_CAST_CONSTEXPR #endif #elif defined(__ICC) || defined(__INTEL_COMPILER) @@ -118,13 +113,8 @@ inline constexpr bool is_bit_cast_constexpr_v = BIT_CAST_IS_CONSTEXPR; #elif defined(__GNUC__) || defined(__GNUG__) /* GNU GCC/G++. --------------------------------------------- */ -#ifndef BIT_CAST_SUPPORT -#define BIT_CAST_SUPPORT 0 -#define CONSTEXPRESSION -#endif - #ifndef CONSTEXPRESSION -#define CONSTEXPRESSION +#define CONSTEXPRESSION BIT_CAST_CONSTEXPR #endif #elif defined(__HP_cc) || defined(__HP_aCC) @@ -136,19 +126,8 @@ inline constexpr bool is_bit_cast_constexpr_v = BIT_CAST_IS_CONSTEXPR; #elif defined(_MSC_VER) /* Microsoft Visual Studio. --------------------------------- */ -#ifndef BIT_CAST_SUPPORT -#define BIT_CAST_SUPPORT 1 -#include -#ifndef CONSTEXPRESSION -#define CONSTEXPRESSION constexpr -#endif -#endif - -// if you are not controlling BIT_CAST_SUPPORT -// you have the option to indepdently control CONSTEXPRESSION -// default is to turn it off #ifndef CONSTEXPRESSION -#define CONSTEXPRESSION +#define CONSTEXPRESSION BIT_CAST_CONSTEXPR #endif #elif defined(__PGI) diff --git a/include/universal/utility/compiler.hpp b/include/universal/utility/compiler.hpp index 8b69d65f3..a350807c1 100644 --- a/include/universal/utility/compiler.hpp +++ b/include/universal/utility/compiler.hpp @@ -6,7 +6,7 @@ // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include - +#include @@ -14,6 +14,8 @@ namespace sw { namespace universal { inline void report_compiler() { + std::string compiler_identifier_full(""); + #if defined(__clang__) /* Clang/LLVM. ---------------------------------------------- */ std::string compiler_identifier("clang"); @@ -39,6 +41,40 @@ std::string compiler_identifier("ibmcpp"); /* Microsoft Visual Studio. --------------------------------- */ std::string compiler_identifier("msvc"); +if constexpr (_MSC_VER == 1600) compiler_identifier_full = std::string("Visual Studio 2010 version 10.0"); +else if constexpr (_MSC_VER == 1700) compiler_identifier_full = std::string("Visual Studio 2012 version 11.0"); +else if constexpr (_MSC_VER == 1800) compiler_identifier_full = std::string("Visual Studio 2013 version 12.0"); +else if constexpr (_MSC_VER == 1900) compiler_identifier_full = std::string("Visual Studio 2015 version 14.0"); +else if constexpr (_MSC_VER == 1910) compiler_identifier_full = std::string("Visual Studio 2017 version 15.0"); +else if constexpr (_MSC_VER == 1911) compiler_identifier_full = std::string("Visual Studio 2017 version 15.3"); +else if constexpr (_MSC_VER == 1912) compiler_identifier_full = std::string("Visual Studio 2017 version 15.5"); +else if constexpr (_MSC_VER == 1913) compiler_identifier_full = std::string("Visual Studio 2017 version 15.6"); +else if constexpr (_MSC_VER == 1914) compiler_identifier_full = std::string("Visual Studio 2017 version 15.7"); +else if constexpr (_MSC_VER == 1915) compiler_identifier_full = std::string("Visual Studio 2017 version 15.8"); +else if constexpr (_MSC_VER == 1916) compiler_identifier_full = std::string("Visual Studio 2017 version 15.9"); +else if constexpr (_MSC_VER == 1920) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.0"); +else if constexpr (_MSC_VER == 1921) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.1"); +else if constexpr (_MSC_VER == 1922) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.2"); +else if constexpr (_MSC_VER == 1923) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.3"); +else if constexpr (_MSC_VER == 1924) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.4"); +else if constexpr (_MSC_VER == 1925) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.5"); +else if constexpr (_MSC_VER == 1926) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.6"); +else if constexpr (_MSC_VER == 1927) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.7"); +else if constexpr (_MSC_VER == 1928) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.9"); +else if constexpr (_MSC_VER == 1929) compiler_identifier_full = std::string("Visual Studio 2019 Version 16.11"); +else if constexpr (_MSC_VER == 1930) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.0 RTW"); +else if constexpr (_MSC_VER == 1931) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.1"); +else if constexpr (_MSC_VER == 1932) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.2"); +else if constexpr (_MSC_VER == 1933) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.3"); +else if constexpr (_MSC_VER == 1934) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.4"); +else if constexpr (_MSC_VER == 1935) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.5"); +else if constexpr (_MSC_VER == 1936) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.6"); +else if constexpr (_MSC_VER == 1937) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.7"); +else if constexpr (_MSC_VER == 1938) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.8"); +else if constexpr (_MSC_VER == 1939) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.9"); +else if constexpr (_MSC_VER == 1940) compiler_identifier_full = std::string("Visual Studio 2022 Version 17.10"); +else compiler_identifier_full = std::string("unknown Microsoft Visual C++"); + #elif defined(__PGI) /* Portland Group PGCC/PGCPP. ------------------------------- */ std::string compiler_identifier("pgcpp"); @@ -49,38 +85,17 @@ std::string compiler_identifier("suncc"); #endif - std::cout << "compiler architecture: " << compiler_identifier << '\n'; - std::cout << "compiler language cfg: " << __cplusplus << '\n'; + std::cout << "compiler architecture : " << compiler_identifier << '\n'; + std::cout << "compiler release : " << compiler_identifier_full << '\n'; + std::cout << "compiler language cfg : " << __cplusplus << '\n'; #if defined(_MSC_VER) && (_MSC_VER >= 1300) - std::cout << "Microsoft Visual C++: " << _MSC_VER << '\n'; - if constexpr (_MSC_VER == 1600) std::cout << "(Visual Studio 2010 version 10.0)\n"; - else if constexpr (_MSC_VER == 1700) std::cout << "(Visual Studio 2012 version 11.0)\n"; - else if constexpr (_MSC_VER == 1800) std::cout << "(Visual Studio 2013 version 12.0)\n"; - else if constexpr (_MSC_VER == 1900) std::cout << "(Visual Studio 2015 version 14.0)\n"; - else if constexpr (_MSC_VER == 1910) std::cout << "(Visual Studio 2017 version 15.0)\n"; - else if constexpr (_MSC_VER == 1911) std::cout << "(Visual Studio 2017 version 15.3)\n"; - else if constexpr (_MSC_VER == 1912) std::cout << "(Visual Studio 2017 version 15.5)\n"; - else if constexpr (_MSC_VER == 1913) std::cout << "(Visual Studio 2017 version 15.6)\n"; - else if constexpr (_MSC_VER == 1914) std::cout << "(Visual Studio 2017 version 15.7)\n"; - else if constexpr (_MSC_VER == 1915) std::cout << "(Visual Studio 2017 version 15.8)\n"; - else if constexpr (_MSC_VER == 1916) std::cout << "(Visual Studio 2017 version 15.9)\n"; - else if constexpr (_MSC_VER == 1920) std::cout << "(Visual Studio 2019 Version 16.0)\n"; - else if constexpr (_MSC_VER == 1921) std::cout << "(Visual Studio 2019 Version 16.1)\n"; - else if constexpr (_MSC_VER == 1922) std::cout << "(Visual Studio 2019 Version 16.2)\n"; - else if constexpr (_MSC_VER == 1923) std::cout << "(Visual Studio 2019 Version 16.3)\n"; - else if constexpr (_MSC_VER == 1924) std::cout << "(Visual Studio 2019 Version 16.4)\n"; - else if constexpr (_MSC_VER == 1925) std::cout << "(Visual Studio 2019 Version 16.5)\n"; - else if constexpr (_MSC_VER == 1926) std::cout << "(Visual Studio 2019 Version 16.6)\n"; - else if constexpr (_MSC_VER == 1927) std::cout << "(Visual Studio 2019 Version 16.7)\n"; - else if constexpr (_MSC_VER == 1928) std::cout << "(Visual Studio 2019 Version 16.9)\n"; - else if constexpr (_MSC_VER == 1929) std::cout << "(Visual Studio 2019 Version 16.11)\n"; - else if constexpr (_MSC_VER == 1930) std::cout << "(Visual Studio 2022 Version 17.0 RTW)\n"; - else if constexpr (_MSC_VER == 1931) std::cout << "(Visual Studio 2022 Version 17.1)\n"; - else if constexpr (_MSC_VER == 1932) std::cout << "(Visual Studio 2022 Version 17.2)\n"; - else std::cout << "unknown Microsoft Visual C++: " << _MSC_VER << '\n'; - - std::cout << "__cplusplus: " << __cplusplus << '\n'; + std::cout << "Microsoft Visual C++ version : " << _MSC_VER << '\n'; + // Visual C++ compiler is 15.00.20706.01, the _MSC_FULL_VER will be 15002070601 + std::stringstream s; + s << _MSC_FULL_VER; + std::string version = s.str(); + std::cout << std::string("Microsoft Visual C++ full : ") + std::string(version) << '\n'; /* _MSVC_LANG Defined as an integer literal that specifies the C++ language standard targeted by the compiler. diff --git a/include/universal/utility/directives.hpp b/include/universal/utility/directives.hpp index 7c2c2a7f6..abedff7e9 100644 --- a/include/universal/utility/directives.hpp +++ b/include/universal/utility/directives.hpp @@ -17,7 +17,7 @@ #pragma warning(disable : 5264) // 'const' variable is not used #pragma warning(disable : 5045) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified -// this is a good warning to catch Universal library conditional compilation errors +// this is a good warning to catch conditional compilation errors //#pragma warning(disable : 4688) warning C4668: 'LONG_DOUBLE_SUPPORT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' // but this one warning is making life difficult // warning C4668: '__STDC_WANT_SECURE_LIB__' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' diff --git a/include/universal/verification/blockbinary_test_status.hpp b/include/universal/verification/blockbinary_test_status.hpp index f1f4a136d..09a1ff94b 100644 --- a/include/universal/verification/blockbinary_test_status.hpp +++ b/include/universal/verification/blockbinary_test_status.hpp @@ -22,8 +22,8 @@ void ReportBinaryArithmeticError(const std::string& test_case, const std::string << " != " << std::setw(COLUMN_WIDTH) << (long long)result // to_hex(result, true) << " golden reference is " - << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference,nbits) - << " " << to_binary(result, true) << " vs " << to_binary(reference, nbits) + << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference,false, nbits) + << " " << to_binary(result, true) << " vs " << to_binary(reference, false, nbits) << std::setprecision(old_precision) << std::endl; } @@ -39,8 +39,8 @@ void ReportBinaryArithmeticSuccess(const std::string& test_case, const std::stri << " == " << std::setw(COLUMN_WIDTH) << (long long)result // to_hex(result, true) << " matches reference " - << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference, nbits) - << " " << to_binary(result, true) << " vs " << to_binary(reference, nbits) + << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference, false, nbits) + << " " << to_binary(result, true) << " vs " << to_binary(reference, false, nbits) << std::setprecision(old_precision) << std::endl; } @@ -56,8 +56,8 @@ void ReportArithmeticShiftError(const std::string& test_case, const std::string& << " != " << std::setw(COLUMN_WIDTH) << (long long)result // to_hex(result, true) << " golden reference is " - << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference, nbits) - << " " << to_binary(result, true) << " vs " << to_binary(reference, nbits) + << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference, false, nbits) + << " " << to_binary(result, true) << " vs " << to_binary(reference, false, nbits) << std::setprecision(old_precision) << std::endl; } @@ -73,8 +73,8 @@ void ReportArithmeticShiftSuccess(const std::string& test_case, const std::strin << " == " << std::setw(COLUMN_WIDTH) << (long long)result << " matches reference " - << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference, nbits) - << " " << to_binary(result, true) << " vs " << to_binary(reference, nbits) + << std::setw(COLUMN_WIDTH) << reference << ' ' << to_binary(reference, false, nbits) + << " " << to_binary(result, true) << " vs " << to_binary(reference, false, nbits) << std::setprecision(old_precision) << std::endl; } diff --git a/include/universal/verification/test_case.hpp b/include/universal/verification/test_case.hpp index a4db55130..77cc63869 100644 --- a/include/universal/verification/test_case.hpp +++ b/include/universal/verification/test_case.hpp @@ -132,8 +132,11 @@ namespace sw { namespace universal { } template - void ReportValue(const TestType& a, const std::string& label = "", unsigned labelWidth = 20) { + void ReportValue(const TestType& a, const std::string& label = "", unsigned labelWidth = 20, unsigned precision = 7) { + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); std::cout << std::setw(labelWidth) << label << " : " << to_binary(a, true) << " : " << a << '\n'; + std::cout << std::setprecision(oldPrec); } template diff --git a/include/universal/verification/test_suite_randoms.hpp b/include/universal/verification/test_suite_randoms.hpp index f7ca63954..1295278a3 100644 --- a/include/universal/verification/test_suite_randoms.hpp +++ b/include/universal/verification/test_suite_randoms.hpp @@ -382,7 +382,7 @@ namespace sw { namespace universal { TestType diff = result - ref; if (reportTestCases) std::cerr << "diff = " << to_binary(diff) << '\n'; } - nrOfFailedTests++; + ++nrOfFailedTests; if (reportTestCases) ReportBinaryArithmeticError("FAIL", operation_string, testa, testb, result, ref); } else { @@ -475,7 +475,7 @@ namespace sw { namespace universal { if (result != ref) { if (result.isnan() && ref.isnan()) continue; - nrOfFailedTests++; + ++nrOfFailedTests; if (reportTestCases) ReportUnaryArithmeticError("FAIL", operation_string, nut, result, ref); } else { @@ -609,7 +609,7 @@ namespace sw { namespace universal { if (result != ref) { std::cout << "result : " << to_binary(result) << '\n'; std::cout << "reference : " << to_binary(ref) << '\n'; - nrOfFailedTests++; + ++nrOfFailedTests; if (reportTestCases) ReportUnaryArithmeticError("FAIL", operation_string, nut, result, ref); } else { @@ -624,7 +624,7 @@ namespace sw { namespace universal { int Compare(long double input, const TestType& testresult, const TestType& ptarget, const TestType& pref, bool reportTestCases) { int fail = 0; if (testresult != ptarget) { - fail++; + ++fail; if (reportTestCases) { ReportConversionError("FAIL", "=", input, (long double)(ptarget), testresult); std::cout << "reference : " << pref.get() << std::endl; diff --git a/internal/blockbinary/arithmetic/addition.cpp b/internal/blockbinary/arithmetic/addition.cpp index 5ddc17efb..6e0364f28 100644 --- a/internal/blockbinary/arithmetic/addition.cpp +++ b/internal/blockbinary/arithmetic/addition.cpp @@ -35,11 +35,11 @@ int VerifyAddition(bool bReportIndividualTestCases) { if (bReportOverflowCondition) std::cout << std::setw(5) << aref << " + " << std::setw(5) << bref << " = " << std::setw(5) << cref << " : "; if (cref < -(1 << (nbits - 1))) { - if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) << "(maxneg) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, 12) << '\n'; + if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) << "(maxneg) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfUnderflows; } else if (cref > ((1 << (nbits - 1)) - 1)) { - if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 << "(maxpos) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, 12) << '\n'; + if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 << "(maxpos) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfOverflows; } else { diff --git a/internal/blockbinary/arithmetic/multiplication.cpp b/internal/blockbinary/arithmetic/multiplication.cpp index cf4443ca4..785a72860 100644 --- a/internal/blockbinary/arithmetic/multiplication.cpp +++ b/internal/blockbinary/arithmetic/multiplication.cpp @@ -39,12 +39,12 @@ int VerifyMultiplication(bool bReportIndividualTestCases) { if (bReportOverflowCondition) std::cout << std::setw(5) << aref << " * " << std::setw(5) << bref << " = " << std::setw(5) << cref << " : "; if (cref < -(1 << (nbits - 1))) { if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) - << "(maxneg) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, 12) << '\n'; + << "(maxneg) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfUnderflows; } else if (cref > ((1 << (nbits - 1)) - 1)) { if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 - << "(maxpos) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, 12) << '\n'; + << "(maxpos) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfOverflows; } else { diff --git a/internal/blockbinary/arithmetic/remainder.cpp b/internal/blockbinary/arithmetic/remainder.cpp index 7c469912a..ced3c17fc 100644 --- a/internal/blockbinary/arithmetic/remainder.cpp +++ b/internal/blockbinary/arithmetic/remainder.cpp @@ -40,12 +40,12 @@ int VerifyRemainder(bool bReportIndividualTestCases) { if (cref < -(1 << (nbits - 1))) { if (bReportOverflowCondition) std::cout << std::setw(5) << aref << " % " << std::setw(5) << bref << " = " << std::setw(5) << cref << " : "; - if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) << "(maxneg) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, 12) << '\n'; + if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) << "(maxneg) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfUnderflows; } else if (cref > ((1 << (nbits - 1)) - 1)) { if (bReportOverflowCondition) std::cout << std::setw(5) << aref << " % " << std::setw(5) << bref << " = " << std::setw(5) << cref << " : "; - if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 << "(maxpos) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, 12) << '\n'; + if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 << "(maxpos) assigned value = " << std::setw(5) << result.to_long_long() << " " << std::setw(5) << to_hex(result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfOverflows; } diff --git a/internal/blockbinary/arithmetic/urmul.cpp b/internal/blockbinary/arithmetic/urmul.cpp index 93c1ea460..74a99f20c 100644 --- a/internal/blockbinary/arithmetic/urmul.cpp +++ b/internal/blockbinary/arithmetic/urmul.cpp @@ -40,11 +40,11 @@ int VerifyUnroundedMultiplication(bool bReportIndividualTestCases) { if (bReportOverflowCondition) std::cout << std::setw(5) << aref << " * " << std::setw(5) << bref << " = " << std::setw(5) << cref << " : "; if (cref < -(1 << (nbits - 1))) { - if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) << "(maxneg) assigned value = " << std::setw(5) << signext_result.to_long_long() << " " << std::setw(5) << to_hex(signext_result) << " vs " << to_binary(cref, 12) << '\n'; + if (bReportOverflowCondition) std::cout << "underflow: " << std::setw(5) << cref << " < " << std::setw(5) << -(1 << (nbits - 1)) << "(maxneg) assigned value = " << std::setw(5) << signext_result.to_long_long() << " " << std::setw(5) << to_hex(signext_result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfUnderflows; } else if (cref > ((1 << (nbits - 1)) - 1)) { - if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 << "(maxpos) assigned value = " << std::setw(5) << signext_result.to_long_long() << " " << std::setw(5) << to_hex(signext_result) << " vs " << to_binary(cref, 12) << '\n'; + if (bReportOverflowCondition) std::cout << "overflow: " << std::setw(5) << cref << " > " << std::setw(5) << (1 << (nbits - 1)) - 1 << "(maxpos) assigned value = " << std::setw(5) << signext_result.to_long_long() << " " << std::setw(5) << to_hex(signext_result) << " vs " << to_binary(cref, false, 12) << '\n'; ++nrOfOverflows; } else { diff --git a/internal/blocktriple/api/constexpr.cpp b/internal/blocktriple/api/constexpr.cpp index 6e10dd748..39bd35415 100644 --- a/internal/blocktriple/api/constexpr.cpp +++ b/internal/blocktriple/api/constexpr.cpp @@ -95,7 +95,7 @@ try { CONSTEXPRESSION blocktriple<32> a(16ull); // unsigned long std::cout << "constexpr constructor for type 'unsigned long long' " << a << '\n'; } -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR { CONSTEXPRESSION blocktriple<32> a(1.125f); // float std::cout << "constexpr constructor for type 'float' " << a << '\n'; @@ -106,12 +106,12 @@ try { } #if LONG_DOUBLE_SUPPORT { - CONSTEXPRESSION blocktriple<32> a(1.03125l); // long double + blocktriple<32> a(1.03125l); // long double std::cout << "constexpr constructor for type 'long double' " << a << '\n'; } #endif -#endif // BIT_CAST_SUPPORT +#endif // BIT_CAST_IS_CONSTEXPR } { @@ -124,7 +124,7 @@ try { CONSTEXPRESSION blocktriple<32> a = 1ul; // unsigned long std::cout << a << '\n'; } -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR { CONSTEXPRESSION blocktriple<32> a = 1.0f; // float std::cout << a << '\n'; @@ -135,12 +135,12 @@ try { } #if LONG_DOUBLE_SUPPORT { - CONSTEXPRESSION blocktriple<32> a = 1.0l; // long double + blocktriple<32> a = 1.0l; // long double std::cout << a << '\n'; } #endif -#endif // BIT_CAST_SUPPORT +#endif // BIT_CAST_IS_CONSTEXPR } if (nrOfFailedTestCases > 0) { diff --git a/internal/f2s/api/api.cpp b/internal/f2s/api/api.cpp index 07f7608db..9d4fa5e85 100644 --- a/internal/f2s/api/api.cpp +++ b/internal/f2s/api/api.cpp @@ -1,6 +1,7 @@ // api.cpp : test suite runner for the class interface of the simplified floating-point type // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/internal/gfp/api/api.cpp b/internal/gfp/api/api.cpp index d62918918..74e49a2de 100644 --- a/internal/gfp/api/api.cpp +++ b/internal/gfp/api/api.cpp @@ -1,6 +1,7 @@ -// api.cpp : test suite runner for the class interface of the simplified floating-point type +// api.cpp : test suite runner for the class interface of a simplified floating-point type // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -9,11 +10,43 @@ #include #include +// https://en.cppreference.com/w/cpp/utility/feature_test +#include + +#if __cpp_lib_to_string >= 202110L +constexpr auto revision() { return " (post C++23)"; } +#define HAS_STD_FLOATS 1 +#include +#else +constexpr auto revision() { return " (pre C++23)"; } +#define HAS_STD_FLOATS 0 +#endif + +namespace sw { + namespace universal { + + std::string to_string(uint64_t bits) { + std::cout << "incoming: " << bits << " log10() : " << std::log10(bits) << '\n'; + std::cout << "incoming: " << bits << " log2() : " << std::log2(bits) << '\n'; + std::cout << "incoming: " << bits << " scale() : " << scale(float(bits)) << '\n'; + unsigned nrDigits = std::log10(bits) + 1; + std::string str(nrDigits, '\0'); + char* p = &str.back(); + do { + *p = bits % 10 + '0'; // extract least significant digit + bits /= 10; + std::cout << "digits : " << str << '\n'; + --p; + } while (bits); + return str; + } + } +} int main() try { using namespace sw::universal; - std::string test_suite = "gfp API validation"; + std::string test_suite = "gfp decimal string conversion validation"; std::string test_tag = "API"; bool reportTestCases = true; int nrOfFailedTestCases = 0; @@ -21,8 +54,6 @@ try { ReportTestSuiteHeader(test_suite, reportTestCases); ///////////////// construction - - { gfp a, b, c; a = 1.0e0f; @@ -87,6 +118,27 @@ try { std::cout << "floating-point value : " << to_binary(d) << " : " << d << " : " << to_triple(d) << '\n'; } + { + // basic to_string algorithm + std::string digits = sw::universal::to_string(1024 * 1024 * 1024); + std::cout << "1024 * 1024 * 1024 : " << digits << '\n'; + } + +#if HAS_STD_FLOATS + { + // for C++23 + // defined in + +#if __STDCPP_FLOAT64_T__ != 1 +#error "64-bit float type required" +#endif + // testing new float types + std::float32_t f{ 1.0f }; + std::float64_t d{ 1.0 }; + std::float128_t l{ 1.0l }; + } +#endif + { std::cout << grisu(1.0) << '\n'; } diff --git a/mixedprecision/approximation/taylor.cpp b/mixedprecision/approximation/taylor.cpp index a1d4f1336..b3452eb42 100644 --- a/mixedprecision/approximation/taylor.cpp +++ b/mixedprecision/approximation/taylor.cpp @@ -1,6 +1,7 @@ // taylor.cpp: mixed-precision experiments with Taylor expansions // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/mixedprecision/integration/simpson.cpp b/mixedprecision/integration/simpson.cpp index 0540e314a..5515606ce 100644 --- a/mixedprecision/integration/simpson.cpp +++ b/mixedprecision/integration/simpson.cpp @@ -1,6 +1,7 @@ // simpson.cpp: mixed-precision experiments with simpson rule integration // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/mixedprecision/integration/trapezoidal.cpp b/mixedprecision/integration/trapezoidal.cpp index e6d494f97..7257a723a 100644 --- a/mixedprecision/integration/trapezoidal.cpp +++ b/mixedprecision/integration/trapezoidal.cpp @@ -1,6 +1,7 @@ // trapezoidal.cpp: mixed-precision experiments with trapezoidal rule integration // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/mixedprecision/interpolation/spline.cpp b/mixedprecision/interpolation/spline.cpp index b7ce873fd..c2ef7bc27 100644 --- a/mixedprecision/interpolation/spline.cpp +++ b/mixedprecision/interpolation/spline.cpp @@ -1,6 +1,7 @@ // spline.cpp: mixed-precision experiments with spline interpolation // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/mixedprecision/optimization/secant.cpp b/mixedprecision/optimization/secant.cpp index 08e01c716..6ded3081c 100644 --- a/mixedprecision/optimization/secant.cpp +++ b/mixedprecision/optimization/secant.cpp @@ -1,6 +1,7 @@ // secant.cpp: mixed-precision experiments with Secant method for optimization // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/mixedprecision/roots/secant.cpp b/mixedprecision/roots/secant.cpp index 42e9e0a77..d140c1ecc 100644 --- a/mixedprecision/roots/secant.cpp +++ b/mixedprecision/roots/secant.cpp @@ -1,6 +1,7 @@ // secant.cpp: mixed-precision experiments with Secant method // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/mixedprecision/tensor/cg/cg.cpp b/mixedprecision/tensor/cg/cg.cpp index 002594c5b..dd0814c4d 100644 --- a/mixedprecision/tensor/cg/cg.cpp +++ b/mixedprecision/tensor/cg/cg.cpp @@ -1,7 +1,8 @@ // cg.cpp: multi-precision, preconditioned Conjugate Gradient iterative solver using Fused Dot Products // using matrix-vector fused dot product operator, and compensation fused dot product operators // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/mixedprecision/tensor/cg/cg_mvdot_cmpdot.cpp b/mixedprecision/tensor/cg/cg_mvdot_cmpdot.cpp index 1df16c043..92f003e9e 100644 --- a/mixedprecision/tensor/cg/cg_mvdot_cmpdot.cpp +++ b/mixedprecision/tensor/cg/cg_mvdot_cmpdot.cpp @@ -1,7 +1,8 @@ // cg_mvdot_cmpdot.cpp: multi-precision, preconditioned Conjugate Gradient iterative solver // using matrix-vector dot product operator and compensation dot product operator // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/mixedprecision/tensor/cg/cg_mvdot_cmpfdp.cpp b/mixedprecision/tensor/cg/cg_mvdot_cmpfdp.cpp index ca51d0421..6e7dd62c8 100644 --- a/mixedprecision/tensor/cg/cg_mvdot_cmpfdp.cpp +++ b/mixedprecision/tensor/cg/cg_mvdot_cmpfdp.cpp @@ -1,7 +1,8 @@ // cg_mvdot_cmpfdp.cpp: multi-precision, preconditioned Conjugate Gradient iterative solver // using matrix-vector dot product operator and compensation fused-dot product operator // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/mixedprecision/tensor/cg/cg_mvfdp_cmpdot.cpp b/mixedprecision/tensor/cg/cg_mvfdp_cmpdot.cpp index 79a976e89..a0cedea36 100644 --- a/mixedprecision/tensor/cg/cg_mvfdp_cmpdot.cpp +++ b/mixedprecision/tensor/cg/cg_mvfdp_cmpdot.cpp @@ -1,7 +1,8 @@ // cg_mvfdp_cmpdot.cpp: multi-precision, preconditioned Conjugate Gradient iterative solver // using matrix-vector FDP operator, and compensation dot operators // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/mixedprecision/tensor/cg/cg_mvfdp_cmpfdp.cpp b/mixedprecision/tensor/cg/cg_mvfdp_cmpfdp.cpp index 8eb72dd6a..6624f3503 100644 --- a/mixedprecision/tensor/cg/cg_mvfdp_cmpfdp.cpp +++ b/mixedprecision/tensor/cg/cg_mvfdp_cmpfdp.cpp @@ -1,7 +1,8 @@ // cg_mvfdp_cmpfdp.cpp: multi-precision, preconditioned Conjugate Gradient iterative solver using Fused Dot Products // using matrix-vector fused dot product operator, and compensation fused dot product operators // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // Authors: Theodore Omtzigt // // This file is part of the universal numbers project, which is released under an MIT Open Source license. diff --git a/mixedprecision/tensor/dnn/inference.cpp b/mixedprecision/tensor/dnn/inference.cpp index 6ca10635c..9fa49db4f 100644 --- a/mixedprecision/tensor/dnn/inference.cpp +++ b/mixedprecision/tensor/dnn/inference.cpp @@ -1,7 +1,7 @@ // inference.cpp: multi-precision inference engine using Fused Dot Products and different number systems // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. -// Authors: Theodore Omtzigt +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/playground/CMakeLists.txt b/playground/CMakeLists.txt index 71be5c90c..3d16f61a0 100644 --- a/playground/CMakeLists.txt +++ b/playground/CMakeLists.txt @@ -1,13 +1,25 @@ -file (GLOB ALL_SRCS "./*.cpp") +#file (GLOB ALL_SRCS "./*.cpp") -set(COMPLEX_SRC complex.cpp) +set(COMPLEX_SRCS complex.cpp) -set(SRCS efunc_posits.cpp +set(REAL_SRCS efunc_posits.cpp efunc_valids.cpp gismo_test.cpp meta_programming.cpp serialization.cpp skeleton.cpp - type_test.cpp) + type_test.cpp + float_to_decimal_string.cpp +) -compile_all("true" "playground" "Playground" "${SRCS}") +compile_all("true" "playground" "Playground" "${REAL_SRCS}") + +# exclude AppleClang as XCode14 and Xcode15 have std::complex libs that do not support user defined types5 +if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") + message(STATUS "Ignoring complex playground tests for AppleClang") + +else() + message(STATUS "Adding complex test for all other non-AppleClang environments") + compile_all("true" "playground" "Playground" "${COMPLEX_SRCS}") + +endif() diff --git a/playground/float_to_decimal_string.cpp b/playground/float_to_decimal_string.cpp new file mode 100644 index 000000000..0f9465f99 --- /dev/null +++ b/playground/float_to_decimal_string.cpp @@ -0,0 +1,74 @@ +// float_to_decimal_string.cpp: experiments with algorithms to convert a Real value to a string of decimal digits +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include + +#include + +int main(int argc, char** argv) +try { + using namespace sw::universal; + + float f = 3.14156; + float x = f * 1e6; + long long int y = static_cast(x); + + std::vector V; + while (y) { + std::cout << y << " : " << (y % 10) << " : " << (y / 10) << '\n'; + V.push_back(y % 10 + '0'); + y /= 10; + } + std::reverse(V.begin(), V.end()); + + std::string S; + for (size_t i = 0; i < V.size() - 6; ++i) { + S.push_back(V[i]); + } + S.push_back('.'); + for (size_t i = V.size() - 6; i < V.size(); ++i) { + S.push_back(V[i]); + } + + size_t i = S.size(); + while (i--) { + if (S[i] == '0') { + S.erase(S.begin() + i); + } + else { + break; + } + } + + std::cout << "Custom conversion: " << S << std::endl; + + return EXIT_SUCCESS; +} +catch (char const* msg) { + std::cerr << "Caught exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Uncaught universal arithmetic exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Uncaught universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Uncaught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/areal/api/constexpr.cpp b/static/areal/api/constexpr.cpp index 57cda01e0..552dc60be 100644 --- a/static/areal/api/constexpr.cpp +++ b/static/areal/api/constexpr.cpp @@ -13,10 +13,8 @@ #include #include -#if BIT_CAST_SUPPORT // stylistic constexpr of pi that we'll assign constexpr to an areal constexpr double pi = 3.14159265358979323846; -#endif template void TestConstexprConstruction() { @@ -29,20 +27,18 @@ void TestConstexprConstruction() { constexpr Real a(1ul); // unsigned long std::cout << a << '\n'; } -#if BIT_CAST_SUPPORT { - CONSTEXPRESSION Real a(1.0f); // float + BIT_CAST_CONSTEXPR Real a(1.0f); // float std::cout << a << '\n'; } { - CONSTEXPRESSION Real a(pi); // double + BIT_CAST_CONSTEXPR Real a(pi); // double std::cout << a << '\n'; } { - CONSTEXPRESSION Real a(1.0l); // long double + BIT_CAST_CONSTEXPR Real a(1.0l); // long double std::cout << a << '\n'; } -#endif // BIT_CAST_SUPPORT } template @@ -56,20 +52,18 @@ void TestConstexprAssignment() { constexpr Real a = 1ul; // unsigned long std::cout << a << '\n'; } -#if BIT_CAST_SUPPORT { - CONSTEXPRESSION Real a = 1.0f; // float + BIT_CAST_CONSTEXPR Real a = 1.0f; // float std::cout << a << '\n'; } { - CONSTEXPRESSION Real a = pi; // double + BIT_CAST_CONSTEXPR Real a = pi; // double std::cout << a << '\n'; } { - CONSTEXPRESSION Real a = 1.0l; // long double + BIT_CAST_CONSTEXPR Real a = 1.0l; // long double std::cout << a << '\n'; } -#endif // BIT_CAST_SUPPORT } // diff --git a/static/bfloat/api/api.cpp b/static/bfloat/api/api.cpp index e4aafdb82..68aadbc54 100644 --- a/static/bfloat/api/api.cpp +++ b/static/bfloat/api/api.cpp @@ -1,12 +1,13 @@ // api.cpp: application programming interface tests for bfloat16 number system // -// Copyright (C) 2022-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include // minimum set of include files to reflect source code dependencies -// Configure the cfloat template environment +// Configure the bfloat template environment // enable/disable arithmetic exceptions #define BFLOAT_THROW_ARITHMETIC_EXCEPTION 0 #include @@ -17,7 +18,7 @@ int main() try { using namespace sw::universal; - std::string test_suite = "bfloat16 Application Programming Interface tests"; + std::string test_suite = "bfloat16 API tests"; int nrOfFailedTestCases = 0; { @@ -33,7 +34,7 @@ try { } // default behavior - std::cout << "+--------- Default bfloat has subnormals, but no supernormals\n"; + std::cout << "+--------- Default bfloat16 has subnormals, but no supernormals\n"; { using Real = bfloat16; @@ -42,11 +43,10 @@ try { } // report on the dynamic range of some standard configurations - std::cout << "+--------- Dynamic ranges of standard cfloat configurations --------+\n"; + std::cout << "+--------- Dynamic ranges of standard bfloat16 configurations --------+\n"; { bfloat16 bf; // uninitialized - bf.maxpos(); std::cout << "maxpos bfloat16 : " << to_binary(bf) << " : " << bf << '\n'; bf.setbits(0x0080); // positive min normal @@ -132,7 +132,7 @@ try { bfloat16 a{ 0 }; // initialized std::cout << "maxpos : " << a.maxpos() << " : " << scale(a) << '\n'; std::cout << "minpos : " << a.minpos() << " : " << scale(a) << '\n'; - std::cout << "zero : " << a.zero() << " : " << scale(a) << '\n'; + std::cout << "zero : " << a.zero() << " : " << scale(a) << '\n'; std::cout << "minneg : " << a.minneg() << " : " << scale(a) << '\n'; std::cout << "maxneg : " << a.maxneg() << " : " << scale(a) << '\n'; std::cout << dynamic_range() << std::endl; diff --git a/static/bfloat/api/attributes.cpp b/static/bfloat/api/attributes.cpp index ed41ce03a..00479b711 100644 --- a/static/bfloat/api/attributes.cpp +++ b/static/bfloat/api/attributes.cpp @@ -1,6 +1,7 @@ // attributes.cpp: attribute tests for Google Brain floating-point // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/static/bfloat/api/traits.cpp b/static/bfloat/api/traits.cpp index 87cd24f33..e1c420508 100644 --- a/static/bfloat/api/traits.cpp +++ b/static/bfloat/api/traits.cpp @@ -1,20 +1,10 @@ -// traits.cpp: tests for type and number traits for arbitrary configuration classic floating-point types +// traits.cpp: tests for type and number traits for Google bfloat16 floating-point type // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include - -// Configure the posit template environment -// first: enable general or specialized configurations -#define CFLOAT_FAST_SPECIALIZATION -// second: enable/disable arithmetic exceptions -#define CFLOAT_THROW_ARITHMETIC_EXCEPTION 1 -// third: enable support for native literals in logic and arithmetic operations -#define CFLOAT_ENABLE_LITERALS 1 -// fourth: enable/disable error-free serialization I/O -#define CFLOAT_ERROR_FREE_IO_FORMAT 0 -// minimum set of include files to reflect source code dependencies #include #include #include diff --git a/static/bfloat/arithmetic/addition.cpp b/static/bfloat/arithmetic/addition.cpp index fc9c5007a..f2f5813bd 100644 --- a/static/bfloat/arithmetic/addition.cpp +++ b/static/bfloat/arithmetic/addition.cpp @@ -1,6 +1,7 @@ // addition.cpp: test suite runner for addition on bfloat16s // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/static/bfloat/arithmetic/arithmetic.cpp b/static/bfloat/arithmetic/arithmetic.cpp index af2252233..926323e06 100644 --- a/static/bfloat/arithmetic/arithmetic.cpp +++ b/static/bfloat/arithmetic/arithmetic.cpp @@ -1,6 +1,7 @@ // arithmetic.cpp: test suite runner for arithmetic on bfloat16s // // Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/static/bfloat/math/pow.cpp b/static/bfloat/math/pow.cpp index bb6fefbac..c43cdcdc2 100644 --- a/static/bfloat/math/pow.cpp +++ b/static/bfloat/math/pow.cpp @@ -1,6 +1,7 @@ // pow.cpp: test suite runner for pow function // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/static/cfloat/api/constexpr.cpp b/static/cfloat/api/constexpr.cpp index 3344fce31..743fdff27 100644 --- a/static/cfloat/api/constexpr.cpp +++ b/static/cfloat/api/constexpr.cpp @@ -15,10 +15,8 @@ #include #include -#if BIT_CAST_SUPPORT // stylistic constexpr of pi that we'll assign constexpr to an cfloat constexpr double pi = 3.14159265358979323846; -#endif // BIT_CAST_SUPPORT template void TestConstexprConstruction() { @@ -31,22 +29,20 @@ void TestConstexprConstruction() { constexpr Real a(1ul); // unsigned long std::cout << a << '\n'; } -#if BIT_CAST_SUPPORT { - CONSTEXPRESSION Real a(1.0f); // float + BIT_CAST_CONSTEXPR Real a(1.0f); // float std::cout << a << '\n'; } { - CONSTEXPRESSION Real a(pi); // double + BIT_CAST_CONSTEXPR Real a(pi); // double std::cout << a << '\n'; } #if LONG_DOUBLE_SUPPORT { - CONSTEXPRESSION Real a(1.0l); // long double + Real a(1.0l); // long double std::cout << a << '\n'; } #endif -#endif // BIT_CAST_SUPPORT } template @@ -60,23 +56,20 @@ void TestConstexprAssignment() { constexpr Real a = 1ul; // unsigned long std::cout << a << '\n'; } -#if BIT_CAST_SUPPORT { - CONSTEXPRESSION Real a = 1.0f; // float + BIT_CAST_CONSTEXPR Real a = 1.0f; // float std::cout << a << '\n'; } { - CONSTEXPRESSION Real a = pi; // double + BIT_CAST_CONSTEXPR Real a = pi; // double std::cout << a << '\n'; } #if LONG_DOUBLE_SUPPORT { - CONSTEXPRESSION Real a = 1.0l; // long double + Real a = 1.0l; // long double std::cout << a << '\n'; } #endif - -#endif // BIT_CAST_SUPPORT } template diff --git a/static/cfloat/conversion/float_conversion.cpp b/static/cfloat/conversion/float_conversion.cpp index 2d5383459..14163e579 100644 --- a/static/cfloat/conversion/float_conversion.cpp +++ b/static/cfloat/conversion/float_conversion.cpp @@ -19,7 +19,7 @@ #include //#include // only used for value table generation -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSEXPR void ToNativeBug() { // now resolved... exponentiation was incorrect using namespace sw::universal; constexpr size_t nbits = 32; @@ -56,7 +56,7 @@ void ToNativeBug() { // now resolved... exponentiation was incorrect std::cout << "raw exp : " << to_binary(rawExponentBits) << '\n'; std::cout << "raw frac : " << to_binary(rawFractionBits) << '\n'; } -#endif // BIT_CAST_SUPPORT +#endif // BIT_CAST_IS_CONSTEXPR /* b0.00000000.00000000000000000000001 : 1.401298464324817e-45 diff --git a/static/cfloat/math/fractional.cpp b/static/cfloat/math/fractional.cpp index 57957162b..cae95c76e 100644 --- a/static/cfloat/math/fractional.cpp +++ b/static/cfloat/math/fractional.cpp @@ -168,8 +168,8 @@ Real trace_fmod(Real x, Real y) { /* std::remainder(x, y) The IEEE floating-point remainder of the division operation x/y calculated by this function is -exactly the value x - n*y, where the value n is the integral value nearest the exact value x/y. -When |n-x/y| = ½, the value n is chosen to be even. +exactly the value x - quo*y, where the value quo is the integral value nearest the exact value x/y. +When |quo-x/y| = 1/2, then the value quo is chosen to be even. In contrast to std::fmod(), the returned value is not guaranteed to have the same sign as x. diff --git a/static/constexpr_directive b/static/constexpr_directive index d4063417d..f41e6e134 100644 --- a/static/constexpr_directive +++ b/static/constexpr_directive @@ -1,10 +1,10 @@ -// BIT_CAST_SUPPORT is compiler env dependent and drives the algorith selection of ieee-754 decode +// now using auto configuration via bit_cast.hpp which will define +// BIT_CAST_IS_CONSTEXPR == true if bit_cast is supported + #if defined(__clang__) /* Clang/LLVM. ---------------------------------------------- */ -#define BIT_CAST_SUPPORT 0 - #elif defined(__ICC) || defined(__INTEL_COMPILER) /* Intel ICC/ICPC. ------------------------------------------ */ @@ -12,8 +12,6 @@ #elif defined(__GNUC__) || defined(__GNUG__) /* GNU GCC/G++. --------------------------------------------- */ -#define BIT_CAST_SUPPORT 0 - #elif defined(__HP_cc) || defined(__HP_aCC) /* Hewlett-Packard C/aC++. ---------------------------------- */ @@ -23,8 +21,6 @@ #elif defined(_MSC_VER) /* Microsoft Visual Studio. --------------------------------- */ -#define BIT_CAST_SUPPORT 1 - #elif defined(__PGI) /* Portland Group PGCC/PGCPP. ------------------------------- */ diff --git a/static/dbns/conversion/rounding.cpp b/static/dbns/conversion/rounding.cpp index 489d03737..1393e0e8f 100644 --- a/static/dbns/conversion/rounding.cpp +++ b/static/dbns/conversion/rounding.cpp @@ -51,7 +51,6 @@ namespace sw { namespace universal { void create5_2() { using DBNS5_2_sat = dbns<5, 2, uint8_t, Behavior::Saturating>; - DBNS5_2_sat d{ 0 }; std::vector> ordered; generateOrderedSet(ordered); for (auto p : ordered) { @@ -60,7 +59,6 @@ namespace sw { namespace universal { } void create7_3() { using DBNS7_3_sat = dbns<7, 3, uint8_t, Behavior::Saturating>; - DBNS7_3_sat d{ 0 }; std::vector> ordered; generateOrderedSet(ordered); for (auto p : ordered) { diff --git a/static/dd/CMakeLists.txt b/static/dd/CMakeLists.txt new file mode 100644 index 000000000..1f19a6244 --- /dev/null +++ b/static/dd/CMakeLists.txt @@ -0,0 +1,13 @@ +file (GLOB API_SRC "api/*.cpp") +file (GLOB LOGIC_SRC "logic/*.cpp") +file (GLOB CONVERSION_SRC "conversion/*.cpp") +file (GLOB ARITHMETIC_SRC "arithmetic/*.cpp") +file (GLOB MATH_SRC "./math/*.cpp") +file (GLOB PERFORMANCE_SRC "./performance/*.cpp") + +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/api" "${API_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/logic" "${LOGIC_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/conversion" "${CONVERSION_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/arithmetic" "${ARITHMETIC_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/math" "${MATH_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/performance" "${PERFORMANCE_SRC}") diff --git a/static/dd/api/api.cpp b/static/dd/api/api.cpp new file mode 100644 index 000000000..b53c210c2 --- /dev/null +++ b/static/dd/api/api.cpp @@ -0,0 +1,316 @@ +// api.cpp: application programming interface tests for double-double (dd) number system +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +// minimum set of include files to reflect source code dependencies +// Configure the dd template environment +// enable/disable arithmetic exceptions +#define DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION 0 +#include +#include +#include +#include + + + +namespace sw { + namespace universal { + + template + void Progression(Real v) { + using namespace sw::universal; + + auto oldPrec = std::cout.precision(); + float f{ float(v) }; + std::cout << std::setprecision(7); + std::cout << to_binary(f, true) << " : " << f << '\n'; + + double d{ v }; + std::cout << std::setprecision(17); + std::cout << to_binary(d, true) << " : " << d << '\n'; + + dd a{ v }; + std::cout << std::setprecision(35); + std::cout << to_binary(a, true) << " : " << a << '\n'; + std::cout << std::setprecision(oldPrec); + } + + dd parse(const std::string& str) { + using namespace sw::universal; + + dd v(str); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(std::numeric_limits::digits10); + std::cout << "string: " << str << " = ( " << v.high() << ", " << v.low() << ") "; + std::cout << std::setprecision(oldPrec); + return v; + } + + void print(std::ostream& ostr, dd const& v) { + std::ios_base::fmtflags fmt = ostr.flags(); + bool showpos = (fmt & std::ios_base::showpos) != 0; + bool uppercase = (fmt & std::ios_base::uppercase) != 0; + bool fixed = (fmt & std::ios_base::fixed) != 0; + bool scientific = (fmt & std::ios_base::scientific) != 0; + bool internal = (fmt & std::ios_base::internal) != 0; + bool left = (fmt & std::ios_base::left) != 0; + std::string str = v.to_string(ostr.precision(), ostr.width(), fixed, scientific, internal, left, showpos, uppercase, ostr.fill()); + ostr << str << '\n'; + } + + } +} + + + + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble (dd) API tests"; + int nrOfFailedTestCases = 0; + + auto oldPrec = std::cout.precision(); + + // important behavioral traits + { + using TestType = dd; + ReportTrivialityOfType(); + } + + // default behavior + std::cout << "+--------- Default dd has subnormals, but no supernormals\n"; + { + uint64_t big = (1ull << 53); + std::cout << to_binary(big) << " : " << big << '\n'; + dd a(big), b(1.0), c{}; + c = a + b; + ReportValue(a, "a"); + ReportValue(b, "b"); + ReportValue(c, "c"); + } + + // arithmetic behavior + std::cout << "+--------- Default dd has subnormals, but no supernormals\n"; + { + dd a(2.0), b(4.0); + ArithmeticOperators(a, b); + } + + std::cout << "+--------- fraction bit progressions \n"; + { + float fulp = ulp(1.0f); + Progression(1.0f + fulp); + Progression(1.0 + ulp(2.0)); + double v = ulp(1.0); + Progression( 1.0 - v/2.0 ); + std::cout << to_pair(dd(1.0 - v / 2.0)) << '\n'; + } + + // report on the dynamic range of some standard configurations + std::cout << "+--------- Dynamic range doubledouble configurations --------+\n"; + { + dd a; // uninitialized + + a.maxpos(); + std::cout << "maxpos doubledouble : " << to_binary(a) << " : " << a << '\n'; + a.setbits(0x0080); // positive min normal + std::cout << "minnorm doubledouble : " << to_binary(a) << " : " << a << '\n'; + a.minpos(); + std::cout << "minpos doubledouble : " << to_binary(a) << " : " << a << '\n'; + a.zero(); + std::cout << "zero : " << to_binary(a) << " : " << a << '\n'; + a.minneg(); + std::cout << "minneg doubledouble : " << to_binary(a) << " : " << a << '\n'; + a.maxneg(); + std::cout << "maxneg doubledouble : " << to_binary(a) << " : " << a << '\n'; + + std::cout << "---\n"; + } + + // constexpr and specific values + std::cout << "+--------- constexpr and specific values --------+\n"; + { + using Real = dd; + + CONSTEXPRESSION Real a{}; // zero constexpr + std::cout << type_tag(a) << '\n'; + + Real b(1.0f); // constexpr of a native type conversion + std::cout << to_binary(b) << " : " << b << '\n'; + + CONSTEXPRESSION Real c(SpecificValue::minpos); // constexpr of a special value in the encoding + std::cout << to_binary(c) << " : " << c << " == minpos" << '\n'; + + CONSTEXPRESSION Real d(SpecificValue::maxpos); // constexpr of a special value in the encoding + std::cout << to_binary(d) << " : " << d << " == maxpos" << '\n'; + } + + // set bit patterns + std::cout << "+--------- set bit patterns API --------+\n"; + { + using Real = dd; + + Real a; // uninitialized + std::cout << type_tag(a) << '\n'; + + a.setbits(0x0000); + std::cout << to_binary(a) << " : " << a << '\n'; + + a.setbit(8); + std::cout << to_binary(a) << " : " << a << " : set bit 8 assuming 0-based" << '\n'; + a.setbits(0xffff); + a.setbit(8, false); + std::cout << to_binary(a) << " : " << a << " : reset bit 8" << '\n'; + + a.setbits(0xAAAA); + std::cout << to_binary(a) << " : " << a << '\n'; + + a.assign(std::string("0b1.0101'0101.0101'010")); + std::cout << to_binary(a) << " : " << a << '\n'; + + a.assign(std::string("0b0.1010'1010.1010'101")); + std::cout << to_binary(a) << " : " << a << '\n'; + } + + // parse decimal strings + std::cout << "+--------- parse API --------+\n"; + { + std::string ddstr; + dd v; + + v = parse("0.0"); + ddstr = v.to_string(25, 25, true, false, false, false, true, false, ' '); + std::cout << ddstr << '\n'; + + std::cout << std::setprecision(7); + print(std::cout, parse("0.5")); + print(std::cout, parse("1.0")); + print(std::cout, parse("2.0")); + + // 100 digits of e + // 10 2.7182818284 + // 20 2.71828182845904523536 + // 30 2.718281828459045235360287471352 + // 40 2.7182818284590452353602874713526624977572 + // 50 2.71828182845904523536028747135266249775724709369995 + // 60 2.718281828459045235360287471352662497757247093699959574966967 + // 70 2.7182818284590452353602874713526624977572470936999595749669676277240766 + // 80 2.71828182845904523536028747135266249775724709369995957496696762772407663035354759 + // 90 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178 + // 100 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274 + ReportValue(std::numbers::e, "e", 10, 25); + std::cout << std::setprecision(10); + print(std::cout, parse("2.7182818284")); // 10 digits + std::cout << std::setprecision(15); + print(std::cout, parse("2.71828182845904")); // 15 digits + std::cout << std::setprecision(20); + print(std::cout, parse("2.71828182845904523536")); // 20 digits + std::cout << std::setprecision(30); + print(std::cout, parse("2.718281828459045235360287471352")); // 30 digits + std::cout << std::setprecision(40); + print(std::cout, parse("2.7182818284590452353602874713526624977572")); // 40 digits + + std::cout << std::setprecision(37); + print(std::cout, parse("2.718281828459045235360287471352662498")); //37 digits + std::cout << std::setprecision(oldPrec); + } + + std::cout << "+--------- set specific values of interest --------+\n"; + { + dd a{ 0 }; // initialized + std::cout << "maxpos : " << a.maxpos() << " : " << scale(a) << '\n'; + std::cout << "minpos : " << a.minpos() << " : " << scale(a) << '\n'; + std::cout << "zero : " << a.zero() << " : " << scale(a) << '\n'; + std::cout << "minneg : " << a.minneg() << " : " << scale(a) << '\n'; + std::cout << "maxneg : " << a.maxneg() << " : " << scale(a) << '\n'; + std::cout << dynamic_range
() << std::endl; + } + + std::cout << "+--------- doubledouble subnormal behavior --------+\n"; + { + constexpr double minpos = std::numeric_limits::min(); + std::cout << to_binary(minpos) << " : " << minpos << '\n'; + double subnormal = minpos / 2.0; + std::cout << to_binary(subnormal) << " : " << subnormal << '\n'; + dd a(minpos); + for (int i = 0; i < 10/*106*/; ++i) { + std::string str = a.to_string(30, 40, false, true, false, false, false, false, ' '); + std::cout << to_binary(a) << " : " << a << " : " << str << '\n'; + a /= 2.0; + } + } + + std::cout << "+--------- special value properties doubledouble vs IEEE-754 --------+\n"; + { + float fa; + fa = NAN; + std::cout << "qNAN : " << to_binary(NAN) << '\n'; + std::cout << "sNAN : " << to_binary(-NAN) << '\n'; + if (fa < 0.0f && fa > 0.0f && fa != 0.0f) { + std::cout << "IEEE-754 is incorrectly implemented\n"; + } + else { + std::cout << "IEEE-754 NAN has no sign\n"; + } + + dd a(fa); + if ((a < 0.0f && a > 0.0f && a != 0.0f)) { + std::cout << "doubledouble (dd) is incorrectly implemented\n"; + ++nrOfFailedTestCases; + } + else { + std::cout << "dd NAN has no sign\n"; + } + } + + std::cout << "+--------- numeric_limits of doubledouble vs IEEE-754 --------+\n"; + { + std::cout << "dd(INFINITY): " << dd(INFINITY) << "\n"; + std::cout << "dd(-INFINITY): " << dd(-INFINITY) << "\n"; + + std::cout << "dd(std::numeric_limits::infinity()) : " << dd(std::numeric_limits::infinity()) << "\n"; + std::cout << "dd(-std::numeric_limits::infinity()) : " << dd(-std::numeric_limits::infinity()) << "\n"; + + std::cout << " 2 * std::numeric_limits::infinity() : " << 2 * std::numeric_limits::infinity() << "\n"; + std::cout << " 2 * std::numeric_limits::infinity() : " << 2 * std::numeric_limits::infinity() << "\n"; + std::cout << "-2 * std::numeric_limits
::infinity() : " << -2 * std::numeric_limits
::infinity() << "\n"; + + std::cout << "sw::universal::nextafter(dd(0), std::numeric_limits
::infinity()) : " << sw::universal::nextafter(dd(-0), std::numeric_limits
::infinity()) << "\n"; + std::cout << "std::nextafter(float(0), std::numeric_limits::infinity()) : " << std::nextafter(float(-0), std::numeric_limits::infinity()) << "\n"; + std::cout << "sw::universal::nextafter(dd(0), -std::numeric_limits
::infinity()) : " << sw::universal::nextafter(dd(0), -std::numeric_limits
::infinity()) << "\n"; + std::cout << "std::nextafter(float(0), -std::numeric_limits::infinity()) : " << std::nextafter(float(0), -std::numeric_limits::infinity()) << "\n"; + + std::cout << "cfloat(std::numeric_limits::signaling_NaN()).isnan(sw::universal::NAN_TYPE_QUIET) : " << dd(std::numeric_limits::signaling_NaN()).isnan(sw::universal::NAN_TYPE_QUIET) << "\n"; + std::cout << "cfloat(std::numeric_limits::signaling_NaN()).isnan(sw::universal::NAN_TYPE_SIGNALLING) : " << dd(std::numeric_limits::signaling_NaN()).isnan(sw::universal::NAN_TYPE_SIGNALLING) << "\n"; + } + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/api/attributes.cpp b/static/dd/api/attributes.cpp new file mode 100644 index 000000000..c0a3693d4 --- /dev/null +++ b/static/dd/api/attributes.cpp @@ -0,0 +1,171 @@ +// attributes.cpp: attribute tests for Google Brain floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include + +// Configure the bfloat and cfloat template environment +// enable/disable arithmetic exceptions +#define DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION 1 +#define CFLOAT_THROW_ARITHMETIC_EXCEPTION 1 +// enable support for native literals in logic and arithmetic operations +#define DOUBLEDOUBLE_ENABLE_LITERALS 1 +#define CFLOAT_ENABLE_LITERALS 1 +#include +#include +#include + +template +void NumericalLimits() { + Real a; + std::cout << "minpos : " << to_binary(a.minpos()) << " : " << a << '\n'; + std::cout << "maxpos : " << to_binary(a.maxpos()) << " : " << a << '\n'; + std::cout << "maxneg : " << to_binary(a.maxneg()) << " : " << a << '\n'; + std::cout << "minneg : " << to_binary(a.minneg()) << " : " << a << '\n'; + Real epsilon = std::numeric_limits::epsilon(); + std::cout << "epsilon: " << to_binary(epsilon) << " : " << epsilon << '\n'; +} + +void ConstructExtremeValues() { + using namespace sw::universal; + + auto oldPrec = std::cout.precision(); + + // construct the doubledouble maxpos bit pattern + using Cfloat = cfloat<64, 11, uint32_t, true, false, false>; + Cfloat a, b(1.7976931348623157e+308); + a.maxpos(); + std::cout << std::setprecision(25); + std::cout << to_binary(a) << " : " << a << '\n'; + std::cout << to_binary(b) << " : " << b << '\n'; + // maxpos exponent is 0b111'1111'1110; + // lo segment is scaled by 2^53 + int i = 0x7fE; + std::cout << "exponent is " << i - Cfloat::EXP_BIAS << '\n'; + std::cout << "lo exponent is " << (i - Cfloat::EXP_BIAS - 53) << '\n'; + std::cout << to_binary(i - 53) << '\n'; // get the unbiased scaled exponent value + // 111'1100'1001 + a.setbits(0x7C9F'FFFF'FFFF'FFFFull); + std::cout << to_binary(a) << " : " << a << '\n'; + b = 1.9958403095347196e+292; + std::cout << to_binary(b) << " : " << b << '\n'; + + // construct the doubledouble minpos bit pattern + a.minpos(); + b = 1.0; + std::cout << to_binary(a) << " : " << a << '\n'; + std::cout << to_binary(b) << " : " << b << '\n'; + + std::cout << std::setprecision(oldPrec); + +} +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble attribute functions"; + std::string test_tag = "attributes"; + bool reportTestCases = true; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + + ///////////////////////////////////////////////////////////////////////////////////// + //// doubledouble attribute functions + + using doubledouble = dd; + using f117_11 = cfloat<117, 11, uint32_t, true, false, false>; + using f118_11 = cfloat<118, 11, uint32_t, true, false, false>; + + { + std::cout << "Number traits: numeric limits of doubledouble floats\n"; + numberTraits< doubledouble >(std::cout); // doubledouble emulation + numberTraits< f117_11 >(std::cout); // cfloat emulation + std::cout << '\n'; + } + + { + std::cout << "extreme values of doubledouble floats\n"; + NumericalLimits(); + NumericalLimits(); + + dd a(SpecificValue::qnan); + std::cout << to_binary(a) << " : " << a << '\n'; + } + + { + std::cout << "Dynamic range of doubledouble floats\n"; + std::cout << dynamic_range< doubledouble >() << '\n'; + std::cout << dynamic_range< f118_11 >() << '\n'; + std::cout << '\n'; + } + + { + std::cout << "Dynamic range of a doubledouble floating-point\n"; + std::cout << minmax_range< doubledouble >() << '\n'; + std::cout << minmax_range< f118_11 >() << '\n'; + } + { + std::cout << "Dynamic range of a doubledouble floating-point\n"; + std::cout << dd_range() << '\n'; + } + { + std::cout << "Dynamic range of a doubledouble floating-point\n"; + std::cout << symmetry_range< doubledouble >() << '\n'; + std::cout << symmetry_range< f118_11 >() << '\n'; + } + + { + std::cout << "Comparitive Number traits\n"; + compareNumberTraits< doubledouble, f117_11 >(std::cout); + compareNumberTraits< doubledouble, f118_11 >(std::cout); + std::cout << '\n'; + } + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} +catch (char const* msg) { + std::cerr << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Uncaught universal arithmetic exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Uncaught universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Uncaught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} + +/* +Dynamic ranges of different specializations of a 32-bit classic floating-point +cfloat< 32, 8, unsigned int, noSubnormals, noSupernormals, notSaturating> : min 1.17549e-38 max 3.40282e+38 +cfloat< 32, 8, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 1.4013e-45 max 3.40282e+38 +cfloat< 32, 8, unsigned int, noSubnormals, hasSupernormals, notSaturating> : min 1.17549e-38 max 6.80565e+38 +cfloat< 32, 8, unsigned int, hasSubnormals, hasSupernormals, notSaturating> : min 1.4013e-45 max 6.80565e+38 + +Dynamic ranges of different specializations of a 32-bit classic floating-point +cfloat< 32, 8, unsigned int, noSubnormals, noSupernormals, notSaturating> : [ -3.40282e+38 ... -1.17549e-38 0 1.17549e-38 ... 3.40282e+38 ] +cfloat< 32, 8, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -3.40282e+38 ... -1.4013e-45 0 1.4013e-45 ... 3.40282e+38 ] +cfloat< 32, 8, unsigned int, noSubnormals, hasSupernormals, notSaturating> : [ -6.80565e+38 ... -1.17549e-38 0 1.17549e-38 ... 6.80565e+38 ] +cfloat< 32, 8, unsigned int, hasSubnormals, hasSupernormals, notSaturating> : [ -6.80565e+38 ... -1.4013e-45 0 1.4013e-45 ... 6.80565e+38 ] + +Dynamic ranges of different specializations of a 32-bit classic floating-point +cfloat< 32, 8, unsigned int, noSubnormals, noSupernormals, notSaturating> : [ -3.40282e+38, -0 0 -0, 3.40282e+38] +cfloat< 32, 8, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -3.40282e+38, -1.4013e-45 0 1.4013e-45, 3.40282e+38] +cfloat< 32, 8, unsigned int, noSubnormals, hasSupernormals, notSaturating> : [ -6.80565e+38, -0 0 -0, 6.80565e+38] +cfloat< 32, 8, unsigned int, hasSubnormals, hasSupernormals, notSaturating> : [ -6.80565e+38, -1.4013e-45 0 1.4013e-45, 6.80565e+38] + + + */ diff --git a/static/dd/api/constants.cpp b/static/dd/api/constants.cpp new file mode 100644 index 000000000..5537386c3 --- /dev/null +++ b/static/dd/api/constants.cpp @@ -0,0 +1,264 @@ +// constants.cpp: test suite runner for creating and verifying doubledouble constants +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include + +namespace sw { + namespace universal { + + sw::universal::dd GenerateDoubleDouble(const std::string& str) { + using namespace sw::universal; + dd v(str); + auto oldPrec = std::cout.precision(); + // 53 bits = 16 decimal digits, 17 to include last, 15 typical valid digits + std::cout << std::setprecision(std::numeric_limits::max_digits10); + std::cout << to_pair(v) << '\n'; + std::cout << std::setprecision(oldPrec); + return v; + } + + void report(const sw::universal::dd& v, int precision = 17) { + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision) << to_pair(v) << " : " << v << '\n'; + std::cout << std::setprecision(oldPrec); + } + + void EnumerateConstants() { + dd _zero("0.0"); report(_zero); + dd _one("1.0"); report(_one); + dd _ten("10.0"); report(_ten); + + dd _tenth("0.1"); report(_tenth); + dd _third("0.333333333333333333333333333333333333"); report(_third); + + dd _2pi("6.283185307179586476925286766559005768"); report(_2pi); + dd _pi("3.141592653589793238462643383279502884"); report(_pi); + dd _pi2("1.570796326794896619231321691639751442"); report(_pi2); + dd _pi4("0.785398163397448309615660845819875721"); report(_pi4); + dd _3pi4 = _pi2 + _pi4; report(_3pi4); + + dd _e("2.718281828459045235360287471352662498"); report(_e); + + dd _ln2("0.693147180559945309417232121458176568"); report(_ln2); + dd _ln10("2.302585092994045684017991454684364208"); report(_ln10); + + dd _lge("1.442695040888963407359924681001892137"); report(_lge); + dd _lg10("3.321928094887362347870319429489390176"); report(_lg10); + + dd _log2("0.301029995663981195213738894724493027"); report(_log2); + dd _loge("0.434294481903251827651128918916605082"); report(_loge); + + dd _sqrt2("1.414213562373095048801688724209698079"); report(_sqrt2); + + dd _inv_pi("0.318309886183790671537767526745028724"); report(_inv_pi); + dd _inv_pi2("0.636619772367581343075535053490057448"); report(_inv_pi2); + dd _inv_e("0.367879441171442321595523770161460867"); report(_inv_e); + dd _inv_sqrt2("0.707106781186547524400844362104849039"); report(_inv_sqrt2); + } + + int VerifyParse(const std::string& str) { + int nrFailedTestCases{ 0 }; + dd v{}; + if (!parse(str, v)) { + std::cerr << "failed to parse " << str << '\n'; + ++nrFailedTestCases; + } + else { + ReportValue(v, str); + std::cout << "PASS\n"; + } + return nrFailedTestCases; + } + } +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble constants"; + std::string test_tag = "dd constants"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd a, b, c; + double _third = 0.3333333333333333333333333333333; + double _third2 = _third * pow(2.0, -53.0); + double _short = 0.3333333333333333; + ReportValue(_short, "0.3333333333333333", 35, 32); + ReportValue(_third, "0.3333333333333333333333333333333", 35, 32); + + a = _third; + b = _third2; + ReportValue(a, "0.3333....", 35, 32); + ReportValue(b, "0.3333....", 35, 32); + c = a + b; + ReportValue(c, "0.3333....", 35, 32); + std::cout << to_pair(c) << '\n'; + + dd d(_third, _third2); + ReportValue(d, "0.3333....", 35, 32); + std::cout << to_pair(d) << '\n'; + + dd e("0.3333333333333333333333333333333333333333333333333"); + ReportValue(e, "0.3333....", 35, 32); + std::cout << to_pair(e) << '\n'; + + dd f(0.3333333333333333, 1.8503717077085935e-17); + ReportValue(f, "0.3333....", 35, 32); + std::cout << to_pair(f) << '\n'; + + + // parsing scientific formats + VerifyParse("12.5e-2"); + VerifyParse("12.5e-1"); + VerifyParse("12.5e-0"); + VerifyParse("12.5e+1"); + VerifyParse("12.5e2"); + VerifyParse("12.5e-02"); + VerifyParse("12.5e-01"); + VerifyParse("12.5e00"); + VerifyParse("12.5e+01"); + VerifyParse("12.5e02"); + VerifyParse("12.5e-002"); + VerifyParse("12.5e-001"); + VerifyParse("12.5e000"); + VerifyParse("12.5e+001"); + VerifyParse("12.5e002"); + VerifyParse("12.5e-200"); + VerifyParse("12.5e-100"); + VerifyParse("12.5e000"); + VerifyParse("12.5e+100"); + VerifyParse("12.5e200"); + + std::cout << "verifying constants\n"; + struct constant_kv { + std::string name; + std::string digits; + dd value; + } constant_symbol_table[] = { + { "dd_2pi", "6.283185307179586476925286766559005768", dd_2pi }, + { "dd_pi" , "3.141592653589793238462643383279502884", dd_pi }, + { "dd_pi2", "1.570796326794896619231321691639751442", dd_pi2 }, + { "dd_pi4", "0.785398163397448309615660845819875721", dd_pi4 }, + + { "dd_e" , "2.718281828459045235360287471352662498", dd_e }, + + { "dd_ln2", "0.693147180559945309417232121458176568", dd_ln2 }, + { "dd_ln10", "2.302585092994045684017991454684364208", dd_ln10 }, + + { "dd_lge", "1.442695040888963407359924681001892137", dd_lge }, + { "dd_lg10", "3.321928094887362347870319429489390176", dd_lg10 }, + + { "dd_log2", "0.301029995663981195213738894724493027", dd_log2 }, + { "dd_loge", "0.434294481903251827651128918916605082", dd_loge }, + + { "dd_sqrt2", "1.414213562373095048801688724209698079", dd_sqrt2 }, + + { "dd_inv_pi", "0.318309886183790671537767526745028724", dd_inv_pi }, + { "dd_inv_pi2", "0.636619772367581343075535053490057448", dd_inv_pi2 }, + { "dd_inv_e", "0.367879441171442321595523770161460867", dd_inv_e }, + { "dd_inv_sqrt2", "0.707106781186547524400844362104849039", dd_inv_sqrt2 }, + }; + + /* + * + * ETLO August 6, 2024 + * Need to verify if these are the most accurate double-double approximations available. + * +verifying constants +dd_2pi : 6.28318530717958647692528676655896e+00 vs 6.28318530717958647692528676655901e+00 : ( 6.28318530717958620, 2.4492935982947059e-16) : -4.93038065763132378382330353301741e-32 +dd_pi : 3.14159265358979323846264338327948e+00 vs 3.14159265358979323846264338327951e+00 : ( 3.14159265358979310, 1.2246467991473530e-16) : -2.46519032881566189191165176650871e-32 +dd_pi2 : 1.57079632679489661923132169163974e+00 vs 1.57079632679489661923132169163976e+00 : ( 1.57079632679489660, 6.1232339957367648e-17) : -1.23259516440783094595582588325435e-32 +dd_pi4 : 7.85398163397448309615660845819878e-01 vs 7.85398163397448309615660845819878e-01 : ( 0.78539816339744828, 3.0616169978683830e-17) : 0.00000000000000000000000000000000e+00 +dd_e : 2.71828182845904523536028747135264e+00 vs 2.71828182845904523536028747135266e+00 : ( 2.71828182845904510, 1.4456468917292499e-16) : -2.46519032881566189191165176650871e-32 +dd_ln2 : 6.93147180559945309417232121458176e-01 vs 6.93147180559945309417232121458176e-01 : ( 0.69314718055994529, 2.3190468138462996e-17) : 0.00000000000000000000000000000000e+00 +dd_ln10 : 2.30258509299404568401799145468437e+00 vs 2.30258509299404568401799145468437e+00 : ( 2.30258509299404590, -2.1707562233822494e-16) : 0.00000000000000000000000000000000e+00 +dd_lge : 1.44269504088896340735992468100189e+00 vs 1.44269504088896340735992468100189e+00 : ( 1.44269504088896340, 2.0355273740931027e-17) : 0.00000000000000000000000000000000e+00 +dd_lg10 : 3.32192809488736234787031942948935e+00 vs 3.32192809488736234787031942948935e+00 : ( 3.32192809488736220, 1.6616175169735918e-16) : 0.00000000000000000000000000000000e+00 +dd_log2 : 3.01029995663981195213738894724493e-01 vs 6.93147180559945309417232121458176e-01 : ( 0.30102999566398120, -2.8037281277851700e-18) : -3.92117184895964114203493226733683e-01 +dd_loge : 4.34294481903251827651128918916605e-01 vs 4.34294481903251827651128918916605e-01 : ( 0.43429448190325182, 1.0983196502167652e-17) : 0.00000000000000000000000000000000e+00 +dd_sqrt2 : 1.41421356237309504880168872420971e+00 vs 1.41421356237309504880168872420971e+00 : ( 1.41421356237309510, -9.6672933134529122e-17) : 0.00000000000000000000000000000000e+00 +dd_inv_pi : 3.18309886183790671537767526745029e-01 vs 3.18309886183790671537767526745029e-01 : ( 0.31830988618379069, -1.9678676675182486e-17) : 0.00000000000000000000000000000000e+00 +dd_inv_pi2 : 6.36619772367581343075535053490057e-01 vs 6.36619772367581343075535053490057e-01 : ( 0.63661977236758138, -3.9357353350364972e-17) : 0.00000000000000000000000000000000e+00 +dd_inv_e : 3.67879441171442321595523770161459e-01 vs 3.67879441171442321595523770161459e-01 : ( 0.36787944117144233, -1.2428753672788364e-17) : 0.00000000000000000000000000000000e+00 +dd_inv_sqrt2 : 7.07106781186547524400844362104854e-01 vs 7.07106781186547524400844362104854e-01 : ( 0.70710678118654757, -4.8336466567264561e-17) : 0.00000000000000000000000000000000e+00 + */ + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(32); + for (auto e : constant_symbol_table) { + dd c(e.digits); + dd error = (c - e.value); + std::cout << std::left << std::setw(15) << e.name << " : " << c << " vs " << e.value << " : " << to_pair(c) << " : " << error << '\n'; + } + std::cout << std::setprecision(oldPrec); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/api/experiments.cpp b/static/dd/api/experiments.cpp new file mode 100644 index 000000000..86177b2cd --- /dev/null +++ b/static/dd/api/experiments.cpp @@ -0,0 +1,176 @@ +// experiments.cpp: experiments with the doubledouble floating-point number system +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +// minimum set of include files to reflect source code dependencies +// Configure the dd template environment +// enable/disable arithmetic exceptions +#define DOUBLEDOUBLE_THROW_ARITHMETIC_EXCEPTION 0 +#include +#include +#include +#include + +namespace sw { + namespace universal { + + void Progression(double v) { + using namespace sw::universal; + + auto oldPrec = std::cout.precision(); + float f{ float(v) }; + std::cout << std::setprecision(7); + std::cout << to_binary(f, true) << " : " << f << '\n'; + + double d{ v }; + std::cout << std::setprecision(17); + std::cout << to_binary(d, true) << " : " << d << '\n'; + + dd a{ v }; + std::cout << std::setprecision(35); + std::cout << to_binary(a, true) << " : " << a << '\n'; + std::cout << std::setprecision(oldPrec); + } + + void dd_binary(dd const& v) { + std::cout << to_pair(v) << '\n'; + } + + void adjust(dd const& a) { + dd r = abs(a); + dd ten(10.0); + int e{ 0 }; + dd_binary(r); + frexp(r, &e); + std::cout << "exponent : " << e << '\n'; + + if (e < 0) { + if (e > 300) { + r = ldexp(r, 53); dd_binary(r); + r *= pown(ten, -e); dd_binary(r); + r = ldexp(r, -53); dd_binary(r); + } + else { + r *= pown(ten, -e); dd_binary(r); + } + } + else { + if (e > 0) { + if (e > 300) { + r = ldexp(r, -53); dd_binary(r); + r /= pown(ten, e); dd_binary(r); + r = ldexp(r, 53); dd_binary(r); + } + else { + r /= pown(ten, -e); dd_binary(r); + } + } + } + } + } +} + + + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble (dd) experiments"; + int nrOfFailedTestCases = 0; + + auto oldPrec = std::cout.precision(); + + std::cout << "Smallest normal number progressions\n"; + { + constexpr double smallestNormal = std::numeric_limits::min(); + dd a(smallestNormal); + for (int i = 0; i < 10; ++i) { + ReportValue(a); + a *= 2.0; + } + + } + + std::cout << "subnormal exponent adjustment\n"; + { + constexpr double smallestNormal = std::numeric_limits::min(); + dd a{ smallestNormal }; + for (int i = 0; i < 5; ++i) { + adjust(a); + a /= 2.0; + } + a = smallestNormal; + for (int i = 0; i < 5; ++i) { + adjust(a); + a *= 2.0; + } + + } + + std::cout << "+--------- doubledouble subnormal behavior --------+\n"; + { + constexpr double smallestNormal = std::numeric_limits::min(); + ReportValue(smallestNormal, "smallest normal"); + double ulpAtSmallestNormal = ulp(smallestNormal); + ReportValue(ulpAtSmallestNormal, "ulpAtSmallestNormal"); + double subnormal = smallestNormal / 2.0; + std::cout << to_binary(subnormal) << " : " << subnormal << '\n'; + dd a(smallestNormal + ulpAtSmallestNormal); + for (int i = 0; i < 10/*106*/; ++i) { + std::string tag = "pow(a, -" + std::to_string(i) + ")"; + ReportValue(a, tag); + a /= 2.0; + } + } + + std::cout << "--------- decimal string rounding -------------\n"; + { + dd a{}; + int precision = 7; + int nrDigits = precision + 7; + char* s = new char[nrDigits + 1ull]; + int decimalPoint; + + s[0] = '1'; + for (int i = 1; i < nrDigits-1; ++i) { + s[i] = '5'; + } + s[nrDigits - 1] = '\0'; + std::cout << "input digits : " << s << '\n'; + decimalPoint = 7; // 15555.5 + a.round_string(s, precision, &decimalPoint); + std::cout << "rounded digits : " << s << " : decimal point at " << decimalPoint << '\n'; + delete[] s; + } + + std::cout << std::setprecision(oldPrec); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/api/traits.cpp b/static/dd/api/traits.cpp new file mode 100644 index 000000000..8cd2feee3 --- /dev/null +++ b/static/dd/api/traits.cpp @@ -0,0 +1,125 @@ +// traits.cpp: tests for type and number traits for doubledouble (dd) floating-point type +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "bfloat traits"; + std::string test_tag = "traits"; + bool reportTestCases = true; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + + ///////////////////////////////////////////////////////////////////////////////////// + //// bfloat type attribute functions + + { + using Real = dd; + bool isTrivial = bool(std::is_trivial()); + static_assert(std::is_trivial(), "dd should be trivial but failed the assertion"); + std::cout << (isTrivial ? "dd is trivial: PASS" : "dd failed trivial: FAIL") << '\n'; + + bool isTriviallyConstructible = bool(std::is_trivially_constructible()); + static_assert(std::is_trivially_constructible(), "dd should be trivially constructible but failed the assertion"); + std::cout << (isTriviallyConstructible ? "dd is trivial constructible: PASS" : "dd failed trivial constructible: FAIL") << '\n'; + + bool isTriviallyCopyable = bool(std::is_trivially_copyable()); + static_assert(std::is_trivially_copyable(), "dd should be trivially copyable but failed the assertion"); + std::cout << (isTriviallyCopyable ? "dd is trivially copyable: PASS" : "dd failed trivially copyable: FAIL") << '\n'; + + bool isTriviallyCopyAssignable = bool(std::is_trivially_copy_assignable()); + static_assert(std::is_trivially_copy_assignable(), "dd should be trivially copy-assignable but failed the assertion"); + std::cout << (isTriviallyCopyAssignable ? "dd is trivially copy-assignable: PASS" : "dd failed trivially copy-assignable: FAIL") << '\n'; + } + + { + std::cout << "Comparison of dynamic ranges of doubledouble and the standard classic floating-point configuration\n"; + std::cout << dynamic_range< double >() << '\n'; + std::cout << dynamic_range< dd >() << '\n'; + std::cout << symmetry_range< double >() << '\n'; + std::cout << symmetry_range< dd >() << '\n'; + } + { + std::cout << "Comparison of min/max values of doubledouble and the standard classic floating-point configurations\n"; + std::cout << minmax_range< quarter >() << '\n'; + std::cout << minmax_range< half >() << '\n'; + std::cout << minmax_range< single >() << '\n'; + std::cout << minmax_range< duble >() << '\n'; + + std::cout << minmax_range< dd >() << '\n'; + } + + { + std::cout << "Comparison of sampling ranges of doubledouble and the standard classic floating-point configurations\n"; + std::cout << symmetry_range< quarter >() << '\n'; + std::cout << symmetry_range< half >() << '\n'; + std::cout << symmetry_range< single >() << '\n'; + std::cout << symmetry_range< duble >() << '\n'; + + std::cout << symmetry_range< dd >() << '\n'; + } + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} +catch (char const* msg) { + std::cerr << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::cfloat_arithmetic_exception& err) { + std::cerr << "Uncaught cfloat arithmetic exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::cfloat_internal_exception& err) { + std::cerr << "Uncaught cfloat internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Uncaught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} + + +/* +generalized posit traits: report test cases +cfloat is trivial: PASS +poscfloatit is trivial constructible: PASS +cfloat is trivially copyable: PASS +cfloat is trivially copy-assignable: PASS +Dynamic ranges of different specializations of an 8-bit classic floating-point +cfloat< 8, 1, unsigned char, hasSubnormals, hasSupernormals, notSaturating> : minexp scale -1 maxexp scale 1 minimum 0.03125 maximum 3.90625 +cfloat< 8, 2, unsigned char, hasSubnormals, hasSupernormals, notSaturating> : minexp scale -2 maxexp scale 2 minimum 0.03125 maximum 7.625 +cfloat< 8, 3, unsigned char, hasSubnormals, hasSupernormals, notSaturating> : minexp scale -4 maxexp scale 4 minimum 0.015625 maximum 29 +cfloat< 8, 4, unsigned char, hasSubnormals, hasSupernormals, notSaturating> : minexp scale -8 maxexp scale 8 minimum 0.00195312 maximum 416 +cfloat< 8, 5, unsigned char, hasSubnormals, hasSupernormals, notSaturating> : minexp scale -16 maxexp scale 16 minimum 1.52588e-05 maximum 81920 +Dynamic ranges of the standard classic floating-point configurations +cfloat< 8, 2, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 0.03125 max 3.9375 +cfloat< 16, 5, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 5.96046e-08 max 65504 +cfloat< 32, 8, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 1.4013e-45 max 3.40282e+38 +cfloat< 64, 11, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 4.94066e-324 max 1.79769e+308 +cfloat<128, 15, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 0 max inf +cfloat<256, 19, unsigned int, hasSubnormals, noSupernormals, notSaturating> : min 0 max inf +Dynamic ranges of the standard posit configurations +cfloat< 8, 2, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -3.9375, -0.03125 0 0.03125, 3.9375] +cfloat< 16, 5, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -65504, -5.96046e-08 0 5.96046e-08, 65504] +cfloat< 32, 8, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -3.40282e+38, -1.4013e-45 0 1.4013e-45, 3.40282e+38] +cfloat< 64, 11, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -1.79769e+308, -4.94066e-324 0 4.94066e-324, 1.79769e+308] +cfloat<128, 15, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -inf, 0 0 0, inf] +cfloat<256, 19, unsigned int, hasSubnormals, noSupernormals, notSaturating> : [ -inf, 0 0 0, inf] +generalized posit traits: PASS + +*/ diff --git a/static/dd/arithmetic/addition.cpp b/static/dd/arithmetic/addition.cpp new file mode 100644 index 000000000..3dfaa43a7 --- /dev/null +++ b/static/dd/arithmetic/addition.cpp @@ -0,0 +1,114 @@ +// addition.cpp: test suite runner for addition of doubledouble floating-point values +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble addition validation"; + std::string test_tag = "doubledouble addition"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd a, b, c, ulpAtOne, onePlusUlp, onePlusHalfUlp; + + a = 1.0; + ulpAtOne = ulp(1.0); + onePlusUlp = a + ulpAtOne; + b = ulpAtOne; + b /= 2.0; + ReportValue(a, "1.0",35,32); + ReportValue(ulpAtOne, "ulp", 35, 32); + ReportValue(b, "ulp/2", 35, 32); + ReportValue(onePlusUlp, "1.0 + ulp", 35, 32); + c = a + b; + ReportValue(c, "1.0 + ulp/2", 35, 32); + onePlusHalfUlp = a; + onePlusHalfUlp += ulp(0.5); + + std::cout << "1.0 : " << to_pair(a) << '\n'; + std::cout << "1.0 + ulp(1.0) : " << to_pair(onePlusUlp) << '\n'; + std::cout << "1.0 + ulp(0.5) : " << to_pair(onePlusHalfUlp) << '\n'; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + + constexpr unsigned nrOfRandoms = 1000; + std::stringstream s; + s << test_tag << " " << nrOfRandoms << " random pairs"; + std::string description = s.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_ADD, nrOfRandoms), + description, + test_tag + ); + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/arithmetic/arithmetic.cpp b/static/dd/arithmetic/arithmetic.cpp new file mode 100644 index 000000000..aaa3d23cf --- /dev/null +++ b/static/dd/arithmetic/arithmetic.cpp @@ -0,0 +1,396 @@ +// arithmetic.cpp: test suite runner of arithmetic operations on doubledouble (dd) floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sw { + namespace universal { + + + class TestDoubleDouble { + public: + double hi, lo; + + TestDoubleDouble(double x = 0.0) : hi(x), lo(0.0) {} + + double high() const { return hi; } + double low() const { return lo; } + + // Arithmetic operators + TestDoubleDouble operator+=(const TestDoubleDouble& rhs) const { + TestDoubleDouble result; + result.hi = hi + rhs.hi; + double t = result.hi - hi; + result.lo = (hi - (result.hi - t)) + (rhs.hi - (result.hi - t)) + lo + rhs.lo; + return result; + } + + TestDoubleDouble operator-=(const TestDoubleDouble& rhs) const { + TestDoubleDouble result; + result.hi = hi - rhs.hi; + double t = result.hi - hi; + result.lo = (hi - (result.hi - t)) - (rhs.hi - (result.hi - t)) + lo - rhs.lo; + return result; + } + + TestDoubleDouble operator*=(const TestDoubleDouble& rhs) const { + // Simplified multiplication for demonstration, more precise methods exist + TestDoubleDouble result; + result.hi = hi * rhs.hi; + result.lo = hi * rhs.lo + lo * rhs.hi; + return result; + } + + TestDoubleDouble operator/=(const TestDoubleDouble& rhs) const { + // Division is more complex, requiring iterative refinement or rhs techniques + // This is a simplified approximation for demonstration purposes + TestDoubleDouble result; + result.hi = hi / rhs.hi; + result.lo = (lo - result.hi * rhs.lo) / rhs.hi; + return result; + } + }; + + inline std::ostream& operator<<(std::ostream& ostr, const TestDoubleDouble& a) { + return ostr << "( " << a.high() << ", " << a.low() << ')'; + } + + } +} + +constexpr unsigned labelWidth = 15; +constexpr unsigned precision = 25; + +double TwoSumTrace(double a, double b, double& r) { + double s = a + b; + double bb = s - a; + //r = (a - (s - bb)) + (b - bb); + double sbb = s - bb; + double asbb = a - sbb; + double bbb = b - bb; + r = asbb + bbb; + return s; +} + +void TraceTwoSum(double addend) { + using namespace sw::universal; + double a, b, s, r; + a = 1.0; + b = addend; + s = two_sum(a, b, r); + + ReportValue(a, "a", labelWidth, precision); + ReportValue(b, "b", labelWidth, precision); + ReportValue(s, "s", labelWidth, precision); + ReportValue(r, "r", labelWidth, precision); +} + +void TraceTwoDiff(double differend) { + using namespace sw::universal; + double a, b, s, r; + a = 1.0; + b = differend; + s = two_diff(a, b, r); + + ReportValue(a, "a", labelWidth, precision); + ReportValue(b, "b", labelWidth, precision); + ReportValue(s, "s", labelWidth, precision); + ReportValue(r, "r", labelWidth, precision); +} + +void TraceTwoProd(double base, double multiplicant) { + using namespace sw::universal; + double a, b, p, r; + a = base; + b = multiplicant; + p = two_prod(a, b, r); + + ReportValue(a, "a", labelWidth, precision); + ReportValue(b, "b", labelWidth, precision); + ReportValue(p, "p", labelWidth, precision); + ReportValue(r, "r", labelWidth, precision); +} + +void TestArithmeticOp(const sw::universal::dd& a, sw::universal::RandomsOp op, const sw::universal::dd& b) { + using namespace sw::universal; + bool binaryOp = true; + dd c; + switch (op) { + case RandomsOp::OPCODE_ADD: + c = a + b; + break; + case RandomsOp::OPCODE_SUB: + c = a - b; + break; + case RandomsOp::OPCODE_MUL: + c = a * b; + break; + case RandomsOp::OPCODE_DIV: + c = a / b; + break; + case RandomsOp::OPCODE_SQRT: + c = sqrt(a); + binaryOp = false; + break; + default: + std::cerr << "unknown operator: test ignored\n"; + break; + } + ReportValue(a, "a", labelWidth, precision); + if (binaryOp) ReportValue(b, "b", labelWidth, precision); + ReportValue(c, "c", labelWidth, precision); +} + + +namespace sw { + namespace universal { + void TestReciprocalIdentity(sw::universal::dd const& a) { + + dd oneOverA = reciprocal(a); + + dd one(1.0); + dd error = one - a * oneOverA; + ReportValue(a, "a", labelWidth, precision); + ReportValue(oneOverA, "1/a", labelWidth, precision); + ReportValue(error, "error", labelWidth, precision); + } + + void TestDivisionalIdentity(sw::universal::dd const& a) { + + dd oneOverA = 1.0 / a; + + dd one(1.0); + dd error = one - a * oneOverA; + ReportValue(a, "a", labelWidth, precision); + ReportValue(oneOverA, "1/a", labelWidth, precision); + ReportValue(error, "error", labelWidth, precision); + } + + void TestRandomReciprocalIdentities(int nrRandoms = 10) { + std::default_random_engine generator; + std::uniform_real_distribution< double > distr(-1048576.0, 1048576.0); + + for (int i = 0; i < nrRandoms; ++i) { + dd a = distr(generator); + TestReciprocalIdentity(a); + } + } + + void TestRandomDivisionalIdentities(int nrRandoms = 10) { + std::default_random_engine generator; + std::uniform_real_distribution< double > distr(-1048576.0, 1048576.0); + + for (int i = 0; i < nrRandoms; ++i) { + dd a = distr(generator); + TestDivisionalIdentity(a); + } + } + } +} + + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble arithmetic validation"; + std::string test_tag = "doubledouble arithmetic"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + // doubledouble addition + std::cout << "two sum\n"; + TraceTwoSum(ulp(pow(0.5, 10.0))); + TraceTwoSum(-ulp(pow(0.5, 10.0))); + + // doubledouble subtraction + std::cout << "\ntwo diff\n"; + TraceTwoDiff(ulp(pow(0.5, 10.0))); + TraceTwoDiff(-ulp(pow(0.5, 10.0))); + + // doubledouble multiplication + std::cout << "\ntwo prod\n"; + double ulp1 = ulp(pow(1.0, 1.0)); + TraceTwoProd(1.0, ulp1); + TraceTwoProd(ulp1, ulp1); + double base = 4.4501477170144023e-308; // smallest normal + double multiplicant = 1.0 / static_cast(1ull << 54); + TraceTwoProd(base, multiplicant); + + base = 1.7976931348623157e+308; + multiplicant = 1.7976931348623157e+308; + TraceTwoProd(base, multiplicant); + + duble min_normal, max_normal; + min_normal.setbits(0x001F'FFFF'FFFF'FFFFull); + ReportValue(min_normal, "min-normal", labelWidth, precision); + max_normal.setbits(0x7FEF'FFFF'FFFF'FFFFull); + ReportValue(max_normal, "max-normal", labelWidth, precision); + + + dd a, b, c; + + a = 1.0; + b = ulp(std::pow(0.5, 10)); + TestArithmeticOp(a, RandomsOp::OPCODE_ADD, b); + TestArithmeticOp(a, RandomsOp::OPCODE_SUB, b); + TestArithmeticOp(a, RandomsOp::OPCODE_MUL, b); + TestArithmeticOp(a, RandomsOp::OPCODE_DIV, b); + + ReportValue(1.0 / b.high(), "one over", labelWidth, precision); + + std::cout << "\n\n\n"; + TestReciprocalIdentity(dd(1.0)); + TestReciprocalIdentity(dd(0.5)); + TestReciprocalIdentity(dd(10.0)); + + std::cout << "\n\nfused multiply add\n"; + a = 1.0; b = 1.0, c = 0.0; + c = fma(a, b, c); + ReportValue(c, "fma(1.0, 1.0, 0.0)"); + a = 0.0; b = 1.0, c = 1.0; + c = fma(a, b, c); + ReportValue(c, "fma(0.0, 1.0, 1.0)"); + a = 1.0; b = 1.0, c = 1023.0; + c = fma(a, b, c); + ReportValue(c, "fma(1.0, 1.0, 1023.0)"); + + std::cout << "\n\nquick product pairs\n"; + a = 0.5; b = 2.0; + c = a * b; + ReportValue(c, "0.5 * 2.0"); + a = 0.0625; b = 16.0; + c = a * b; + ReportValue(c, "0.0625 * 16.0"); + a = 10.0; b = 0.1; + c = a * b; + ReportValue(c, "10.0 * 0.1"); + + std::cout << "\n\nquick divisional pairs\n"; + a = 1.0; b = 2.0; + c = a / b; + ReportValue(c, "1.0 / 2.0"); + a = 0.5; b = 2.0; + c = a / b; + ReportValue(c, "0.5 / 2.0"); + a = 2.0; b = 16.0; + c = a / b; + ReportValue(c, "2.0 / 16.0"); + a = 1.0; b = 2.0; + c = a / b; + ReportValue(c, "1.0 / 2.0"); + a = 10.0; b = 0.1; + c = a / b; + ReportValue(c, "10.0 / 0.1"); + + std::cout << "Test reciprocal identities\n"; + TestRandomReciprocalIdentities(1); + std::cout << "Test divisional identities\n"; + TestRandomDivisionalIdentities(1); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + + constexpr unsigned nrOfRandoms = 1000; + std::stringstream adds; + adds << test_tag << " " << nrOfRandoms << " random adds"; + std::string description = adds.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_ADD, nrOfRandoms), + description, + test_tag + ); + std::stringstream subs; + subs << test_tag << " " << nrOfRandoms << " random subs"; + description = subs.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_SUB, nrOfRandoms), + description, + test_tag + ); + std::stringstream muls; + muls << test_tag << " " << nrOfRandoms << " random muls"; + description = muls.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_MUL, nrOfRandoms), + description, + test_tag + ); + std::stringstream divs; + divs << test_tag << " " << nrOfRandoms << " random divs"; + description = divs.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_DIV, nrOfRandoms), + description, + test_tag + ); + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/arithmetic/division.cpp b/static/dd/arithmetic/division.cpp new file mode 100644 index 000000000..b8868e28b --- /dev/null +++ b/static/dd/arithmetic/division.cpp @@ -0,0 +1,95 @@ +// division.cpp: test suite runner for division of doubledouble floating-point values +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble division validation"; + std::string test_tag = "doubledouble division"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + + constexpr unsigned nrOfRandoms = 1000; + std::stringstream s; + s << test_tag << " " << nrOfRandoms << " random pairs"; + std::string description = s.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_DIV, nrOfRandoms), + description, + test_tag + ); + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/arithmetic/multiplication.cpp b/static/dd/arithmetic/multiplication.cpp new file mode 100644 index 000000000..763879833 --- /dev/null +++ b/static/dd/arithmetic/multiplication.cpp @@ -0,0 +1,124 @@ +// multiplication.cpp: test suite runner for multiplication of doubledouble floating-point values +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble multiplication validation"; + std::string test_tag = "doubledouble multiplication"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd a, b, c, d; + + constexpr unsigned labelWidth = 40; + + a.assign("0.1"); + ReportValue(a, "0.1", labelWidth, 32); + b.assign("10"); + ReportValue(b, "10.0", labelWidth, 32); + c = a * b; + ReportValue(c, "1.0", labelWidth, 32); + std::cout << '\n'; + + std::string _third("0.333333333333333333333333333333333"); + c.assign(_third); + ReportValue(c, _third, labelWidth, 32); + + d = c; + for (int i = 0; i < 53; ++i) { + std::string value = std::string("0.33333... * ") + std::to_string(i) + std::string(" * 0.1"); + ReportValue(d, value, labelWidth, 32); + d *= a; + } + + d = c;; + for (int i = 0; i < 53; ++i) { + std::string value = std::string("0.33333... * ") + std::to_string(i) + std::string(" * 10.0"); + ReportValue(d, value, labelWidth, 32); + d *= b; + } + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + + constexpr unsigned nrOfRandoms = 1000; + std::stringstream s; + s << test_tag << " " << nrOfRandoms << " random pairs"; + std::string description = s.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_MUL, nrOfRandoms), + description, + test_tag + ); + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/arithmetic/subtraction.cpp b/static/dd/arithmetic/subtraction.cpp new file mode 100644 index 000000000..3e7312071 --- /dev/null +++ b/static/dd/arithmetic/subtraction.cpp @@ -0,0 +1,114 @@ +// subtraction.cpp: test suite runner for subtraction of doubledouble floating-point values +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble subtraction validation"; + std::string test_tag = "doubledouble subtraction"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd a, b, c, ulpAtOne, oneMinusUlp, oneMinusHalfUlp; + + a = 1.0; + ulpAtOne = ulp(1.0); + oneMinusUlp = a - ulpAtOne; + b = ulpAtOne; + b /= 2.0; + ReportValue(a, "1.0",35,32); + ReportValue(ulpAtOne, "ulp", 35, 32); + ReportValue(b, "ulp/2", 35, 32); + ReportValue(oneMinusUlp, "1.0 - ulp", 35, 32); + c = a + b; + ReportValue(c, "1.0 - ulp/2", 35, 32); + oneMinusHalfUlp = a; + oneMinusHalfUlp += ulp(0.5); + + std::cout << "1.0 : " << to_pair(a) << '\n'; + std::cout << "1.0 - ulp(1.0) : " << to_pair(oneMinusUlp) << '\n'; + std::cout << "1.0 - ulp(0.5) : " << to_pair(oneMinusHalfUlp) << '\n'; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + + constexpr unsigned nrOfRandoms = 1000; + std::stringstream s; + s << test_tag << " " << nrOfRandoms << " random pairs"; + std::string description = s.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_SUB, nrOfRandoms), + description, + test_tag + ); + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/conversion/conversion.cpp b/static/dd/conversion/conversion.cpp new file mode 100644 index 000000000..9a577b9ac --- /dev/null +++ b/static/dd/conversion/conversion.cpp @@ -0,0 +1,112 @@ +// conversion.cpp: test suite runner for conversion operators for double-double (dd) floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble conversion validation"; + std::string test_tag = "doubledouble conversion"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + uint64_t u64; + int64_t i64; + + // check if we get all the bits of a 64-bit int + u64 = 0xFFFF'FFFF'FFFF'FFFFull; + i64 = 0x7FFF'FFFF'FFFF'FFFFll; + + { + std::cout << to_binary(u64, false, 64) << " : " << u64 << '\n'; + uint64_t v{ u64 }; + double hi = static_cast(v); + uint64_t h = static_cast(hi); + std::cout << std::fixed << hi << '\n'; + std::cout << to_binary(h) << '\n'; + double lo = static_cast(v - h); // difference is always positive + uint64_t l = static_cast(lo); + std::cout << std::fixed << lo << '\n'; + std::cout << to_binary(l) << '\n'; + + dd a(u64); + ReportValue(a, "0xFFFF'FFFF'FFFF'FFFF", 35, 32); + std::cout << color_print(a) << '\n'; + std::cout << to_pair(a) << '\n'; + uint64_t i = uint64_t(a); + ReportValue(i, "0xFFFF'FFFF'FFFF'FFFF", 35, 32); + } + + { + dd a(i64); + ReportValue(a, "0x7FFF'FFFF'FFFF'FFFF", 35, 32); + } + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/conversion/double-string-conversion.txt b/static/dd/conversion/double-string-conversion.txt new file mode 100644 index 000000000..33aeaaed5 --- /dev/null +++ b/static/dd/conversion/double-string-conversion.txt @@ -0,0 +1,225 @@ +double-string-conversion +0x4A90000000000000 : 0b0.10010101001.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ 1e+51_ +scientific : _ 1e+51_ +fixed : _1496577676626844588240573268701473812127674924007424_ +precision : 7 +columnWidth : 14 +default : _ 1.496578e+51_ +scientific : _ 1.4965777e+51_ +fixed : _1496577676626844588240573268701473812127674924007424.0000000_ +precision : 14 +columnWidth : 21 +default : _ 1.4965776766268e+51_ +scientific : _ 1.49657767662684e+51_ +fixed : _1496577676626844588240573268701473812127674924007424.00000000000000_ +precision : 21 +columnWidth : 28 +default : _ 1.49657767662684458824e+51_ +scientific : _ 1.496577676626844588241e+51_ +fixed : _1496577676626844588240573268701473812127674924007424.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _ 1.496577676626844588240573269e+51_ +scientific : _ 1.4965776766268445882405732687e+51_ +fixed : _1496577676626844588240573268701473812127674924007424.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _ 1.4965776766268445882405732687014738e+51_ +scientific : _ 1.49657767662684458824057326870147381e+51_ +fixed : _1496577676626844588240573268701473812127674924007424.00000000000000000000000000000000000_ +0x5530000000000000 : 0b0.10101010011.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ 2e+102_ +scientific : _ 2e+102_ +fixed : _2239744742177804210557442280568444278121645497234649534899989100963791871180160945380877493271607115776_ +precision : 7 +columnWidth : 14 +default : _ 2.239745e+102_ +scientific : _2.2397447e+102_ +fixed : _2239744742177804210557442280568444278121645497234649534899989100963791871180160945380877493271607115776.0000000_ +precision : 14 +columnWidth : 21 +default : _ 2.2397447421778e+102_ +scientific : _2.23974474217780e+102_ +fixed : _2239744742177804210557442280568444278121645497234649534899989100963791871180160945380877493271607115776.00000000000000_ +precision : 21 +columnWidth : 28 +default : _ 2.23974474217780421056e+102_ +scientific : _2.239744742177804210557e+102_ +fixed : _2239744742177804210557442280568444278121645497234649534899989100963791871180160945380877493271607115776.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _ 2.239744742177804210557442281e+102_ +scientific : _2.2397447421778042105574422806e+102_ +fixed : _2239744742177804210557442280568444278121645497234649534899989100963791871180160945380877493271607115776.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _ 2.2397447421778042105574422805684443e+102_ +scientific : _2.23974474217780421055744228056844428e+102_ +fixed : _2239744742177804210557442280568444278121645497234649534899989100963791871180160945380877493271607115776.00000000000000000000000000000000000_ +0x5FD0000000000000 : 0b0.10111111101.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ 3e+153_ +scientific : _ 3e+153_ +fixed : _3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024_ +precision : 7 +columnWidth : 14 +default : _ 3.351952e+153_ +scientific : _3.3519520e+153_ +fixed : _3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024.0000000_ +precision : 14 +columnWidth : 21 +default : _ 3.3519519824856e+153_ +scientific : _3.35195198248565e+153_ +fixed : _3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024.00000000000000_ +precision : 21 +columnWidth : 28 +default : _ 3.35195198248564927489e+153_ +scientific : _3.351951982485649274894e+153_ +fixed : _3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _ 3.35195198248564927489350625e+153_ +scientific : _3.3519519824856492748935062496e+153_ +fixed : _3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _ 3.3519519824856492748935062495514615e+153_ +scientific : _3.35195198248564927489350624955146153e+153_ +fixed : _3351951982485649274893506249551461531869841455148098344430890360930441007518386744200468574541725856922507964546621512713438470702986642486608412251521024.00000000000000000000000000000000000_ +0x6A70000000000000 : 0b0.11010100111.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ 5e+204_ +scientific : _ 5e+204_ +fixed : _5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082176_ +precision : 7 +columnWidth : 14 +default : _ 5.016457e+204_ +scientific : _5.0164565e+204_ +fixed : _5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082176.0000000_ +precision : 14 +columnWidth : 21 +default : _ 5.0164565101131e+204_ +scientific : _5.01645651011312e+204_ +fixed : _5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082176.00000000000000_ +precision : 21 +columnWidth : 28 +default : _ 5.01645651011311865543e+204_ +scientific : _5.016456510113118655435e+204_ +fixed : _5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082176.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _ 5.016456510113118655434598811e+204_ +scientific : _5.0164565101131186554345988110e+204_ +fixed : _5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082176.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _ 5.016456510113118655434598811035279e+204_ +scientific : _5.01645651011311865543459881103527896e+204_ +fixed : _5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082176.00000000000000000000000000000000000_ +0x7510000000000000 : 0b0.11101010001.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ 8e+255_ +scientific : _ 8e+255_ +fixed : _7507516828804700229971157695509256861311759593549503536677899390762631562619231707947410198580331380848554019184705462619182690666302243261761460906639905160039726922590902577336628349889145412319979767917902626154330339044684617119264613887239597666074624_ +precision : 7 +columnWidth : 14 +default : _ 7.507517e+255_ +scientific : _7.5075168e+255_ +fixed : _7507516828804700229971157695509256861311759593549503536677899390762631562619231707947410198580331380848554019184705462619182690666302243261761460906639905160039726922590902577336628349889145412319979767917902626154330339044684617119264613887239597666074624.0000000_ +precision : 14 +columnWidth : 21 +default : _ 7.5075168288047e+255_ +scientific : _7.50751682880470e+255_ +fixed : _7507516828804700229971157695509256861311759593549503536677899390762631562619231707947410198580331380848554019184705462619182690666302243261761460906639905160039726922590902577336628349889145412319979767917902626154330339044684617119264613887239597666074624.00000000000000_ +precision : 21 +columnWidth : 28 +default : _ 7.50751682880470022997e+255_ +scientific : _7.507516828804700229971e+255_ +fixed : _7507516828804700229971157695509256861311759593549503536677899390762631562619231707947410198580331380848554019184705462619182690666302243261761460906639905160039726922590902577336628349889145412319979767917902626154330339044684617119264613887239597666074624.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _ 7.507516828804700229971157696e+255_ +scientific : _7.5075168288047002299711576955e+255_ +fixed : _7507516828804700229971157695509256861311759593549503536677899390762631562619231707947410198580331380848554019184705462619182690666302243261761460906639905160039726922590902577336628349889145412319979767917902626154330339044684617119264613887239597666074624.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _ 7.5075168288047002299711576955092569e+255_ +scientific : _7.50751682880470022997115769550925686e+255_ +fixed : _7507516828804700229971157695509256861311759593549503536677899390762631562619231707947410198580331380848554019184705462619182690666302243261761460906639905160039726922590902577336628349889145412319979767917902626154330339044684617119264613887239597666074624.00000000000000000000000000000000000_ +0x7FB0000000000000 : 0b0.11111111011.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ 1e+307_ +scientific : _ 1e+307_ +fixed : _11235582092889474423308157442431404585112356118389416079589380072358292237843810195794279832650471001320007117491962084853674360550901038905802964414967132773610493339054092829768888725077880882465817684505312860552384417646403930092119569408801702322709406917786643639996702871154982269052209770601514008576_ +precision : 7 +columnWidth : 14 +default : _ 1.123558e+307_ +scientific : _1.1235582e+307_ +fixed : _11235582092889474423308157442431404585112356118389416079589380072358292237843810195794279832650471001320007117491962084853674360550901038905802964414967132773610493339054092829768888725077880882465817684505312860552384417646403930092119569408801702322709406917786643639996702871154982269052209770601514008576.0000000_ +precision : 14 +columnWidth : 21 +default : _ 1.1235582092889e+307_ +scientific : _1.12355820928895e+307_ +fixed : _11235582092889474423308157442431404585112356118389416079589380072358292237843810195794279832650471001320007117491962084853674360550901038905802964414967132773610493339054092829768888725077880882465817684505312860552384417646403930092119569408801702322709406917786643639996702871154982269052209770601514008576.00000000000000_ +precision : 21 +columnWidth : 28 +default : _ 1.12355820928894744233e+307_ +scientific : _1.123558209288947442331e+307_ +fixed : _11235582092889474423308157442431404585112356118389416079589380072358292237843810195794279832650471001320007117491962084853674360550901038905802964414967132773610493339054092829768888725077880882465817684505312860552384417646403930092119569408801702322709406917786643639996702871154982269052209770601514008576.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _ 1.123558209288947442330815744e+307_ +scientific : _1.1235582092889474423308157442e+307_ +fixed : _11235582092889474423308157442431404585112356118389416079589380072358292237843810195794279832650471001320007117491962084853674360550901038905802964414967132773610493339054092829768888725077880882465817684505312860552384417646403930092119569408801702322709406917786643639996702871154982269052209770601514008576.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _ 1.1235582092889474423308157442431405e+307_ +scientific : _1.12355820928894744233081574424314046e+307_ +fixed : _11235582092889474423308157442431404585112356118389416079589380072358292237843810195794279832650471001320007117491962084853674360550901038905802964414967132773610493339054092829768888725077880882465817684505312860552384417646403930092119569408801702322709406917786643639996702871154982269052209770601514008576.00000000000000000000000000000000000_ +0x7FF0000000000000 : 0b0.11111111111.0000000000000000000000000000000000000000000000000000 +double +precision : 0 +columnWidth : 7 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 7 +columnWidth : 14 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 14 +columnWidth : 21 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 21 +columnWidth : 28 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 28 +columnWidth : 35 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 35 +columnWidth : 42 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ \ No newline at end of file diff --git a/static/dd/conversion/doubledouble-string-conversion.txt b/static/dd/conversion/doubledouble-string-conversion.txt new file mode 100644 index 000000000..b8b371ac2 --- /dev/null +++ b/static/dd/conversion/doubledouble-string-conversion.txt @@ -0,0 +1,225 @@ +doubledouble-string-conversion +0x4A90000000000000 : 0b0.10010101001.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ 1e+51_ +scientific : _ 1e+51_ +fixed : _1496577676626844588240573268701474654419726360737976_ +precision : 7 +columnWidth : 14 +default : _ 1.4965777e+51_ +scientific : _ 1.4965777e+51_ +fixed : _1496577676626844588240573268701474654419726360737966.4806663_ +precision : 14 +columnWidth : 21 +default : _ 1.49657767662684e+51_ +scientific : _ 1.49657767662684e+51_ +fixed : _1496577676626844588240573268701474654419726360737966.48066633189263_ +precision : 21 +columnWidth : 28 +default : _ 1.496577676626844588241e+51_ +scientific : _ 1.496577676626844588241e+51_ +fixed : _1496577676626844588240573268701474654419726360737966.480666331892633580392_ +precision : 28 +columnWidth : 35 +default : _ 1.4965776766268445882405732687e+51_ +scientific : _ 1.4965776766268445882405732687e+51_ +fixed : _1496577676626844588240573268701474654419726360737966.4806663318926335803915605993_ +precision : 35 +columnWidth : 42 +default : _ 1.49657767662684458824057326870147465e+51_ +scientific : _ 1.49657767662684458824057326870147465e+51_ +fixed : _1496577676626844588240573268701474654419726360737966.48066633189263358039156059930974152_ +0x5530000000000000 : 0b0.10101010011.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ 2e+102_ +scientific : _ 2e+102_ +fixed : _2239744742177804210557442280568504261275579826533149855438998578581466514236808507121168076992034912119_ +precision : 7 +columnWidth : 14 +default : _2.2397447e+102_ +scientific : _2.2397447e+102_ +fixed : _2239744742177804210557442280568504261275579826533149855438998578581466514236808507121168076992034912109.3750000_ +precision : 14 +columnWidth : 21 +default : _2.23974474217780e+102_ +scientific : _2.23974474217780e+102_ +fixed : _2239744742177804210557442280568504261275579826533149855438998578581466514236808507121168076992034912109.37500000000000_ +precision : 21 +columnWidth : 28 +default : _2.239744742177804210557e+102_ +scientific : _2.239744742177804210557e+102_ +fixed : _2239744742177804210557442280568504261275579826533149855438998578581466514236808507121168076992034912109.375000000000000000000_ +precision : 28 +columnWidth : 35 +default : _2.2397447421778042105574422806e+102_ +scientific : _2.2397447421778042105574422806e+102_ +fixed : _2239744742177804210557442280568504261275579826533149855438998578581466514236808507121168076992034912109.3750000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _2.23974474217780421055744228056850426e+102_ +scientific : _2.23974474217780421055744228056850426e+102_ +fixed : _2239744742177804210557442280568504261275579826533149855438998578581466514236808507121168076992034912109.37500000000000000000000000000000000_ +0x5FD0000000000000 : 0b0.10111111101.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ 3e+153_ +scientific : _ 3e+153_ +fixed : _3351951982485649274893506249551659521255252443936972474520033515865691242652246728539466857910156250000000000000000000000000000000000000000000000000000000_ +precision : 7 +columnWidth : 14 +default : _3.3519520e+153_ +scientific : _3.3519520e+153_ +fixed : _3351951982485649274893506249551659521255252443936972474520033515865691242652246728539466857910156250000000000000000000000000000000000000000000000000000000.0000000_ +precision : 14 +columnWidth : 21 +default : _3.35195198248565e+153_ +scientific : _3.35195198248565e+153_ +fixed : _3351951982485649274893506249551659521255252443936972474520033515865691242652246728539466857910156250000000000000000000000000000000000000000000000000000000.00000000000000_ +precision : 21 +columnWidth : 28 +default : _3.351951982485649274894e+153_ +scientific : _3.351951982485649274894e+153_ +fixed : _3351951982485649274893506249551659521255252443936972474520033515865691242652246728539466857910156250000000000000000000000000000000000000000000000000000000.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _3.3519519824856492748935062496e+153_ +scientific : _3.3519519824856492748935062496e+153_ +fixed : _3351951982485649274893506249551659521255252443936972474520033515865691242652246728539466857910156250000000000000000000000000000000000000000000000000000000.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _3.35195198248564927489350624955165952e+153_ +scientific : _3.35195198248564927489350624955165952e+153_ +fixed : _3351951982485649274893506249551659521255252443936972474520033515865691242652246728539466857910156250000000000000000000000000000000000000000000000000000000.00000000000000000000000000000000000_ +0x6A70000000000000 : 0b0.11010100111.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ 5e+204_ +scientific : _ 5e+204_ +fixed : _5016456510113118655434598811035720102747410760955944240675681192838039623715928883029846474528312683105468750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_ +precision : 7 +columnWidth : 14 +default : _5.0164565e+204_ +scientific : _5.0164565e+204_ +fixed : _5016456510113118655434598811035720102747410760955944240675681192838039623715928883029846474528312683105468750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000_ +precision : 14 +columnWidth : 21 +default : _5.01645651011312e+204_ +scientific : _5.01645651011312e+204_ +fixed : _5016456510113118655434598811035720102747410760955944240675681192838039623715928883029846474528312683105468750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000000000_ +precision : 21 +columnWidth : 28 +default : _5.016456510113118655435e+204_ +scientific : _5.016456510113118655435e+204_ +fixed : _5016456510113118655434598811035720102747410760955944240675681192838039623715928883029846474528312683105468750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _5.0164565101131186554345988110e+204_ +scientific : _5.0164565101131186554345988110e+204_ +fixed : _5016456510113118655434598811035720102747410760955944240675681192838039623715928883029846474528312683105468750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _5.01645651011311865543459881103572010e+204_ +scientific : _5.01645651011311865543459881103572010e+204_ +fixed : _5016456510113118655434598811035720102747410760955944240675681192838039623715928883029846474528312683105468750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000000000000000000000000000000_ +0x7510000000000000 : 0b0.11101010001.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ 8e+255_ +scientific : _ 8e+255_ +fixed : _7507516828804700229971157695509931467673939159727746462179057379375535230536797826061956584453582763671875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_ +precision : 7 +columnWidth : 14 +default : _7.5075168e+255_ +scientific : _7.5075168e+255_ +fixed : _7507516828804700229971157695509931467673939159727746462179057379375535230536797826061956584453582763671875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000_ +precision : 14 +columnWidth : 21 +default : _7.50751682880470e+255_ +scientific : _7.50751682880470e+255_ +fixed : _7507516828804700229971157695509931467673939159727746462179057379375535230536797826061956584453582763671875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000000000_ +precision : 21 +columnWidth : 28 +default : _7.507516828804700229971e+255_ +scientific : _7.507516828804700229971e+255_ +fixed : _7507516828804700229971157695509931467673939159727746462179057379375535230536797826061956584453582763671875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _7.5075168288047002299711576955e+255_ +scientific : _7.5075168288047002299711576955e+255_ +fixed : _7507516828804700229971157695509931467673939159727746462179057379375535230536797826061956584453582763671875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _7.50751682880470022997115769550993147e+255_ +scientific : _7.50751682880470022997115769550993147e+255_ +fixed : _7507516828804700229971157695509931467673939159727746462179057379375535230536797826061956584453582763671875000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000000000000000000000000000000_ +0x7FB0000000000000 : 0b0.11111111011.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ 1e+307_ +scientific : _ 1e+307_ +fixed : _11235582092889474423308157442433034398240876223473669309165437067872528320577885097009129822254180908203125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000_ +precision : 7 +columnWidth : 14 +default : _1.1235582e+307_ +scientific : _1.1235582e+307_ +fixed : _11235582092889474423308157442433034398240876223473669309165437067872528320577885097009129822254180908203125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000_ +precision : 14 +columnWidth : 21 +default : _1.12355820928895e+307_ +scientific : _1.12355820928895e+307_ +fixed : _11235582092889474423308157442433034398240876223473669309165437067872528320577885097009129822254180908203125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000000000_ +precision : 21 +columnWidth : 28 +default : _1.123558209288947442331e+307_ +scientific : _1.123558209288947442331e+307_ +fixed : _11235582092889474423308157442433034398240876223473669309165437067872528320577885097009129822254180908203125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000_ +precision : 28 +columnWidth : 35 +default : _1.1235582092889474423308157442e+307_ +scientific : _1.1235582092889474423308157442e+307_ +fixed : _11235582092889474423308157442433034398240876223473669309165437067872528320577885097009129822254180908203125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0000000000000000000000000000_ +precision : 35 +columnWidth : 42 +default : _1.12355820928894744233081574424330344e+307_ +scientific : _1.12355820928894744233081574424330344e+307_ +fixed : _11235582092889474423308157442433034398240876223473669309165437067872528320577885097009129822254180908203125000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.00000000000000000000000000000000000_ +0x7FF0000000000000 : 0b0.11111111111.0000000000000000000000000000000000000000000000000000 +doubledouble +precision : 0 +columnWidth : 7 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 7 +columnWidth : 14 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 14 +columnWidth : 21 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 21 +columnWidth : 28 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 28 +columnWidth : 35 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ +precision : 35 +columnWidth : 42 +default : _ inf_ +scientific : _ inf_ +fixed : _ inf_ \ No newline at end of file diff --git a/static/dd/conversion/to_string.cpp b/static/dd/conversion/to_string.cpp new file mode 100644 index 000000000..f516a82d8 --- /dev/null +++ b/static/dd/conversion/to_string.cpp @@ -0,0 +1,232 @@ +// to_string.cpp: test suite runner for the string conversion operators for double-double (dd) floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#if __cpp_lib_format >= 202311L +constexpr auto revision() { return " (post C++26)"; } +#include +#else +constexpr auto revision() { return " (pre C++26)"; } +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace sw { + namespace universal { + + /* + * the width requested is subservient to the precision, that is, if precision is width < precision + surplus, you are + * going to get a string that is precision + surplus + * in scientific format the surplus is 7 characters 1.precisionE+300; + */ + template + void ScanWidth(TestType v, int precision = 7) { + std::cout << type_tag(v) << '\n'; + for (int width = precision; width < precision + 7; ++width) { + std::cout << "precision : " << precision << '\n'; + std::cout << "columnWidth : " << width << '\n'; + std::cout << "default : _" << std::setprecision(precision) << std::setw(width) << v << '_' << '\n'; + std::cout << "scientific : _" << std::scientific << std::setprecision(precision) << std::setw(width) << v << '_' << '\n'; + std::cout << "fixed : _" << std::fixed << std::setprecision(precision) << std::setw(width) << v << '_' << '\n'; + std::cout << std::defaultfloat; + } + } + template + void ScanPrecision(TestType v) { + std::cout << type_tag(v) << '\n'; + for (int i = 0; i < 6; ++i) { + int precision = 7 * i; + int width = precision + 7; + std::cout << "precision : " << precision << '\n'; + std::cout << "columnWidth : " << width << '\n'; + std::cout << "default : _" << std::setprecision(precision) << std::setw(width) << v << '_' << '\n'; + std::cout << "scientific : _" << std::scientific << std::setprecision(precision) << std::setw(width) << v << '_' << '\n'; + std::cout << "fixed : _" << std::fixed << std::setprecision(precision) << std::setw(width) << v << '_' << '\n'; + std::cout << std::defaultfloat; + } + } + + void ScanTest(int selection) { + // 2^166 = exponent of 1e50 + double clean = std::ldexp(1.0, 170); // construct a double with the fraction bits of 1.0 and the exponent of 2^170 + switch (selection) { + case 0: + { + // reference native double + double base{ clean }; + for (int i = 0; i < 7; ++i) { + std::cout << to_hex(base) << " : " << to_binary(base) << '\n'; + ScanPrecision(base); + base *= clean; + } + } + break; + case 1: + { + // comparative double-double + dd base{ clean }; + for (int i = 0; i < 7; ++i) { + std::cout << to_hex(double(base)) << " : " << to_binary(double(base)) << '\n'; + ScanPrecision(base); + base *= clean; + } + } + break; + } + } + int VerifyStreamRoundTrip(bool reportTestCases, dd seed, std::streamsize precision = 32, std::streamsize width = 35, unsigned nrTrials = 10) { + int nrOfTestFailures{ 0 }; + dd a{seed}, b{}; + + std::random_device rd; // get a random seed from the OS entropy device + std::mt19937_64 eng(rd()); // use the 64-bit Mersenne Twister 19937 generator and seed it with entropy. + double min = -1024 * 1024, max = 1024 * 1024; + std::uniform_real_distribution distr(min, max); // define the distribution + + for (unsigned i = 0; i < nrTrials; ++i) { + std::stringstream s1; + s1 << std::setprecision(precision) << std::setw(width) << a << ' '; + std::string input = s1.str(); + //std::cout << "out: " << input; + s1 >> b; + std::stringstream s2; + s2 << std::setprecision(precision) << std::setw(width) << b << ' '; + std::string output = s2.str(); + //std::cout << "in : " << output << '\n'; + if (output != input) { + ++nrOfTestFailures; + if (reportTestCases) std::cerr << "FAIL: " << input << " != " << output << '\n'; + } + a = seed * distr(eng); + } + return nrOfTestFailures; + } + } +} +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble string conversion validation"; + std::string test_tag = "doubledouble string conversion"; + bool reportTestCases = true; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + + ScanTest(0); // reference native double + ScanTest(1); // comparative double-double + + double dSeed = 1.0e50; + std::cout << scale(dSeed) << '\n'; + dd seed(dSeed); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 7, 10, 3); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 10, 15, 3); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 25, 30, 3); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 32, 35, 3); + + + for (const double f : {1.23456789555555, 23.43, 1e-9, 1e40, 1e-40, 123456789.0}) { + std::cout << "to_string:\t" << std::to_string(f) << revision() << '\n'; + + // Before C++26, the output of std::to_string matches std::printf. + std::printf("printf:\t\t%f\n", f); + + // As of C++26, the output of std::to_string matches std::format. +// std::cout << std::format("format:\t\t{}\n", f); + + std::cout << "std::cout:\t" << f << "\n\n"; + } + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + dd seed{ 125.125125125125125125125 }; + + return 0; + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 7, 7); + std::cout << "failures " << nrOfFailedTestCases << '\n'; + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 10, 7); + std::cout << "failures " << nrOfFailedTestCases << '\n'; + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 15, 7); + std::cout << "failures " << nrOfFailedTestCases << '\n'; + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 25, 7); + std::cout << "failures " << nrOfFailedTestCases << '\n'; + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 32, 7); + std::cout << "failures " << nrOfFailedTestCases << '\n'; + + seed.assign("0.333333333333333333333333333333333333333"); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 7, 10); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 10, 15); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 25, 30); + nrOfFailedTestCases += VerifyStreamRoundTrip(reportTestCases, seed, 32, 35); +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/logic/logic.cpp b/static/dd/logic/logic.cpp new file mode 100644 index 000000000..f346aeced --- /dev/null +++ b/static/dd/logic/logic.cpp @@ -0,0 +1,95 @@ +// addition.cpp: test suite runner for addition on bfloat16s +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble logic validation"; + std::string test_tag = "doubledouble logic"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else // !MANUAL_TESTING + +#if REGRESSION_LEVEL_1 + + constexpr unsigned nrOfRandoms = 1000; + std::stringstream s; + s << test_tag << " " << nrOfRandoms << " random pairs"; + std::string description = s.str(); + nrOfFailedTestCases += ReportTestResult( + VerifyBinaryOperatorThroughRandoms
(reportTestCases, RandomsOp::OPCODE_ADD, nrOfRandoms), + description, + test_tag + ); + +#endif + +#if REGRESSION_LEVEL_2 +#endif + +#if REGRESSION_LEVEL_3 +#endif + +#if REGRESSION_LEVEL_4 +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/classify.cpp b/static/dd/math/classify.cpp new file mode 100644 index 000000000..246e2232c --- /dev/null +++ b/static/dd/math/classify.cpp @@ -0,0 +1,152 @@ +// classify.cpp: test suite runner for doubledouble (dd) classification functions +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 0 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib classification function validation"; + std::string test_tag = "pow"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + std::cout << "fpclassify(qnan) = " << fpclassify(std::numeric_limits
::quiet_NaN()) << " == " << FP_NAN << "\n"; + std::cout << "fpclassify(snan) = " << fpclassify(std::numeric_limits
::signaling_NaN()) << " == " << FP_NAN << "\n"; + std::cout << "fpclassify(-inf) = " << fpclassify(-std::numeric_limits
::infinity()) << " == " << FP_INFINITE << "\n"; + std::cout << "fpclassify(-1.0) = " << fpclassify(dd(-1.0)) << " == " << FP_NORMAL << "\n"; + std::cout << "fpclassify(-0.0) = " << fpclassify(dd("-0.0")) << " == " << FP_ZERO << "\n"; + std::cout << "fpclassify(0.0) = " << fpclassify(dd("0.0")) << " == " << FP_ZERO << "\n"; + std::cout << "fpclassify(1.0) = " << fpclassify(dd(1.0)) << " == " << FP_NORMAL << "\n"; + std::cout << "fpclassify(inf) = " << fpclassify(std::numeric_limits
::infinity()) << " == " << FP_INFINITE << "\n"; + std::cout << "\n"; + + std::cout << "isfinite(qnan) = " << isfinite(std::numeric_limits
::quiet_NaN()) << "\n"; + std::cout << "isfinite(snan) = " << isfinite(std::numeric_limits
::signaling_NaN()) << "\n"; + std::cout << "isfinite(-inf) = " << isfinite(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "isfinite(-1.0) = " << isfinite(dd(-1.0)) << "\n"; + std::cout << "isfinite(-0.0) = " << isfinite(dd("-0.0")) << "\n"; + std::cout << "isfinite(0.0) = " << isfinite(dd("0.0")) << "\n"; + std::cout << "isfinite(1.0) = " << isfinite(dd(1.0)) << "\n"; + std::cout << "isfinite(inf) = " << isfinite(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + std::cout << "isinf(qnan) = " << isinf(std::numeric_limits
::quiet_NaN()) << "\n"; + std::cout << "isinf(snan) = " << isinf(std::numeric_limits
::signaling_NaN()) << "\n"; + std::cout << "isinf(-inf) = " << isinf(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "isinf(-1.0) = " << isinf(dd(-1.0)) << "\n"; + std::cout << "isinf(-0.0) = " << isinf(dd("-0.0")) << "\n"; + std::cout << "isinf(0.0) = " << isinf(dd("0.0")) << "\n"; + std::cout << "isinf(1.0) = " << isinf(dd(1.0)) << "\n"; + std::cout << "isinf(inf) = " << isinf(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + std::cout << "isnan(qnan) = " << isnan(std::numeric_limits
::quiet_NaN()) << "\n"; + std::cout << "isnan(snan) = " << isnan(std::numeric_limits
::signaling_NaN()) << "\n"; + std::cout << "isnan(-inf) = " << isnan(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "isnan(-1.0) = " << isnan(dd(-1.0)) << "\n"; + std::cout << "isnan(-0.0) = " << isnan(dd("-0.0")) << "\n"; + std::cout << "isnan(0.0) = " << isnan(dd("0.0")) << "\n"; + std::cout << "isnan(1.0) = " << isnan(dd(1.0)) << "\n"; + std::cout << "isnan(inf) = " << isnan(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + std::cout << "isnormal(qnan) = " << isnormal(std::numeric_limits
::quiet_NaN()) << "\n"; + std::cout << "isnormal(snan) = " << isnormal(std::numeric_limits
::signaling_NaN()) << "\n"; + std::cout << "isnormal(-inf) = " << isnormal(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "isnormal(-1.0) = " << isnormal(dd(-1.0)) << "\n"; + std::cout << "isnormal(-0.0) = " << isnormal(dd("-0.0")) << "\n"; + std::cout << "isnormal(0.0) = " << isnormal(dd("0.0")) << "\n"; + std::cout << "isnormal(1.0) = " << isnormal(dd(1.0)) << "\n"; + std::cout << "isnormal(inf) = " << isnormal(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + constexpr double minpos = std::numeric_limits::min(); + std::cout << to_binary(minpos) << " : " << minpos << '\n'; + double subnormal = minpos / 2.0; + std::cout << to_binary(subnormal) << " : " << subnormal << '\n'; + + std::cout << "isdenorm(qnan) = " << isdenorm(std::numeric_limits
::quiet_NaN()) << "\n"; + std::cout << "isdenorm(snan) = " << isdenorm(std::numeric_limits
::signaling_NaN()) << "\n"; + std::cout << "isdenorm(-inf) = " << isdenorm(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "isdenorm(-1.0) = " << isdenorm(dd(-1.0)) << "\n"; + std::cout << "isdenorm(-0.0) = " << isdenorm(dd("-0.0")) << "\n"; + std::cout << "isdenorm(0.0) = " << isdenorm(dd("0.0")) << "\n"; + std::cout << "isdenorm(subnorm) = " << isdenorm(subnormal) << "\n"; + std::cout << "isdenorm(1.0) = " << isdenorm(dd(1.0)) << "\n"; + std::cout << "isdenorm(inf) = " << isdenorm(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + std::cout << "iszero(qnan) = " << iszero(std::numeric_limits
::quiet_NaN()) << "\n"; + std::cout << "iszero(snan) = " << iszero(std::numeric_limits
::signaling_NaN()) << "\n"; + std::cout << "iszero(-inf) = " << iszero(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "iszero(-1.0) = " << iszero(dd(-1.0)) << "\n"; + std::cout << "iszero(-0.0) = " << iszero(dd("-0.0")) << "\n"; + std::cout << "iszero(0.0) = " << iszero(dd("0.0")) << "\n"; + std::cout << "iszero(1.0) = " << iszero(dd(1.0)) << "\n"; + std::cout << "iszero(inf) = " << iszero(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + std::cout << "signbit(-inf) = " << signbit(-std::numeric_limits
::infinity()) << "\n"; + std::cout << "signbit(-1.0) = " << signbit(dd(-1.0)) << "\n"; + std::cout << "signbit(-0.0) = " << signbit(dd("-0.0")) << "\n"; + std::cout << "signbit(0.0) = " << signbit(dd("0.0")) << "\n"; + std::cout << "signbit(1.0) = " << signbit(dd(1.0)) << "\n"; + std::cout << "signbit(inf) = " << signbit(std::numeric_limits
::infinity()) << "\n"; + std::cout << "\n"; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/error_and_gamma.cpp b/static/dd/math/error_and_gamma.cpp new file mode 100644 index 000000000..604b5a8f9 --- /dev/null +++ b/static/dd/math/error_and_gamma.cpp @@ -0,0 +1,105 @@ +// error_and_gamma.cpp: test suite runner for error and gamma functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// generate specific test case +template +void GenerateTestCase(Ty fa) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, ref, v; + a = fa; + fref = std::erf(fa); + ref = fref; + v = sw::universal::erf(a); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> erf(" << fa << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> erf( " << a << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib error/gamma function validation"; + std::string test_tag = "error/gamma"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + GenerateTestCase(1.0); + + dd x(-3.0), increment(0.5); + for (int i = 0; i < 14; i++) { + std::cout << " erf( " << x << ") = " << erf(x) << '\n'; + x += increment; + } + x = -3.0; + for (int i = 0; i < 14; i++) { + std::cout << " erfc( " << x << ") = " << erfc(x) << '\n'; + x += increment; + } + + //nrOfFailedTestCases += ReportTestResult(VerifyLogFunction
("Manual Testing", reportTestCases), "dd", test_tag); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/exponent.cpp b/static/dd/math/exponent.cpp new file mode 100644 index 000000000..45f282f1b --- /dev/null +++ b/static/dd/math/exponent.cpp @@ -0,0 +1,102 @@ +// exponent.cpp: test suite runner for exponentiation function for double-double (dd) floats +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include + +// generate specific test case +template +void GenerateTestCase(Ty fa) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, ref, v; + a = fa; + fref = std::exp(fa); + ref = fref; + v = sw::universal::exp(a); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> exp(" << fa << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> exp( " << a << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib exponentiation function validation"; + std::string test_tag = "exp"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + // generate individual testcases to hand trace/debug + GenerateTestCase(4.0); + + auto oldPrec = std::cout.precision(); + for (int i = 0; i < 30; ++i) { + std::string tag = "exp(" + std::to_string(i) + ")"; + double e = std::exp(double(i)); + dd dd_e = exp(dd(i)); + dd dd_diff = dd_e - dd(e); + double error = double(dd_diff); + std::cout << std::setw(20) << tag << " : " << std::setprecision(32) << dd_e << " : " << std::setprecision(15) << std::setw(20) << e << " : " << std::setw(25) << error << '\n'; + } + std::cout << std::setprecision(oldPrec); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/fractional.cpp b/static/dd/math/fractional.cpp new file mode 100644 index 000000000..b09a46d92 --- /dev/null +++ b/static/dd/math/fractional.cpp @@ -0,0 +1,101 @@ +// fractional.cpp: test suite runner for fractional functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// generate specific test case +template +void GenerateTestCase(Ty fa, Ty fb) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, b, ref, v; + a = fa; + b = fb; + fref = std::remainder(fa, fb); + ref = fref; + v = sw::universal::remainder(a, b); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> remainder(" << fa << "," << fb << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> remainder( " << a << "," << b << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + using std::fmod; + + std::string test_suite = "doubledouble mathlib fractional function validation"; + std::string test_tag = "fractional"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + double a{ 1.5 }, b{ 1.25 }; + dd da(a), db(b); + + std::cout << "fmod( " << a << ", " << b << ") = " << fmod(a, b) << '\n'; + std::cout << "fmod( " << da << ", " << db << ") = " << fmod(da, db) << '\n'; + + std::cout << "remainder( " << a << ", " << b << ") = " << remainder(a, b) << '\n'; + std::cout << "remainder( " << da << ", " << db << ") = " << remainder(da, db) << '\n'; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/hyperbolic.cpp b/static/dd/math/hyperbolic.cpp new file mode 100644 index 000000000..0e3b10167 --- /dev/null +++ b/static/dd/math/hyperbolic.cpp @@ -0,0 +1,80 @@ +// hyperbolic.cpp: test suite runner for hyperbolic functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib hyperbolic function validation"; + std::string test_tag = "hyperbolic"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd x = dd_pi4; + std::cout << "sinh( " << x << " ) = " << sinh(x) << '\n'; + std::cout << "cosh( " << x << " ) = " << cosh(x) << '\n'; + std::cout << "tanh( " << x << " ) = " << tanh(x) << '\n'; + + std::cout << "asinh( " << x << " ) = " << asinh(x) << '\n'; + std::cout << "acosh( " << x << " ) = " << acosh(x) << '\n'; + std::cout << "atanh( " << x << " ) = " << atanh(x) << '\n'; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/hypot.cpp b/static/dd/math/hypot.cpp new file mode 100644 index 000000000..d5795747c --- /dev/null +++ b/static/dd/math/hypot.cpp @@ -0,0 +1,75 @@ +// hypot.cpp: test suite runner for hypot functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib hypot function validation"; + std::string test_tag = "hypot"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd x{ 3.0 }, y{ 4.0 }; + + std::cout << "hypot( " << x << ", " << y << ") = " << hypot(x, y) << '\n'; + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/logarithm.cpp b/static/dd/math/logarithm.cpp new file mode 100644 index 000000000..b2c54b160 --- /dev/null +++ b/static/dd/math/logarithm.cpp @@ -0,0 +1,98 @@ +// logarithm.cpp: test suite runner for log/log1p/log2/log10 functions for doubledouble floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// generate specific test case +template +void GenerateLogTestCase(Ty fa) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, ref, v; + a = fa; + fref = std::log(fa); + ref = fref; + v = sw::universal::log(a); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> log(" << fa << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> log( " << a << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib logarithm function validation"; + std::string test_tag = "log/log1p/log2/log10"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + // generate individual testcases to hand trace/debug + GenerateLogTestCase(1.0); + GenerateLogTestCase(std::numbers::e); + for (int i = 2; i < 65; i *= 2) { + GenerateLogTestCase(pow(std::numbers::e, double(i))); + } + + //nrOfFailedTestCases += ReportTestResult(VerifyLogFunction
("Manual Testing", reportTestCases), "dd", test_tag); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/minmax.cpp b/static/dd/math/minmax.cpp new file mode 100644 index 000000000..8a5a75625 --- /dev/null +++ b/static/dd/math/minmax.cpp @@ -0,0 +1,75 @@ +// minmax.cpp: test suite runner for minmax functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib minmax function validation"; + std::string test_tag = "minmax"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd x{ 3.0 }, y{ 4.0 }; + + std::cout << "min( " << x << ", " << y << ") = " << min(x, y) << '\n'; + std::cout << "max( " << x << ", " << y << ") = " << max(x, y) << '\n'; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/next.cpp b/static/dd/math/next.cpp new file mode 100644 index 000000000..d5022b2d9 --- /dev/null +++ b/static/dd/math/next.cpp @@ -0,0 +1,95 @@ +// next.cpp: test suite runner for nextafter/nextbefore functions for doubledouble (dd) +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include + +// generate specific test case +template +void GenerateTestCase(Ty fa, Ty fb) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, b, ref, v; + a = fa; + b = fb; + fref = std::nextafter(fa, fb); + ref = fref; + v = sw::universal::nextafter(a, b); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> nextafter(" << fa << "," << fb << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> nextafter( " << a << "," << b << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib nextafter/nextbefore function validation"; + std::string test_tag = "pow"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + // generate individual testcases to hand trace/debug + GenerateTestCase(1.0, 2.0); + + + //nrOfFailedTestCases += ReportTestResult(VerifyNextFunction
("Manual Testing", reportTestCases), "dd", test_tag); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/pow.cpp b/static/dd/math/pow.cpp new file mode 100644 index 000000000..a16dedaa3 --- /dev/null +++ b/static/dd/math/pow.cpp @@ -0,0 +1,104 @@ +// pow.cpp: test suite runner for pow function for double-double (dd) floats +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include + +// generate specific test case +template +void GenerateTestCase(Ty fa, Ty fb) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, b, ref, v; + a = fa; + b = fb; + fref = std::pow(fa, fb); + ref = fref; + v = sw::universal::pow(a, b); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> pow(" << fa << "," << fb << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> pow( " << a << "," << b << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib power function validation"; + std::string test_tag = "pow"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + // generate individual testcases to hand trace/debug + GenerateTestCase(4.0, 2.0); + + dd a{ 1.0 }; + for (int i = 0; i < 30; ++i) { + std::string tag = "pow(1.0, " + std::to_string(i) + ")"; + ReportValue(pow(a, i), tag); + } + a = 2.0; + for (int i = 0; i < 30; ++i) { + std::string tag = "pow(2.0, " + std::to_string(i) + ")"; + ReportValue(pow(a, i), tag); + } + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/sqrt.cpp b/static/dd/math/sqrt.cpp new file mode 100644 index 000000000..6a7ce97f6 --- /dev/null +++ b/static/dd/math/sqrt.cpp @@ -0,0 +1,121 @@ +// sqrt.cpp: test suite runner for sqrt function for doubledouble floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include + +// generate specific test case +template +void GenerateSqrtTestCase(Ty fa) { + unsigned precision = 25; + //unsigned width = 30; + Ty fref; + sw::universal::dd a, ref, v; + a = fa; + fref = std::sqrt(fa); + ref = fref; + v = sw::universal::sqrt(a); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> sqrt(" << fa << ") = " << fref << std::endl; + std::cout << " -> sqrt( " << a << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +namespace sw { + namespace universal { + + template + int VerifySqrtFunction(bool reportTestCases, DoubleDouble a) { + int nrOfFailedTestCases{ 0 }; + DoubleDouble b{ a }; + for (int i = 0; i < 9; ++i) { + a *= a; + dd c = sqrt(a); + if (b != c) { + if (reportTestCases) std::cerr << "FAIL : " << b << " != " << c << '\n'; + ++nrOfFailedTestCases; + } + b *= b; + } + return nrOfFailedTestCases; + } + } +} + + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 0 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib sqrt function validation"; + std::string test_tag = "sqrt"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + // generate individual testcases to hand trace/debug + GenerateSqrtTestCase(1.0); + GenerateSqrtTestCase(1024.0 * 1024.0); + constexpr double minpos = std::numeric_limits::min(); + GenerateSqrtTestCase(minpos); + constexpr double maxpos = std::numeric_limits::max(); + GenerateSqrtTestCase(maxpos); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + nrOfFailedTestCases += ReportTestResult(VerifySqrtFunction(reportTestCases, dd(2.0)), "sqrt(dd > 1.0)", test_tag); + nrOfFailedTestCases += ReportTestResult(VerifySqrtFunction(reportTestCases, dd(0.5)), "sqrt(dd < 1.0)", test_tag); + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/trigonometry.cpp b/static/dd/math/trigonometry.cpp new file mode 100644 index 000000000..787cd0501 --- /dev/null +++ b/static/dd/math/trigonometry.cpp @@ -0,0 +1,98 @@ +// trigonometry.cpp: test suite runner for trigonometry functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// generate specific test case +template +void GenerateLogTestCase(Ty fa) { + unsigned precision = 25; + unsigned width = 30; + Ty fref; + sw::universal::dd a, ref, v; + a = fa; + fref = std::log(fa); + ref = fref; + v = sw::universal::log(a); + auto oldPrec = std::cout.precision(); + std::cout << std::setprecision(precision); + std::cout << " -> log(" << fa << ") = " << std::setw(width) << fref << std::endl; + std::cout << " -> log( " << a << ") = " << v << '\n' << to_binary(v) << '\n'; + std::cout << to_binary(ref) << "\n -> reference\n"; + std::cout << (ref == v ? "PASS" : "FAIL") << std::endl << std::endl; + std::cout << std::setprecision(oldPrec); +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib trigonometry function validation"; + std::string test_tag = "trigonometry"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + // generate individual testcases to hand trace/debug + GenerateLogTestCase(1.0); + GenerateLogTestCase(std::numbers::e); + for (int i = 2; i < 65; i *= 2) { + GenerateLogTestCase(pow(std::numbers::e, double(i))); + } + + //nrOfFailedTestCases += ReportTestResult(VerifyLogFunction
("Manual Testing", reportTestCases), "dd", test_tag); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/math/truncate.cpp b/static/dd/math/truncate.cpp new file mode 100644 index 000000000..e7397d909 --- /dev/null +++ b/static/dd/math/truncate.cpp @@ -0,0 +1,77 @@ +// truncate.cpp: test suite runner for truncate functions for double-double floating-point +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 1 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "doubledouble mathlib truncate function validation"; + std::string test_tag = "truncate"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + dd x{ 1.75 }; + + std::cout << "trunc( " << x << ") = " << trunc(x) << '\n'; + std::cout << "round( " << x << ") = " << round(x) << '\n'; + std::cout << "floor( " << x << ") = " << floor(x) << '\n'; + std::cout << "ceil( " << x << ") = " << ceil(x) << '\n'; + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore errors +#else + + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); + +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << "Caught ad-hoc exception: " << msg << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_arithmetic_exception& err) { + std::cerr << "Caught unexpected universal arithmetic exception : " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const sw::universal::universal_internal_exception& err) { + std::cerr << "Caught unexpected universal internal exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Caught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << std::endl; + return EXIT_FAILURE; +} diff --git a/static/dd/performance/perf.cpp b/static/dd/performance/perf.cpp new file mode 100644 index 000000000..523583d0f --- /dev/null +++ b/static/dd/performance/perf.cpp @@ -0,0 +1,184 @@ +// perf.cpp : baseline performance benchmarking for double-double (dd) arithmetic operators +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace sw::universal::internal { + + // Generic set of adds and subtracts for a given number system type + template + void AdditionSubtractionWorkload(size_t NR_OPS) { + Scalar a{ 0 }, b{ 0 }, c{ 0 }, d{ 0 }; + d = 1.0f; + c = d; + b = c; + a = b; + for (size_t i = 0; i < NR_OPS; ++i) { + c = a + b; + b = c; + } +// std::cout << a << ' ' << b << ' ' << c << ' ' << d << '\n'; + if (c == d) std::cout << "amazing\n"; + } + + // Generic set of multiplies for a given number system type + template + void MultiplicationWorkload(size_t NR_OPS) { + Scalar a{ 0 }, b{ 0 }, c{ 0 }, d{ 0 }; + d = 1.0f; + c = d; + b = 1.125f; + a = 1.0f / b; + for (size_t i = 0; i < NR_OPS; ++i) { + c = a * b; + b = c; + } +// std::cout << a << ' ' << b << ' ' << c << ' ' << d << '\n'; + if (c == d) std::cout << "amazing\n"; + } + + // Generic set of divides for a given number system type + template + void DivisionWorkload(size_t NR_OPS) { + Scalar a{ 0 }, b{ 0 }, c{ 0 }, d{ 0 }; + d = 1.0f; + c = d; + b = 1.5f; + a = 0.75f; + for (size_t i = 0; i < NR_OPS; ++i) { + c = a / b; + b = c; + } +// std::cout << a << ' ' << b << ' ' << c << ' ' << d << '\n'; + if (c == d) std::cout << "amazing\n"; + } + + /* + August, 2024, AMD Ryzen 7 2700X Eight-Core Processor, 3.70 GHz desktop + + Arithmetic operator performance (no SIMD) + float add/subtract 4194304 per 0.0003982sec -> 10 Gops/sec + double add/subtract 4194304 per 0.0004099sec -> 10 Gops/sec + quad add/subtract 2097152 per 0.204351sec -> 10 Mops/sec + dd add/subtract 4194304 per 0.0033172sec -> 1 Gops/sec + float multiplication 1048576 per 9.78e-05sec -> 10 Gops/sec + double multiplication 1048576 per 0.0001303sec -> 8 Gops/sec + quad multiplication 524288 per 0.0906857sec -> 5 Mops/sec + dd multiplication 1048576 per 0.0450566sec -> 23 Mops/sec + float division 1048576 per 0.0026275sec -> 399 Mops/sec + double division 1048576 per 0.0027365sec -> 383 Mops/sec + quad division 524288 per 5.85166sec -> 89 Kops/sec + dd division 1048576 per 0.112724sec -> 9 Mops/sec + + */ + + void TestArithmeticOperatorPerformance() { + using namespace sw::universal; + std::cout << "\nArithmetic operator performance\n"; + + size_t NR_OPS = 1024ull * 1024ull * 4ull; + PerformanceRunner("float add/subtract ", AdditionSubtractionWorkload< float >, NR_OPS); + PerformanceRunner("double add/subtract ", AdditionSubtractionWorkload< double >, NR_OPS); + PerformanceRunner("quad add/subtract ", AdditionSubtractionWorkload< sw::universal::quad >, NR_OPS / 2); + PerformanceRunner("dd add/subtract ", AdditionSubtractionWorkload< sw::universal::dd >, NR_OPS); + + NR_OPS = 1024ull * 1024ull; + PerformanceRunner("float multiplication", MultiplicationWorkload< float >, NR_OPS); + PerformanceRunner("double multiplication", MultiplicationWorkload< double >, NR_OPS); + PerformanceRunner("quad multiplication", MultiplicationWorkload< sw::universal::quad >, NR_OPS / 2); + PerformanceRunner("dd multiplication", MultiplicationWorkload< sw::universal::dd >, NR_OPS); + + NR_OPS = 1024ull * 1024ull; + PerformanceRunner("float division ", DivisionWorkload< float >, NR_OPS); + PerformanceRunner("double division ", DivisionWorkload< double >, NR_OPS); + PerformanceRunner("quad division ", DivisionWorkload< sw::universal::quad >, NR_OPS / 2); + PerformanceRunner("dd division ", DivisionWorkload< sw::universal::dd >, NR_OPS); + + } + +} + +// Regression testing guards: typically set by the cmake configuration, but MANUAL_TESTING is an override +#define MANUAL_TESTING 0 +// REGRESSION_LEVEL_OVERRIDE is set by the cmake file to drive a specific regression intensity +// It is the responsibility of the regression test to organize the tests in a quartile progression. +//#undef REGRESSION_LEVEL_OVERRIDE +#ifndef REGRESSION_LEVEL_OVERRIDE +#undef REGRESSION_LEVEL_1 +#undef REGRESSION_LEVEL_2 +#undef REGRESSION_LEVEL_3 +#undef REGRESSION_LEVEL_4 +#define REGRESSION_LEVEL_1 1 +#define REGRESSION_LEVEL_2 1 +#define REGRESSION_LEVEL_3 1 +#define REGRESSION_LEVEL_4 1 +#endif + +int main() +try { + using namespace sw::universal; + using namespace sw::universal::internal; + + std::string test_suite = "dd operator performance benchmarking"; + std::string test_tag = "performance"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + +#if MANUAL_TESTING + + TestArithmeticOperatorPerformance(); + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return EXIT_SUCCESS; // ignore failures +#else + +#if REGRESSION_LEVEL_1 + TestArithmeticOperatorPerformance(); +#endif + +#if REGRESSION_LEVEL_2 + +#endif + +#if REGRESSION_LEVEL_4 + +#endif + + ReportTestSuiteResults(test_suite, nrOfFailedTestCases); + return (nrOfFailedTestCases > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +#endif // MANUAL_TESTING +} +catch (char const* msg) { + std::cerr << msg << '\n'; + return EXIT_FAILURE; +} +catch (const std::runtime_error& err) { + std::cerr << "Uncaught runtime exception: " << err.what() << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "Caught unknown exception" << '\n'; + return EXIT_FAILURE; +} + +/* +ETLO +Date run : 3/01/2021 +Processor: Intel Core i7-7500 CPU @ 2.70GHz, 2 cores, 4 threads, 15W mobile processor +Memory : 16GB +System : 64-bit Windows 10 Pro, Version 1803, x64-based processor, OS build 17134.165 + +*/ diff --git a/static/dfloat/api/api.cpp b/static/dfloat/api/api.cpp index 773bc0f7f..963dd5027 100644 --- a/static/dfloat/api/api.cpp +++ b/static/dfloat/api/api.cpp @@ -1,6 +1,7 @@ // api.cpp: application programming interface tests for decimal floating-point number system // -// Copyright (C) 2017-2022 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -28,19 +29,19 @@ try { using TestType = dfloat<8, 2>; ReportTrivialityOfType(); } -#ifdef LATER + // default behavior std::cout << "+--------- Default dfloat has no subnormals, no supernormals and is not saturating\n"; { constexpr size_t nbits = 8; constexpr size_t es = 3; - using Real = dfloat; // bt = uint8_t, hasSubnormals = false, hasSupernormals = false, isSaturating = false + using Real = dfloat; // bt = uint8_t Real a(1.0f), b(0.5f); ArithmeticOperators(a, b); } - +#ifdef LATER // explicit configuration std::cout << "+--------- Explicit configuration of a dfloat\n"; { diff --git a/static/fixpnt/binary/api/constexpr.cpp b/static/fixpnt/binary/api/constexpr.cpp index 07737e573..567199467 100644 --- a/static/fixpnt/binary/api/constexpr.cpp +++ b/static/fixpnt/binary/api/constexpr.cpp @@ -32,25 +32,23 @@ int DecoratedConstructors() { std::cout << a << '\n'; } // constexpr for float depends on C++20 support and bit_cast<> -#if BIT_CAST_SUPPORT { - CONSTEXPRESSION Fixpnt a(1.0f); // float + BIT_CAST_CONSTEXPR Fixpnt a(1.0f); // float std::cout << a << '\n'; } { - CONSTEXPRESSION Fixpnt a(1.0); // double + BIT_CAST_CONSTEXPR Fixpnt a(1.0); // double std::cout << a << '\n'; } #if LONG_DOUBLE_SUPPORT { - CONSTEXPRESSION Fixpnt a(1.0l); // long double + #if defined(DEBUG_LONG_DOUBLE_CONSTEXPR) + Fixpnt a(1.0l); // long double std::cout << a << '\n'; + #endif } #endif // LONG_DOUBLE_SUPPORT -#else - std::cout << "constexpr not supported yet by compiler\n"; -#endif // BIT_CAST_SUPPORT } return nrOfFailedTestCases; @@ -73,25 +71,20 @@ int AssignmentOperators() { std::cout << a << '\n'; } // constexpr for float depends on C++20 support and bit_cast<> -#if BIT_CAST_SUPPORT { - CONSTEXPRESSION Fixpnt a = 1.0f; // float + BIT_CAST_CONSTEXPR Fixpnt a = 1.0f; // float std::cout << a << '\n'; } { - CONSTEXPRESSION Fixpnt a = 1.0; // double + BIT_CAST_CONSTEXPR Fixpnt a = 1.0; // double std::cout << a << '\n'; } #if LONG_DOUBLE_SUPPORT { - CONSTEXPRESSION Fixpnt a = 1.0l; // long double + Fixpnt a = 1.0l; // long double std::cout << a << '\n'; } #endif // LONG_DOUBLE_SUPPORT -#else - std::cout << "constexpr not supported yet by compiler\n"; - -#endif // BIT_CAST_SUPPORT } return nrOfFailedTestCases; diff --git a/static/fixpnt/binary/conversion/sat_subnormal_conversion.cpp b/static/fixpnt/binary/conversion/sat_subnormal_conversion.cpp index 621c6a0d0..6c06b0fad 100644 --- a/static/fixpnt/binary/conversion/sat_subnormal_conversion.cpp +++ b/static/fixpnt/binary/conversion/sat_subnormal_conversion.cpp @@ -146,7 +146,7 @@ try { return EXIT_SUCCESS; // ignore failures #else -#pragma message("Fixed-point saturating subnormal conversion : TBD") +std::cout << "Fixed-point saturating subnormal conversion : TODO\n"; #if REGRESSION_LEVEL_1 diff --git a/static/integer/binary/api/api.cpp b/static/integer/binary/api/api.cpp index d5ef606d4..dacfa1bbf 100644 --- a/static/integer/binary/api/api.cpp +++ b/static/integer/binary/api/api.cpp @@ -436,7 +436,7 @@ try { int8_t a0s = int8_t(a0); int8_t b0s = int8_t(b0); uint8_t c0 = static_cast(a0s / b0s); - std::cout << to_binary(c0, 8) << " : " << unsigned(c0) << '\n'; // -128/100 = -1 + std::cout << to_binary(c0, true, 8) << " : " << unsigned(c0) << '\n'; // -128/100 = -1 } { @@ -480,11 +480,11 @@ try { } int32_t _a = -1; for (unsigned i = 0; i < 32; ++i) { - std::cout << to_binary(_a, 32, false) << " : " << std::setw(11) << _a << '\n'; + std::cout << to_binary(_a, false, 32) << " : " << std::setw(11) << _a << '\n'; _a *= 2; } _a = 0x8000'0001; - std::cout << to_binary(_a, 32, false) << " : " << _a << '\n'; + std::cout << to_binary(_a, false, 32) << " : " << _a << '\n'; } { diff --git a/static/integer/binary/conversion/conversion.cpp b/static/integer/binary/conversion/conversion.cpp index 92b13e2a7..edf3a6e6f 100644 --- a/static/integer/binary/conversion/conversion.cpp +++ b/static/integer/binary/conversion/conversion.cpp @@ -40,19 +40,19 @@ int VerifyToIntegerConversion(bool reportTestCases) { uint16_t ua16 = uint16_t(a); uint32_t ua32 = uint32_t(a); uint64_t ua64 = uint64_t(a); - std::cout << "ua8 : " << to_binary(ua8, sizeof(ua8) * 8, true) << std::setw(95) << (long long)(ua8) << '\n'; - std::cout << "ua16 : " << to_binary(ua16, sizeof(ua16) * 8, true) << std::setw(85) << (long long)(ua16) << '\n'; - std::cout << "ua32 : " << to_binary(ua32, sizeof(ua32) * 8, true) << std::setw(65) << (long long)(ua32) << '\n'; - std::cout << "ua64 : " << to_binary(ua64, sizeof(ua64) * 8, true) << std::setw(25) << (long long)(ua64) << '\n'; + std::cout << "ua8 : " << to_binary(ua8, true, sizeof(ua8) * 8) << std::setw(95) << (long long)(ua8) << '\n'; + std::cout << "ua16 : " << to_binary(ua16, true, sizeof(ua16) * 8) << std::setw(85) << (long long)(ua16) << '\n'; + std::cout << "ua32 : " << to_binary(ua32, true, sizeof(ua32) * 8) << std::setw(65) << (long long)(ua32) << '\n'; + std::cout << "ua64 : " << to_binary(ua64, true, sizeof(ua64) * 8) << std::setw(25) << (long long)(ua64) << '\n'; int8_t ia8 = int8_t(a); int16_t ia16 = int16_t(a); int32_t ia32 = int32_t(a); int64_t ia64 = int64_t(a); - std::cout << "ia8 : " << to_binary(ia8, sizeof(ia8) * 8, true) << std::setw(95) << (long long)(ia8) << '\n'; - std::cout << "ia16 : " << to_binary(ia16, sizeof(ia16) * 8, true) << std::setw(85) << (long long)(ia16) << '\n'; - std::cout << "ia32 : " << to_binary(ia32, sizeof(ia32) * 8, true) << std::setw(65) << (long long)(ia32) << '\n'; - std::cout << "ia64 : " << to_binary(ia64, sizeof(ia64) * 8, true) << std::setw(25) << (long long)(ia64) << '\n'; + std::cout << "ia8 : " << to_binary(ia8, true, sizeof(ia8) * 8) << std::setw(95) << (long long)(ia8) << '\n'; + std::cout << "ia16 : " << to_binary(ia16, true, sizeof(ia16) * 8) << std::setw(85) << (long long)(ia16) << '\n'; + std::cout << "ia32 : " << to_binary(ia32, true, sizeof(ia32) * 8) << std::setw(65) << (long long)(ia32) << '\n'; + std::cout << "ia64 : " << to_binary(ia64, true, sizeof(ia64) * 8) << std::setw(25) << (long long)(ia64) << '\n'; return nrOfFailedTests; } diff --git a/static/integer/binary/logic/bit_manipulation.cpp b/static/integer/binary/logic/bit_manipulation.cpp index 6f44cc43e..4b0c12d98 100644 --- a/static/integer/binary/logic/bit_manipulation.cpp +++ b/static/integer/binary/logic/bit_manipulation.cpp @@ -57,7 +57,7 @@ void TestNLZ() { uint8_t a = 0x1; for (uint32_t i = 0; i < 8; ++i) { int shift = nlz(a); - std::cout << " shift = " << shift << " : " << to_binary(a, 8, true) << '\n'; + std::cout << " shift = " << shift << " : " << to_binary(a, true, 8) << '\n'; a <<= 1; } } @@ -66,7 +66,7 @@ void TestNLZ() { uint16_t a = 0x1; for (uint32_t i = 0; i < 16; ++i) { int shift = nlz(a); - std::cout << " shift = " << shift << " : " << to_binary(a, 16, true) << '\n'; + std::cout << " shift = " << shift << " : " << to_binary(a, true, 16) << '\n'; a <<= 1; } } @@ -74,7 +74,7 @@ void TestNLZ() { uint32_t a = 0x1; for (uint32_t i = 0; i < 32; ++i) { int shift = nlz(a); - std::cout << " shift = " << shift << " : " << to_binary(a, 32, true) << '\n'; + std::cout << " shift = " << shift << " : " << to_binary(a, true, 32) << '\n'; a <<= 1; } } @@ -82,7 +82,7 @@ void TestNLZ() { uint64_t a = 0x1; for (uint32_t i = 0; i < 64; ++i) { int shift = nlz(a); - std::cout << " shift = " << shift << " : " << to_binary(a, 64, true) << '\n'; + std::cout << " shift = " << shift << " : " << to_binary(a, true, 64) << '\n'; a <<= 1; } } diff --git a/static/native/float/bit_manipulation.cpp b/static/native/float/bit_manipulation.cpp index 09d8a78a8..b48fc6e8b 100644 --- a/static/native/float/bit_manipulation.cpp +++ b/static/native/float/bit_manipulation.cpp @@ -1,6 +1,7 @@ // bit_manipulation.cpp: experiments with the C++20 library // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include @@ -45,6 +46,7 @@ std::cout << "Architecture is unknown\n"; extractFields(a, sign, rawExponent, rawFraction, bits); exponent = static_cast(rawExponent) - ieee754_parameter::bias; + std::cout << "sign : " << (sign ? "1\n" : "0\n"); std::cout << "rawExponent : " << rawExponent << '\n'; std::cout << "exponent bias : " << ieee754_parameter::bias << '\n'; std::cout << "unbiased exponent : " << exponent << '\n'; @@ -118,9 +120,37 @@ try { std::cout << "size of long double : " << sizeof(ld) << '\n'; ReportValue(ld); + { + /* + struct blob { + std::uint64_t hi; + std::uint64_t fraction; + } raw; + raw = std::bit_cast(value); + std::cout << "sign mask : " << to_binary(ieee754_parameter::smask) << '\n'; + std::cout << "exponent mask : " << to_binary(ieee754_parameter::emask) << '\n'; + std::cout << "fraction mask : " << to_binary(ieee754_parameter::fmask) << '\n'; + std::cout << "hi : " << to_binary(raw.hi) << '\n'; + std::cout << "fraction bits : " << to_binary(raw.fraction) << '\n'; + bool s = (ieee754_parameter::smask & raw.hi); + uint64_t eBits = (ieee754_parameter::emask & raw.hi); + uint64_t fBits = (ieee754_parameter::fmask & raw.fraction); + std::cout << "sign : " << (s ? "1\n" : "0\n"); + std::cout << "eBits : " << to_binary(eBits) << '\n'; + std::cout << "fBits : " << to_binary(fBits) << '\n'; + */ + long_double_decoder decoder; + decoder.ld = 1.0l; + std::cout << "sign : " << (decoder.parts.sign ? "1\n" : "0\n"); + std::cout << "eBits : " << to_binary(decoder.parts.exponent) << '\n'; + std::cout << "fBits : " << to_binary(decoder.parts.fraction) << '\n'; + } + nrOfFailedTestCases += ReportTestResult(VerifyRealFieldExtraction(reportTestCases), "float", test_tag); nrOfFailedTestCases += ReportTestResult(VerifyRealFieldExtraction(reportTestCases), "double", test_tag); +#if LONG_DOUBLE_SUPPORT nrOfFailedTestCases += ReportTestResult(VerifyRealFieldExtraction(reportTestCases), "long double", test_tag); +#endif ReportTestSuiteResults(test_suite, nrOfFailedTestCases); return EXIT_SUCCESS; // ignore failures diff --git a/static/qd/CMakeLists.txt b/static/qd/CMakeLists.txt new file mode 100644 index 000000000..2072f6423 --- /dev/null +++ b/static/qd/CMakeLists.txt @@ -0,0 +1,14 @@ +file (GLOB API_SRC "api/*.cpp") +file (GLOB LOGIC_SRC "logic/*.cpp") +file (GLOB CONVERSION_SRC "conversion/*.cpp") +file (GLOB ARITHMETIC_SRC "arithmetic/*.cpp") +file (GLOB MATH_SRC "./math/*.cpp") +#file (GLOB PERFORMANCE_SRC "./performance/*.cpp") + +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/api" "${API_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/logic" "${LOGIC_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/conversion" "${CONVERSION_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/arithmetic" "${ARITHMETIC_SRC}") +compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/math" "${MATH_SRC}") +#compile_all("true" "dd" "Number Systems/static/floating-point/binary/dd/performance" "${PERFORMANCE_SRC}") + diff --git a/static/takum/api/api.cpp b/static/takum/api/api.cpp index bdb11f050..fb90143fe 100644 --- a/static/takum/api/api.cpp +++ b/static/takum/api/api.cpp @@ -82,20 +82,20 @@ try { std::cout << dynamic_range>() << '\n'; } -#if BIT_CAST_SUPPORT +#if BIT_CAST_IS_CONSTEXPR { std::cout << "+--------- constexpr and specific values --------+\n"; constexpr size_t nbits = 10; using Real = takum; // BlockType = uint8_t - CONSTEXPRESSION Real a{}; // zero constexpr + BIT_CAST_CONSTEXPR Real a{}; // zero constexpr std::cout << type_tag(a) << '\n'; // constexpr of a native floating-point type construction requires a constexpr log2 and floor library function // CONSTEXPRESSION Real b(1.0f); // constexpr of a native type conversion // std::cout << to_binary(b) << " : " << b << '\n'; - CONSTEXPRESSION Real c(SpecificValue::minpos); // constexpr of a special value in the encoding + BIT_CAST_CONSTEXPR Real c(SpecificValue::minpos); // constexpr of a special value in the encoding constexpr float fminpos = float(c); float f = 1.0f; if (f < fminpos) { @@ -106,16 +106,16 @@ try { } std::cout << to_binary(c) << " : " << c << " == minpos" << '\n'; - CONSTEXPRESSION Real d(SpecificValue::maxpos); // constexpr of a special value in the encoding + BIT_CAST_CONSTEXPR Real d(SpecificValue::maxpos); // constexpr of a special value in the encoding std::cout << to_binary(d) << " : " << d << " == maxpos" << '\n'; } -#else +#else // ! BIT_CAST_IS_CONSTEXPR { std::cout << "+--------- constexpr and specific values --------+\n"; std::cout << "compiler does not support constexpr on native floating-point types\n"; report_compiler(); } -#endif +#endif // BIT_CAST_IS_CONSTEXPR { std::cout << "+--------- extreme values --------+\n"; diff --git a/tools/cmake/summary.cmake b/tools/cmake/summary.cmake index bfd223e52..15dfca677 100644 --- a/tools/cmake/summary.cmake +++ b/tools/cmake/summary.cmake @@ -124,6 +124,8 @@ function(universal_print_configuration_summary) universal_status(" BUILD_NUMBER_BFLOATS : ${BUILD_NUMBER_BFLOATS}") universal_status(" BUILD_NUMBER_CFLOATS : ${BUILD_NUMBER_CFLOATS}") universal_status(" BUILD_NUMBER_DFLOATS : ${BUILD_NUMBER_DFLOATS}") + universal_status(" BUILD_NUMBER_DDS : ${BUILD_NUMBER_DDS}") + universal_status(" BUILD_NUMBER_QDS : ${BUILD_NUMBER_QDS}") universal_status(" BUILD_NUMBER_AREALS : ${BUILD_NUMBER_AREALS}") universal_status(" BUILD_NUMBER_UNUM1S : ${BUILD_NUMBER_UNUM1S}") universal_status(" BUILD_NUMBER_UNUM2S : ${BUILD_NUMBER_UNUM2S}") diff --git a/tools/cmd/ieee.cpp b/tools/cmd/ieee.cpp index 42c6b9589..8e687d757 100644 --- a/tools/cmd/ieee.cpp +++ b/tools/cmd/ieee.cpp @@ -1,13 +1,17 @@ // ieee.cpp: cli to show the sign/scale/fraction components of a 32b/64/128b IEEE floats // -// Copyright (C) 2017-2021 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include #include #include +#include +#include #include #include +#define VALUE_THROW_ARITHMETIC_EXCEPTION 0 #include std::string version_string(int a, int b, int c) { @@ -16,44 +20,6 @@ std::string version_string(int a, int b, int c) { return ss.str(); } -std::string report_compiler_version() { -#if defined(__clang__) - /* Clang/LLVM. ---------------------------------------------- */ - return version_string(__clang_major__, __clang_minor__, __clang_patchlevel__); - -#elif defined(__ICC) || defined(__INTEL_COMPILER) - /* Intel ICC/ICPC. ------------------------------------------ */ - return std::string("Intel Compiler"); - -#elif defined(__GNUC__) || defined(__GNUG__) - /* GNU GCC/G++. --------------------------------------------- */ - return version_string(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); - -#elif defined(__HP_cc) || defined(__HP_aCC) - /* Hewlett-Packard C/C++. ---------------------------------- */ - return std::string("Hewlett-Packard C/C++ compiler"); - -#elif defined(__IBMC__) || defined(__IBMCPP__) - /* IBM XL C/C++. -------------------------------------------- */ - return std::string("IBM XL C/C++"); - -#elif defined(_MSC_VER) - /* Microsoft Visual Studio. --------------------------------- */ - // Visual C++ compiler is 15.00.20706.01, the _MSC_FULL_VER will be 15002070601 - char version[16]; - sprintf(version, "%d", _MSC_FULL_VER); - return std::string("Microsoft Visual Studio C++ compiler version ") + std::string(version); - -#elif defined(__PGI) - /* Portland Group PGCC/PGCPP. ------------------------------- */ - return std::string("Portland Group PGCC/PGCPP"); - -#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - /* Oracle Solaris Studio. ----------------------------------- */ - return std::string("Oracle Solaris Studio"); -#endif -} - // receive a float and print the components of a IEEE float representations int main(int argc, char** argv) try { @@ -87,7 +53,7 @@ try { double d = double(q); float f = float(d); - std::cout << "compiler : " << report_compiler_version() << '\n'; + report_compiler(); std::cout << "float precision : " << f_fbits << " bits\n"; std::cout << "double precision : " << d_fbits << " bits\n"; std::cout << "long double precision : " << q_fbits << " bits\n"; diff --git a/tools/utils/execution_environment.cpp b/tools/utils/execution_environment.cpp index e14e0a2ce..41bd7532c 100644 --- a/tools/utils/execution_environment.cpp +++ b/tools/utils/execution_environment.cpp @@ -1,6 +1,7 @@ // execution_environment.cpp: cli to show the execution environment: compiler and arch // -// Copyright (C) 2017-2023 Stillwater Supercomputing, Inc. +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // // This file is part of the universal numbers project, which is released under an MIT Open Source license. #include diff --git a/tools/utils/language_feature_testing.cpp b/tools/utils/language_feature_testing.cpp new file mode 100644 index 000000000..425ef3eb4 --- /dev/null +++ b/tools/utils/language_feature_testing.cpp @@ -0,0 +1,666 @@ +// language_feature_testing.cpp: cli to show the language features +// +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT +// +// https://en.cppreference.com/w/cpp/feature_test +// +// This file is part of the universal numbers project, which is released under an MIT Open Source license. +#include +#include + +static constexpr struct change_these_options_to_select_what_will_be_printed +{ + constexpr static int longest_macro_name{ 45 }; + constexpr static bool titles = 1; + constexpr static bool counters = 1; + constexpr static bool attributes = 1; + constexpr static bool standard_values = 1; + constexpr static bool compiler_specific = 1; + constexpr static bool core_features = 1; + constexpr static bool lib_features = 1; + constexpr static bool supported_features = 1; + constexpr static bool unsupported_features = 1; + constexpr static bool sort_by_date = 0; + constexpr static bool separate_year_month = 1; + constexpr static bool separated_revisions = 1; + constexpr static bool latest_revisions = 1; + constexpr static bool cxx98 = 0; + constexpr static bool cxx11 = 1; + constexpr static bool cxx14 = 1; + constexpr static bool cxx17 = 1; + constexpr static bool cxx20 = 1; + constexpr static bool cxx23 = 1; + constexpr static bool cxx26 = 1; + constexpr static bool cxx29 = 0; +} print; + +#if __cplusplus < 201100 +# error "C++11 or better is required" +#endif + +#include +#include +#include +#include +#include + +#ifdef __has_include +# if __has_include() +# include +# endif +#endif + +// Expect a string that starts with 6-decimal-digits or with '_' (if unsupported) +#define COMPILER_VALUE_INT(n) #n [0] == '_' ? 0 : \ + (#n[5] - '0') + (#n[4] - '0') * 10 + (#n[3] - '0') * 100 + \ + (#n[2] - '0') * 1000 + (#n[1] - '0') * 10000 + (#n[0] - '0') * 100000 +#define COMPILER_FEATURE_ENTRY(expect, name) { #name, COMPILER_VALUE_INT(name), expect }, + +#if defined(__has_cpp_attribute) && defined(__GNUG__) +# define COMPILER_ATTRIBUTE(expect, name) { #name, __has_cpp_attribute(name), expect }, +#else +# define COMPILER_ATTRIBUTE(expect, name) { #name, COMPILER_VALUE_INT(name), expect }, +#endif + +#define COMPILER_SPECIFIC_STRING(value) #value +#define COMPILER_SPECIFIC_ENTRY(name) { #name, COMPILER_SPECIFIC_STRING(name) }, + +class CompilerFeature +{ + char const* name_; long data_; long std_; +public: + constexpr CompilerFeature(char const* name, long data, long std) + : name_(name), data_(data), std_(std) {} + constexpr CompilerFeature(CompilerFeature const&) = default; + CompilerFeature& operator=(CompilerFeature const&) = default; + bool operator<(CompilerFeature const& rhs) const + { + return std::strcmp(name_, rhs.name_) < 0; + } + bool operator==(CompilerFeature const& rhs) const + { + return std::strcmp(name_, rhs.name_) == 0; + } + constexpr bool supported() const { return data_ >= std_; } + constexpr bool maybe() const { return data_ > 0; } + constexpr char const* name() const { return name_; } + constexpr long std() const { return std_; } + constexpr long data() const { return data_; } + void data(long x) { data_ = x; } +}; + +static /*constexpr*/ std::pair compiler[] = { + COMPILER_SPECIFIC_ENTRY(__cplusplus) //< not compiler specific, but useful :) + COMPILER_SPECIFIC_ENTRY(__clang_major__) + COMPILER_SPECIFIC_ENTRY(__clang_minor__) + COMPILER_SPECIFIC_ENTRY(__clang_patchlevel__) + COMPILER_SPECIFIC_ENTRY(__GNUG__) + COMPILER_SPECIFIC_ENTRY(__GNUC_MINOR__) + COMPILER_SPECIFIC_ENTRY(__GNUC_PATCHLEVEL__) + // Add your favorite compiler specific macros. Undefined ones will not be printed. +}; + +static constexpr CompilerFeature cxx98_core[] = { + COMPILER_FEATURE_ENTRY(199711L, __cpp_exceptions) + COMPILER_FEATURE_ENTRY(199711L, __cpp_rtti) +}; + +static constexpr CompilerFeature cxx11_core[] = { + COMPILER_FEATURE_ENTRY(200704L, __cpp_alias_templates) + COMPILER_FEATURE_ENTRY(200809L, __cpp_attributes) + COMPILER_FEATURE_ENTRY(200704L, __cpp_constexpr) + COMPILER_FEATURE_ENTRY(201711L, __cpp_constexpr_in_decltype) + COMPILER_FEATURE_ENTRY(200707L, __cpp_decltype) + COMPILER_FEATURE_ENTRY(200604L, __cpp_delegating_constructors) + COMPILER_FEATURE_ENTRY(201511L, __cpp_inheriting_constructors) + COMPILER_FEATURE_ENTRY(200806L, __cpp_initializer_lists) + COMPILER_FEATURE_ENTRY(200907L, __cpp_lambdas) + COMPILER_FEATURE_ENTRY(200809L, __cpp_nsdmi) + COMPILER_FEATURE_ENTRY(200907L, __cpp_range_based_for) + COMPILER_FEATURE_ENTRY(200710L, __cpp_raw_strings) + COMPILER_FEATURE_ENTRY(200710L, __cpp_ref_qualifiers) + COMPILER_FEATURE_ENTRY(200610L, __cpp_rvalue_references) + COMPILER_FEATURE_ENTRY(200410L, __cpp_static_assert) + COMPILER_FEATURE_ENTRY(200806L, __cpp_threadsafe_static_init) + COMPILER_FEATURE_ENTRY(200704L, __cpp_unicode_characters) + COMPILER_FEATURE_ENTRY(200710L, __cpp_unicode_literals) + COMPILER_FEATURE_ENTRY(200809L, __cpp_user_defined_literals) + COMPILER_FEATURE_ENTRY(200704L, __cpp_variadic_templates) +}; + +static constexpr CompilerFeature cxx14_core[] = { + COMPILER_FEATURE_ENTRY(201304L, __cpp_aggregate_nsdmi) + COMPILER_FEATURE_ENTRY(201304L, __cpp_binary_literals) + COMPILER_FEATURE_ENTRY(201304L, __cpp_constexpr) + COMPILER_FEATURE_ENTRY(201304L, __cpp_decltype_auto) + COMPILER_FEATURE_ENTRY(201304L, __cpp_generic_lambdas) + COMPILER_FEATURE_ENTRY(201304L, __cpp_init_captures) + COMPILER_FEATURE_ENTRY(201304L, __cpp_return_type_deduction) + COMPILER_FEATURE_ENTRY(201309L, __cpp_sized_deallocation) + COMPILER_FEATURE_ENTRY(201304L, __cpp_variable_templates) +}; +static constexpr CompilerFeature cxx14_lib[] = { + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_chrono_udls) + COMPILER_FEATURE_ENTRY(201309L, __cpp_lib_complex_udls) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_exchange_function) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_generic_associative_lookup) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_integer_sequence) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_integral_constant_callable) + COMPILER_FEATURE_ENTRY(201402L, __cpp_lib_is_final) + COMPILER_FEATURE_ENTRY(201309L, __cpp_lib_is_null_pointer) + COMPILER_FEATURE_ENTRY(201402L, __cpp_lib_make_reverse_iterator) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_make_unique) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_null_iterators) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_quoted_string_io) + COMPILER_FEATURE_ENTRY(201210L, __cpp_lib_result_of_sfinae) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_robust_nonmodifying_seq_ops) + COMPILER_FEATURE_ENTRY(201402L, __cpp_lib_shared_timed_mutex) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_string_udls) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_transformation_trait_aliases) + COMPILER_FEATURE_ENTRY(201210L, __cpp_lib_transparent_operators) + COMPILER_FEATURE_ENTRY(201402L, __cpp_lib_tuple_element_t) + COMPILER_FEATURE_ENTRY(201304L, __cpp_lib_tuples_by_type) +}; + +static constexpr CompilerFeature cxx17_core[] = { + COMPILER_FEATURE_ENTRY(201603L, __cpp_aggregate_bases) + COMPILER_FEATURE_ENTRY(201606L, __cpp_aligned_new) + COMPILER_FEATURE_ENTRY(201603L, __cpp_capture_star_this) + COMPILER_FEATURE_ENTRY(201603L, __cpp_constexpr) + COMPILER_FEATURE_ENTRY(201703L, __cpp_deduction_guides) + COMPILER_FEATURE_ENTRY(201411L, __cpp_enumerator_attributes) + COMPILER_FEATURE_ENTRY(201603L, __cpp_fold_expressions) + COMPILER_FEATURE_ENTRY(201606L, __cpp_guaranteed_copy_elision) + COMPILER_FEATURE_ENTRY(201603L, __cpp_hex_float) + COMPILER_FEATURE_ENTRY(201606L, __cpp_if_constexpr) + COMPILER_FEATURE_ENTRY(201606L, __cpp_inline_variables) + COMPILER_FEATURE_ENTRY(201411L, __cpp_namespace_attributes) + COMPILER_FEATURE_ENTRY(201510L, __cpp_noexcept_function_type) + COMPILER_FEATURE_ENTRY(201411L, __cpp_nontype_template_args) + COMPILER_FEATURE_ENTRY(201606L, __cpp_nontype_template_parameter_auto) + COMPILER_FEATURE_ENTRY(201603L, __cpp_range_based_for) + COMPILER_FEATURE_ENTRY(201411L, __cpp_static_assert) + COMPILER_FEATURE_ENTRY(201606L, __cpp_structured_bindings) + COMPILER_FEATURE_ENTRY(201611L, __cpp_template_template_args) + COMPILER_FEATURE_ENTRY(201611L, __cpp_variadic_using) +}; +static constexpr CompilerFeature cxx17_lib[] = { + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_addressof_constexpr) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_allocator_traits_is_always_equal) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_any) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_apply) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_array_constexpr) + COMPILER_FEATURE_ENTRY(201510L, __cpp_lib_as_const) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_atomic_is_always_lock_free) + COMPILER_FEATURE_ENTRY(201505L, __cpp_lib_bool_constant) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_boyer_moore_searcher) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_byte) + COMPILER_FEATURE_ENTRY(201611L, __cpp_lib_chrono) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_clamp) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_enable_shared_from_this) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_execution) + COMPILER_FEATURE_ENTRY(201703L, __cpp_lib_filesystem) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_gcd_lcm) + COMPILER_FEATURE_ENTRY(201703L, __cpp_lib_hardware_interference_size) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_has_unique_object_representations) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_hypot) + COMPILER_FEATURE_ENTRY(201505L, __cpp_lib_incomplete_container_elements) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_invoke) + COMPILER_FEATURE_ENTRY(201703L, __cpp_lib_is_aggregate) + COMPILER_FEATURE_ENTRY(201703L, __cpp_lib_is_invocable) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_is_swappable) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_launder) + COMPILER_FEATURE_ENTRY(201510L, __cpp_lib_logical_traits) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_make_from_tuple) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_map_try_emplace) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_math_special_functions) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_memory_resource) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_node_extract) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_nonmember_container_access) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_not_fn) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_optional) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_parallel_algorithm) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_raw_memory_algorithms) + COMPILER_FEATURE_ENTRY(201603L, __cpp_lib_sample) + COMPILER_FEATURE_ENTRY(201703L, __cpp_lib_scoped_lock) + COMPILER_FEATURE_ENTRY(201505L, __cpp_lib_shared_mutex) + COMPILER_FEATURE_ENTRY(201611L, __cpp_lib_shared_ptr_arrays) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_shared_ptr_weak_type) + COMPILER_FEATURE_ENTRY(201606L, __cpp_lib_string_view) + COMPILER_FEATURE_ENTRY(201611L, __cpp_lib_to_chars) + COMPILER_FEATURE_ENTRY(201510L, __cpp_lib_transparent_operators) + COMPILER_FEATURE_ENTRY(201510L, __cpp_lib_type_trait_variable_templates) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_uncaught_exceptions) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_unordered_map_try_emplace) + COMPILER_FEATURE_ENTRY(202102L, __cpp_lib_variant) + COMPILER_FEATURE_ENTRY(201411L, __cpp_lib_void_t) +}; + +static constexpr CompilerFeature cxx20_core[] = { + COMPILER_FEATURE_ENTRY(201902L, __cpp_aggregate_paren_init) + COMPILER_FEATURE_ENTRY(202207L, __cpp_char8_t) + COMPILER_FEATURE_ENTRY(202002L, __cpp_concepts) + COMPILER_FEATURE_ENTRY(201806L, __cpp_conditional_explicit) + COMPILER_FEATURE_ENTRY(202211L, __cpp_consteval) + COMPILER_FEATURE_ENTRY(202002L, __cpp_constexpr) + COMPILER_FEATURE_ENTRY(201907L, __cpp_constexpr_dynamic_alloc) + COMPILER_FEATURE_ENTRY(201907L, __cpp_constinit) + COMPILER_FEATURE_ENTRY(201907L, __cpp_deduction_guides) + COMPILER_FEATURE_ENTRY(201707L, __cpp_designated_initializers) + COMPILER_FEATURE_ENTRY(201707L, __cpp_generic_lambdas) + COMPILER_FEATURE_ENTRY(201902L, __cpp_impl_coroutine) + COMPILER_FEATURE_ENTRY(201806L, __cpp_impl_destroying_delete) + COMPILER_FEATURE_ENTRY(201907L, __cpp_impl_three_way_comparison) + COMPILER_FEATURE_ENTRY(201803L, __cpp_init_captures) + COMPILER_FEATURE_ENTRY(201907L, __cpp_modules) + COMPILER_FEATURE_ENTRY(201911L, __cpp_nontype_template_args) + COMPILER_FEATURE_ENTRY(201907L, __cpp_using_enum) +}; +static constexpr CompilerFeature cxx20_lib[] = { + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_array_constexpr) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_assume_aligned) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_atomic_flag_test) + COMPILER_FEATURE_ENTRY(201711L, __cpp_lib_atomic_float) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_atomic_lock_free_type_aliases) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_atomic_ref) + COMPILER_FEATURE_ENTRY(201711L, __cpp_lib_atomic_shared_ptr) + COMPILER_FEATURE_ENTRY(201911L, __cpp_lib_atomic_value_initialization) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_atomic_wait) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_barrier) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_bind_front) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_bit_cast) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_bitops) + COMPILER_FEATURE_ENTRY(201902L, __cpp_lib_bounded_array_traits) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_char8_t) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_chrono) + COMPILER_FEATURE_ENTRY(202002L, __cpp_lib_concepts) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_constexpr_algorithms) + COMPILER_FEATURE_ENTRY(201711L, __cpp_lib_constexpr_complex) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_constexpr_dynamic_alloc) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_constexpr_functional) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_constexpr_iterator) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_constexpr_memory) + COMPILER_FEATURE_ENTRY(201911L, __cpp_lib_constexpr_numeric) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_constexpr_string) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_constexpr_string_view) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_constexpr_tuple) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_constexpr_utility) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_constexpr_vector) + COMPILER_FEATURE_ENTRY(201902L, __cpp_lib_coroutine) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_destroying_delete) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_endian) + COMPILER_FEATURE_ENTRY(202002L, __cpp_lib_erase_if) + COMPILER_FEATURE_ENTRY(201902L, __cpp_lib_execution) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_format) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_generic_unordered_lookup) + COMPILER_FEATURE_ENTRY(202002L, __cpp_lib_int_pow2) + COMPILER_FEATURE_ENTRY(202002L, __cpp_lib_integer_comparison_functions) + COMPILER_FEATURE_ENTRY(201902L, __cpp_lib_interpolate) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_is_constant_evaluated) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_is_layout_compatible) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_is_nothrow_convertible) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_is_pointer_interconvertible) + COMPILER_FEATURE_ENTRY(201911L, __cpp_lib_jthread) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_latch) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_list_remove_return_type) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_math_constants) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_optional) + COMPILER_FEATURE_ENTRY(201902L, __cpp_lib_polymorphic_allocator) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_ranges) + COMPILER_FEATURE_ENTRY(201711L, __cpp_lib_remove_cvref) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_semaphore) + COMPILER_FEATURE_ENTRY(201707L, __cpp_lib_shared_ptr_arrays) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_shift) + COMPILER_FEATURE_ENTRY(202002L, __cpp_lib_smart_ptr_for_overwrite) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_source_location) + COMPILER_FEATURE_ENTRY(202002L, __cpp_lib_span) + COMPILER_FEATURE_ENTRY(201902L, __cpp_lib_ssize) + COMPILER_FEATURE_ENTRY(201711L, __cpp_lib_starts_ends_with) + COMPILER_FEATURE_ENTRY(201803L, __cpp_lib_string_view) + COMPILER_FEATURE_ENTRY(201803L, __cpp_lib_syncbuf) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_three_way_comparison) + COMPILER_FEATURE_ENTRY(201711L, __cpp_lib_to_address) + COMPILER_FEATURE_ENTRY(201907L, __cpp_lib_to_array) + COMPILER_FEATURE_ENTRY(201806L, __cpp_lib_type_identity) + COMPILER_FEATURE_ENTRY(201811L, __cpp_lib_unwrap_ref) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_variant) +}; + +static constexpr CompilerFeature cxx23_core[] = { + COMPILER_FEATURE_ENTRY(202110L, __cpp_auto_cast) + COMPILER_FEATURE_ENTRY(202211L, __cpp_constexpr) + COMPILER_FEATURE_ENTRY(202110L, __cpp_explicit_this_parameter) + COMPILER_FEATURE_ENTRY(202106L, __cpp_if_consteval) + COMPILER_FEATURE_ENTRY(202207L, __cpp_implicit_move) + COMPILER_FEATURE_ENTRY(202211L, __cpp_multidimensional_subscript) + COMPILER_FEATURE_ENTRY(202207L, __cpp_named_character_escapes) + COMPILER_FEATURE_ENTRY(202211L, __cpp_range_based_for) + COMPILER_FEATURE_ENTRY(202011L, __cpp_size_t_suffix) + COMPILER_FEATURE_ENTRY(202207L, __cpp_static_call_operator) +}; +static constexpr CompilerFeature cxx23_lib[] = { + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_adaptor_iterator_pair_constructor) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_algorithm_iterator_requirements) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_allocate_at_least) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_associative_heterogeneous_erasure) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_barrier) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_bind_back) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_byteswap) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_common_reference) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_common_reference_wrapper) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_concepts) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_constexpr_bitset) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_constexpr_charconv) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_constexpr_cmath) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_constexpr_memory) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_constexpr_typeinfo) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_containers_ranges) + COMPILER_FEATURE_ENTRY(202211L, __cpp_lib_expected) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_flat_map) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_flat_set) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_format) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_format_ranges) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_formatters) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_forward_like) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_generator) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_invoke_r) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ios_noreplace) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_is_implicit_lifetime) + COMPILER_FEATURE_ENTRY(202011L, __cpp_lib_is_scoped_enum) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_mdspan) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_modules) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_move_iterator_concept) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_move_only_function) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_optional) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_out_ptr) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_print) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_ranges) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_as_const) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_as_rvalue) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_cartesian_product) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_ranges_chunk) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_ranges_chunk_by) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_contains) + COMPILER_FEATURE_ENTRY(202302L, __cpp_lib_ranges_enumerate) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_find_last) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_fold) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_ranges_iota) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_ranges_join_with) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_repeat) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_ranges_slide) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_ranges_starts_ends_with) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_ranges_stride) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_ranges_to_container) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_ranges_zip) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_reference_from_temporary) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_shift) + COMPILER_FEATURE_ENTRY(202106L, __cpp_lib_spanstream) + COMPILER_FEATURE_ENTRY(202011L, __cpp_lib_stacktrace) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_start_lifetime_as) + COMPILER_FEATURE_ENTRY(202011L, __cpp_lib_stdatomic_h) + COMPILER_FEATURE_ENTRY(202011L, __cpp_lib_string_contains) + COMPILER_FEATURE_ENTRY(202110L, __cpp_lib_string_resize_and_overwrite) + COMPILER_FEATURE_ENTRY(202102L, __cpp_lib_to_underlying) + COMPILER_FEATURE_ENTRY(202207L, __cpp_lib_tuple_like) + COMPILER_FEATURE_ENTRY(202202L, __cpp_lib_unreachable) +}; + +static constexpr CompilerFeature cxx26_core[] = { + //< Continue to Populate + COMPILER_FEATURE_ENTRY(202406L, __cpp_constexpr) + COMPILER_FEATURE_ENTRY(202403L, __cpp_deleted_function) + COMPILER_FEATURE_ENTRY(202406L, __cpp_fold_expressions) + COMPILER_FEATURE_ENTRY(202311L, __cpp_pack_indexing) + COMPILER_FEATURE_ENTRY(202306L, __cpp_placeholder_variables) + COMPILER_FEATURE_ENTRY(202306L, __cpp_static_assert) + COMPILER_FEATURE_ENTRY(202406L, __cpp_structured_bindings) + COMPILER_FEATURE_ENTRY(202403L, __cpp_variadic_friend) +}; +static constexpr CompilerFeature cxx26_lib[] = { + //< Continue to Populate + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_algorithm_default_value_type) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_associative_heterogeneous_insertion) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_atomic_min_max) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_bind_back) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_bind_front) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_bitset) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_chrono) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_constexpr_algorithms) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_constexpr_cmath) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_constexpr_complex) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_constexpr_new) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_constrained_equality) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_copyable_function) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_debugging) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_format) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_format_path) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_format_uchar) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_algorithm) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_array) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_char_traits) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_charconv) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_cstdlib) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_cstring) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_cwchar) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_errc) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_expected) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_feature_test_macros) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_functional) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_iterator) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_mdspan) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_memory) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_numeric) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_operator_new) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_optional) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_ranges) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_ratio) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_string_view) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_tuple) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_freestanding_utility) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_freestanding_variant) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_fstream_native_handle) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_function_ref) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_hazard_pointer) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_inplace_vector) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_is_virtual_base_of) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_is_within_lifetime) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_linalg) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_mdspan) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_not_fn) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_out_ptr) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_optional_range_support) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_philox_engine) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_print) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_ranges) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_ranges_as_const) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_ranges_concat) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_ranges_generate_random) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_ratio) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_rcu) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_reference_wrapper) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_saturation_arithmetic) + COMPILER_FEATURE_ENTRY(202406L, __cpp_lib_senders) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_smart_ptr_owner_equality) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_span) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_span_initializer_list) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_sstream_from_string_view) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_string_view) + COMPILER_FEATURE_ENTRY(202403L, __cpp_lib_submdspan) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_text_encoding) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_to_chars) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_to_string) + COMPILER_FEATURE_ENTRY(202311L, __cpp_lib_tuple_like) + COMPILER_FEATURE_ENTRY(202306L, __cpp_lib_variant) +}; + +static constexpr CompilerFeature cxx29_core[] = { + //< Continue to Populate + COMPILER_FEATURE_ENTRY(202604L, __cpp_core_TODO) +}; +static constexpr CompilerFeature cxx29_lib[] = { + //< Continue to Populate + COMPILER_FEATURE_ENTRY(202604L, __cpp_lib_TODO) +}; + +static constexpr CompilerFeature attributes[] = { + COMPILER_ATTRIBUTE(202207L, assume) + COMPILER_ATTRIBUTE(200809L, carries_dependency) + COMPILER_ATTRIBUTE(201309L, deprecated) + COMPILER_ATTRIBUTE(201603L, fallthrough) + COMPILER_ATTRIBUTE(202403L, indeterminate) + COMPILER_ATTRIBUTE(201803L, likely) + COMPILER_ATTRIBUTE(201603L, maybe_unused) + COMPILER_ATTRIBUTE(201803L, no_unique_address) + COMPILER_ATTRIBUTE(201907L, nodiscard) + COMPILER_ATTRIBUTE(200809L, noreturn) + COMPILER_ATTRIBUTE(201803L, unlikely) +}; + +inline void show_compiler_specific_info() +{ + std::printf("Compiler specific macros:\n"); + for (auto co : compiler) + if (std::strcmp(co.first, co.second)) + std::printf("%*s %s\n", -print.longest_macro_name, co.first, co.second); +} + +inline void print_compiler_feature(const CompilerFeature& x) +{ + if (not ((print.supported_features and x.maybe()) or + (print.unsupported_features and not x.maybe()))) + return; + auto print_year_month = [](long n) + { + return std::printf("%ld%s%02ld", + n / 100, print.separate_year_month ? "-" : "", n % 100); + }; + std::printf("%*s ", -print.longest_macro_name, x.name()); + x.maybe() ? print_year_month(x.data()) : + std::printf("------%s", print.separate_year_month ? "-" : ""); + if (print.standard_values) + std::printf(" %c ", (x.supported() ? (x.data() > x.std() ? '>' : '=') : '<')), + print_year_month(x.std()); + std::puts(""); +} + +template +inline void show(char const* const title, Container const& co) +{ + if (print.titles) + { + std::printf("%-s (", title); + if (print.counters) + { + std::printf("%zd/", std::count_if(std::begin(co), std::end(co), + [](CompilerFeature x) + { + return x.supported(); + })); + } + std::printf("%td)\n", std::distance(std::begin(co), std::end(co))); + } + if (print.sort_by_date) + { + std::vector v(std::begin(co), std::end(co)); + std::stable_sort(v.begin(), v.end(), + [](CompilerFeature const& lhs, CompilerFeature const& rhs) + { + return lhs.data() < rhs.data(); + }); + std::for_each(v.cbegin(), v.cend(), print_compiler_feature); + } + else + std::for_each(std::begin(co), std::end(co), print_compiler_feature); + std::puts(""); +} + +inline void show_latest() +{ + auto latest_rev = []() -> int + { + return print.cxx29 ? 29 : print.cxx26 ? 26 : print.cxx23 ? 23 : print.cxx20 ? 20 : + print.cxx17 ? 17 : print.cxx14 ? 14 : print.cxx11 ? 11 : 98; + }; + std::vector latest; + auto add = [&latest](CompilerFeature x) + { + auto i = std::lower_bound(latest.begin(), latest.end(), x); + if (i == latest.end() or not (*i == x)) + latest.insert(i, x); + else if (i->data() < x.data()) + i->data(x.data()); + }; + char text[64]; + latest.reserve(512); // max macros + if (print.core_features) + { // preserve reverse revision insertion order! + if (print.cxx29) std::for_each(std::begin(cxx29_core), std::end(cxx29_core), add); + if (print.cxx26) std::for_each(std::begin(cxx26_core), std::end(cxx26_core), add); + if (print.cxx23) std::for_each(std::begin(cxx23_core), std::end(cxx23_core), add); + if (print.cxx20) std::for_each(std::begin(cxx20_core), std::end(cxx20_core), add); + if (print.cxx17) std::for_each(std::begin(cxx17_core), std::end(cxx17_core), add); + if (print.cxx14) std::for_each(std::begin(cxx14_core), std::end(cxx14_core), add); + if (print.cxx11) std::for_each(std::begin(cxx11_core), std::end(cxx11_core), add); + if (print.cxx98) std::for_each(std::begin(cxx98_core), std::end(cxx98_core), add); + std::snprintf(text, sizeof text, "ALL CORE MACROS UP TO C++%02i", latest_rev()); + show(text, latest); + } + latest.clear(); + if (print.lib_features) + { // preserve reverse revision insertion order! + if (print.cxx29) std::for_each(std::begin(cxx29_lib), std::end(cxx29_lib), add); + if (print.cxx26) std::for_each(std::begin(cxx26_lib), std::end(cxx26_lib), add); + if (print.cxx23) std::for_each(std::begin(cxx23_lib), std::end(cxx23_lib), add); + if (print.cxx20) std::for_each(std::begin(cxx20_lib), std::end(cxx20_lib), add); + if (print.cxx17) std::for_each(std::begin(cxx17_lib), std::end(cxx17_lib), add); + if (print.cxx14) std::for_each(std::begin(cxx14_lib), std::end(cxx14_lib), add); + std::snprintf(text, sizeof text, "ALL LIB MACROS UP TO C++%02i", latest_rev()); + show(text, latest); + } +} + +int main() +try { + using namespace sw::universal; + + std::string test_suite = "language feature testing"; + std::string test_tag = "C++ language features"; + bool reportTestCases = false; + int nrOfFailedTestCases = 0; + + ReportTestSuiteHeader(test_suite, reportTestCases); + + if (print.separated_revisions) + { + if (print.cxx98 and print.core_features) show("C++98 CORE", cxx98_core); + if (print.cxx11 and print.core_features) show("C++11 CORE", cxx11_core); + if (print.cxx14 and print.core_features) show("C++14 CORE", cxx14_core); + if (print.cxx14 and print.lib_features) show("C++14 LIB", cxx14_lib); + if (print.cxx17 and print.core_features) show("C++17 CORE", cxx17_core); + if (print.cxx17 and print.lib_features) show("C++17 LIB", cxx17_lib); + if (print.cxx20 and print.core_features) show("C++20 CORE", cxx20_core); + if (print.cxx20 and print.lib_features) show("C++20 LIB", cxx20_lib); + if (print.cxx23 and print.core_features) show("C++23 CORE", cxx23_core); + if (print.cxx23 and print.lib_features) show("C++23 LIB", cxx23_lib); + if (print.cxx26 and print.core_features) show("C++26 CORE", cxx26_core); + if (print.cxx26 and print.lib_features) show("C++26 LIB", cxx26_lib); + if (print.cxx29 and print.core_features) show("C++29 CORE", cxx29_core); + if (print.cxx29 and print.lib_features) show("C++29 LIB", cxx29_lib); + } + if (print.latest_revisions) show_latest(); + if (print.attributes) show("ATTRIBUTES", attributes); + if (print.compiler_specific) show_compiler_specific_info(); + + + return EXIT_SUCCESS; +} +catch (const char* const msg) { + std::cerr << msg << std::endl; + return EXIT_FAILURE; +} +catch (...) { + std::cerr << "caught unknown exception" << std::endl; + return EXIT_FAILURE; +} +