From 679b78809a98568993597acaf00a8ee92163102d Mon Sep 17 00:00:00 2001 From: Ravenwater Date: Fri, 23 Aug 2024 19:16:34 -0400 Subject: [PATCH] code hygiene and creating a string_utils.hpp to collect string utilities --- include/universal/SPDX | 1 + .../universal/common/enumerate_encodings.hpp | 3 +- .../common/number_traits_reports.hpp | 9 ++ include/universal/common/string_utils.hpp | 22 +++++ include/universal/copyright | 1 + .../utility/boolean_logic_operators.hpp | 3 +- include/universal/utility/cmdline.hpp | 2 + include/universal/utility/convert_to.hpp | 3 +- include/universal/utility/directives.hpp | 2 + include/universal/utility/error.hpp | 3 +- include/universal/utility/occurrence.hpp | 5 +- include/universal/utility/reverse_view.hpp | 3 +- include/universal/utility/sampleviz.hpp | 5 +- include/universal/utility/scale_tracker.hpp | 3 +- include/universal/utility/scientific.hpp | 3 +- static/dd/api/api.cpp | 96 +++++++++++++------ static/dd/api/experiments.cpp | 18 +--- static/qd/api/experiments.cpp | 13 +-- 18 files changed, 131 insertions(+), 64 deletions(-) create mode 100644 include/universal/SPDX create mode 100644 include/universal/common/string_utils.hpp create mode 100644 include/universal/copyright diff --git a/include/universal/SPDX b/include/universal/SPDX new file mode 100644 index 000000000..8096cb460 --- /dev/null +++ b/include/universal/SPDX @@ -0,0 +1 @@ +// SPDX-License-Identifier: MIT diff --git a/include/universal/common/enumerate_encodings.hpp b/include/universal/common/enumerate_encodings.hpp index b569debee..eba923965 100644 --- a/include/universal/common/enumerate_encodings.hpp +++ b/include/universal/common/enumerate_encodings.hpp @@ -1,7 +1,8 @@ #pragma once // enumerate_encodings.hpp: enumerate the ordered encodings of an arithmetic type // -// 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. diff --git a/include/universal/common/number_traits_reports.hpp b/include/universal/common/number_traits_reports.hpp index 2ea1dcfe6..a90552d98 100644 --- a/include/universal/common/number_traits_reports.hpp +++ b/include/universal/common/number_traits_reports.hpp @@ -13,6 +13,8 @@ template void numberTraits(std::ostream& ostr) { using namespace std; + auto defaultPrecision = ostr.precision(); + ostr << std::scientific << std::setprecision(numeric_limits::max_digits10); ostr << "std::numeric_limits< " << typeid(Scalar).name() << " >\n"; ostr << "min exponent " << setw(ColumnWidth) << numeric_limits::min_exponent << '\n'; ostr << "max exponent " << setw(ColumnWidth) << numeric_limits::max_exponent << '\n'; @@ -28,6 +30,7 @@ void numberTraits(std::ostream& ostr) { ostr << "quiet_NAN " << setw(ColumnWidth) << numeric_limits::quiet_NaN() << '\n'; ostr << "signaling_NAN " << setw(ColumnWidth) << numeric_limits::signaling_NaN() << '\n'; ostr << '\n'; + ostr << std::setprecision(defaultPrecision); } // compare numeric_limits of two Real types @@ -35,6 +38,8 @@ template void compareNumberTraits(std::ostream& ostr) { using namespace std; + auto defaultPrecision = ostr.precision(); + ostr << std::scientific << std::setprecision(numeric_limits::max_digits10); ostr << "comparing numeric_limits between " << typeid(Type1).name() << " and " << typeid(Type2).name() << '\n'; ostr << " " << setw(ColumnWidth) << typeid(Type1).name() << " vs " << setw(ColumnWidth) << typeid(Type2).name() << '\n'; ostr << "min exponent " << setw(ColumnWidth) << numeric_limits< Type1 >::min_exponent << " vs " << setw(ColumnWidth) << numeric_limits< Type2 >::min_exponent << '\n'; @@ -51,6 +56,7 @@ void compareNumberTraits(std::ostream& ostr) { ostr << "quiet_NAN " << setw(ColumnWidth) << numeric_limits< Type1 >::quiet_NaN() << " vs " << setw(ColumnWidth) << numeric_limits< Type2 >::quiet_NaN() << '\n'; ostr << "signaling_NAN " << setw(ColumnWidth) << numeric_limits< Type1 >::signaling_NaN() << " vs " << setw(ColumnWidth) << numeric_limits< Type2 >::signaling_NaN() << '\n'; ostr << '\n'; + ostr << std::setprecision(defaultPrecision); } // compare numeric_limits of three Real types @@ -58,6 +64,8 @@ template::max_digits10); ostr << "comparing numeric_limits between " << typeid(Type1).name() << " and " << typeid(Type2).name() << " and " << typeid(Type3).name() << '\n'; ostr << " " << setw(ColumnWidth) << typeid(Type1).name() << " vs " << setw(ColumnWidth) << typeid(Type2).name() << " vs " << setw(ColumnWidth) << typeid(Type3).name() << '\n'; ostr << "min exponent " << setw(ColumnWidth) << numeric_limits< Type1 >::min_exponent << setw(ColumnWidth) << numeric_limits< Type2 >::min_exponent << setw(ColumnWidth) << numeric_limits< Type3 >::min_exponent << '\n'; @@ -74,6 +82,7 @@ void threeWayCompareNumberTraits(std::ostream& ostr) { ostr << "quiet_NAN " << setw(ColumnWidth) << numeric_limits< Type1 >::quiet_NaN() << setw(ColumnWidth) << numeric_limits< Type2 >::quiet_NaN() << setw(ColumnWidth) << numeric_limits< Type3 >::quiet_NaN() << '\n'; ostr << "signaling_NAN " << setw(ColumnWidth) << numeric_limits< Type1 >::signaling_NaN() << setw(ColumnWidth) << numeric_limits< Type2 >::signaling_NaN() << setw(ColumnWidth) << numeric_limits< Type3 >::signaling_NaN() << '\n'; ostr << '\n'; + ostr << std::setprecision(defaultPrecision); } }} // namespace sw::universal diff --git a/include/universal/common/string_utils.hpp b/include/universal/common/string_utils.hpp new file mode 100644 index 000000000..83185ec1b --- /dev/null +++ b/include/universal/common/string_utils.hpp @@ -0,0 +1,22 @@ +#pragma once +// string_utils.hpp: utilities to work with std::string +// +// 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 { + + std::string centered(const std::string& label, unsigned columnWidth) { + unsigned length = static_cast(label.length()); + if (columnWidth < length) return label; + + unsigned padding = columnWidth - length; + unsigned leftPadding = (padding >> 1); + unsigned rightPadding = padding - leftPadding; + return std::string(leftPadding, ' ') + label + std::string(rightPadding, ' '); + } + +}} // namespace sw::universal diff --git a/include/universal/copyright b/include/universal/copyright new file mode 100644 index 000000000..af7fb354b --- /dev/null +++ b/include/universal/copyright @@ -0,0 +1 @@ +// Copyright (C) 2017 Stillwater Supercomputing, Inc. diff --git a/include/universal/utility/boolean_logic_operators.hpp b/include/universal/utility/boolean_logic_operators.hpp index 45057905c..739130025 100644 --- a/include/universal/utility/boolean_logic_operators.hpp +++ b/include/universal/utility/boolean_logic_operators.hpp @@ -1,7 +1,8 @@ #pragma once // boolean_logic_operators.hpp : full set of boolean logic operators // -// 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. diff --git a/include/universal/utility/cmdline.hpp b/include/universal/utility/cmdline.hpp index 0119886f7..a688ae9e5 100644 --- a/include/universal/utility/cmdline.hpp +++ b/include/universal/utility/cmdline.hpp @@ -1,4 +1,6 @@ #pragma once +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT #include diff --git a/include/universal/utility/convert_to.hpp b/include/universal/utility/convert_to.hpp index 619210307..ac311e17c 100644 --- a/include/universal/utility/convert_to.hpp +++ b/include/universal/utility/convert_to.hpp @@ -1,7 +1,8 @@ #pragma once // convert_to.hpp: more convenient conversion // -// 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/utility/directives.hpp b/include/universal/utility/directives.hpp index abedff7e9..138c82158 100644 --- a/include/universal/utility/directives.hpp +++ b/include/universal/utility/directives.hpp @@ -1,4 +1,6 @@ #pragma once +// Copyright (C) 2017 Stillwater Supercomputing, Inc. +// SPDX-License-Identifier: MIT // compiler directives #if defined(_MSC_VER) diff --git a/include/universal/utility/error.hpp b/include/universal/utility/error.hpp index 53b059480..abdcca691 100644 --- a/include/universal/utility/error.hpp +++ b/include/universal/utility/error.hpp @@ -1,7 +1,8 @@ #pragma once // error.hpp: utility functions to calculate relative and absolute error // -// 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/utility/occurrence.hpp b/include/universal/utility/occurrence.hpp index c60d86901..5f3291c10 100644 --- a/include/universal/utility/occurrence.hpp +++ b/include/universal/utility/occurrence.hpp @@ -1,7 +1,8 @@ #pragma once // occurrence.hpp: utility object to track arithmetic operation counts during execution of a specific number system // -// 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. @@ -42,4 +43,4 @@ namespace sw { namespace universal { } }; -}} // namespace sw::universal \ No newline at end of file +}} // namespace sw::universal diff --git a/include/universal/utility/reverse_view.hpp b/include/universal/utility/reverse_view.hpp index aff4bb194..8d72a36ec 100644 --- a/include/universal/utility/reverse_view.hpp +++ b/include/universal/utility/reverse_view.hpp @@ -1,7 +1,8 @@ #pragma once // reverse_view.hpp: wrapper function to reverse a container iteration for range based loops // -// 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/utility/sampleviz.hpp b/include/universal/utility/sampleviz.hpp index 8d8c2cb33..49cb75fe4 100644 --- a/include/universal/utility/sampleviz.hpp +++ b/include/universal/utility/sampleviz.hpp @@ -1,7 +1,8 @@ #pragma once // sampleviz.hpp: utility // -// 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. namespace sw { @@ -49,4 +50,4 @@ namespace sw { } } -} } // namespace sw::universal \ No newline at end of file +} } // namespace sw::universal diff --git a/include/universal/utility/scale_tracker.hpp b/include/universal/utility/scale_tracker.hpp index 0093716a8..ec8bbb930 100644 --- a/include/universal/utility/scale_tracker.hpp +++ b/include/universal/utility/scale_tracker.hpp @@ -1,7 +1,8 @@ #pragma once // occurrence.hpp: utility object to track arithmetic operation counts during execution of a specific number system // -// 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/utility/scientific.hpp b/include/universal/utility/scientific.hpp index 91787293b..123bf2194 100644 --- a/include/universal/utility/scientific.hpp +++ b/include/universal/utility/scientific.hpp @@ -1,7 +1,8 @@ #pragma once // scientific.hpp: transform a value into a scientific format string // -// 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/static/dd/api/api.cpp b/static/dd/api/api.cpp index b91fbde25..24e0efe5a 100644 --- a/static/dd/api/api.cpp +++ b/static/dd/api/api.cpp @@ -14,7 +14,8 @@ #include #include #include -#include +//#include // integral part of double-double and quad-double but can be used standalone +#include namespace sw { namespace universal { @@ -114,9 +115,6 @@ namespace sw { } } - - - int main() try { using namespace sw::universal; @@ -196,35 +194,77 @@ try { // fraction bit behavior 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'; + // what is the value that adds a delta one below the least significant fraction bit of the high double? + // dd = high + lo + // = 1*2^0 + 1*2^-53 + // = 1.0e00 + 1.0elog10(2^-53) + double x0{ std::pow(2.0, 0.0) }; + double x1{ std::pow(2.0, -53.0) }; + + // now let's walk that bit down to the ULP + int precisionForRange = 16; + std::cout << std::setprecision(precisionForRange); + x0 = 1.0; + dd a(x0, x1); + std::cout << centered("double-double", precisionForRange + 6) << " : "; + std::cout << centered("binary form of x0", 68) << " : "; + std::cout << centered("real value of x0", 15) << '\n'; + std::cout << a << " : " << to_binary(x0) << " : " << x0 << '\n'; + for (int i = 1; i < 53; ++i) { + x0 = 1.0 + (std::pow(2.0, -double(i))); + a.set(x0, x1); + std::cout << a << " : " << to_binary(x0) << " : " << std::setprecision(7) << x0 << std::setprecision(precisionForRange) << '\n'; + } + // x0 is 1.0 + eps() at this point + std::cout << to_binary(dd(x0, x1)) << '\n'; + x0 = 1.0; + precisionForRange = 32; + std::cout << std::setprecision(precisionForRange); + std::cout << centered("double-double", precisionForRange + 6) << " : "; + std::cout << centered("binary form of x1", 68) << " : "; + std::cout << centered("real value of x1", 15) << '\n'; + for (int i = 0; i < 54; ++i) { + x1 = (std::pow(2.0, -53.0 - double(i))); + a.set(x0, x1); + std::cout << a << " : " << to_binary(x1) << " : " << std::setprecision(7) << x1 << std::setprecision(precisionForRange) << '\n'; + } + std::cout << std::setprecision(defaultPrecision); } - // report on the dynamic range of some standard configurations - std::cout << "+--------- Dynamic range double-double configurations ---------+\n"; + + std::cout << "+--------- set specific values of interest --------+\n"; { dd a; // uninitialized + std::cout << std::setprecision(32); a.maxpos(); - std::cout << "maxpos double-double : " << to_binary(a) << " : " << a << '\n'; + std::cout << "maxpos double-double : " << to_binary(a) << " : " << a << " : " << scale(a) << '\n'; a.setbits(0x0080); // positive min normal - std::cout << "minnorm double-double : " << to_binary(a) << " : " << a << '\n'; + std::cout << "minnorm double-double : " << to_binary(a) << " : " << a << " : " << scale(a) << '\n'; a.minpos(); - std::cout << "minpos double-double : " << to_binary(a) << " : " << a << '\n'; + std::cout << "minpos double-double : " << to_binary(a) << " : " << a << " : " << scale(a) << '\n'; a.zero(); - std::cout << "zero : " << to_binary(a) << " : " << a << '\n'; + std::cout << "zero : " << to_binary(a) << " : " << a << " : " << scale(a) << '\n'; a.minneg(); - std::cout << "minneg double-double : " << to_binary(a) << " : " << a << '\n'; + std::cout << "minneg double-double : " << to_binary(a) << " : " << a << " : " << scale(a) << '\n'; a.maxneg(); - std::cout << "maxneg double-double : " << to_binary(a) << " : " << a << '\n'; - + std::cout << "maxneg double-double : " << to_binary(a) << " : " << a << " : " << scale(a) << '\n'; + std::cout << std::setprecision(defaultPrecision); std::cout << "---\n"; } + std::cout << "+--------- Dynamic range double-double configuration ---------+\n"; + { + std::cout << dynamic_range() << '\n'; + std::cout << dynamic_range() << '\n'; + std::cout << dynamic_range
() << '\n'; + + std::cout << '\n'; + std::cout << symmetry_range() << '\n'; + std::cout << symmetry_range() << '\n'; + std::cout << symmetry_range
() << '\n'; + } + // constexpr and specific values std::cout << "+--------- constexpr and specific values ---------+\n"; { @@ -313,16 +353,7 @@ try { std::cout << std::setprecision(defaultPrecision); } - 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 << "+--------- double-double subnormal behavior --------+\n"; { @@ -364,6 +395,13 @@ try { std::cout << "---------- Unit in the Last Place --------+\n"; { ulp_progression("\nULP progression for dd:\n", dd(10.0)); + + for (int i = -5; i < 6; ++i) { + dd a(std::pow(2.0, double(i))); + dd ulpAtI = ulp(a); + std::string label = "ulpAt
(2^" + std::to_string(i) + ")"; + ReportValue(ulpAtI, label, 20, 32); + } } std::cout << "+--------- numeric_limits of double-double vs IEEE-754 --------+\n"; diff --git a/static/dd/api/experiments.cpp b/static/dd/api/experiments.cpp index ebba7dba3..a4c69e0ad 100644 --- a/static/dd/api/experiments.cpp +++ b/static/dd/api/experiments.cpp @@ -14,7 +14,8 @@ #include #include #include -#include +//#include // integral part of double-double and quad-double but can be used standalone +#include namespace sw { namespace universal { @@ -115,15 +116,6 @@ namespace sw { } } - std::string centered(const std::string& label, unsigned columnWidth) { - unsigned length = static_cast(label.length()); - if (columnWidth < length) return label; - - unsigned padding = columnWidth - length; - unsigned leftPadding = (padding >> 1); - unsigned rightPadding = padding - leftPadding; - return std::string(leftPadding, ' ') + label + std::string(rightPadding, ' '); - } } } @@ -182,10 +174,11 @@ try { double nlo; if (lo == 0.0) { nlo = std::numeric_limits::epsilon() / 2.0; - nlo /= double(1ull << 53); + int binaryExponent = scale(hi) - 53; + nlo /= std::pow(2.0, -binaryExponent); } else { - nlo = std::nextafter(lo, INFINITY); + nlo = (hi < 0.0 ? std::nextafter(lo, -INFINITY) : std::nextafter(lo, +INFINITY)); } dd n(hi, nlo); ReportValue(a, "a = 1.0"); @@ -227,7 +220,6 @@ try { } } - return 0; std::cout << "+---------- unevaluated pairs ------------ +\n"; { // what is the value that adds a delta one below the least significant fraction bit of the high double? diff --git a/static/qd/api/experiments.cpp b/static/qd/api/experiments.cpp index a36dd270a..f5d2c7fe0 100644 --- a/static/qd/api/experiments.cpp +++ b/static/qd/api/experiments.cpp @@ -14,7 +14,8 @@ #include #include #include -#include +//#include // integral part of double-double and quad-double but can be used standalone +#include namespace sw { namespace universal { @@ -75,16 +76,6 @@ namespace sw { return ostr << v.v; } - - std::string centered(const std::string& label, unsigned columnWidth) { - unsigned length = static_cast(label.length()); - if (columnWidth < length) return label; - - unsigned padding = columnWidth - length; - unsigned leftPadding = (padding >> 1); - unsigned rightPadding = padding - leftPadding; - return std::string(leftPadding, ' ') + label + std::string(rightPadding, ' '); - } } }