From 3da272497fa0435bcdb176105cb908351f9ea075 Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Thu, 6 Aug 2020 12:04:14 -0700 Subject: [PATCH 1/4] Fixes hyperbolic function truncation - Fix integer truncation and off-by-one errors in calculating limit where exp(-x) can be ignored in hyperbolic functions. --- stl/src/xfvalues.cpp | 2 +- stl/src/xlvalues.cpp | 2 +- stl/src/xvalues.cpp | 2 +- tests/std/test.lst | 1 + .../GH_001059_hyperbolic_truncation/env.lst | 4 ++ .../GH_001059_hyperbolic_truncation/test.cpp | 62 +++++++++++++++++++ 6 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 tests/std/tests/GH_001059_hyperbolic_truncation/env.lst create mode 100644 tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp diff --git a/stl/src/xfvalues.cpp b/stl/src/xfvalues.cpp index 5822c050fae..d0329ee4860 100644 --- a/stl/src/xfvalues.cpp +++ b/stl/src/xfvalues.cpp @@ -28,6 +28,6 @@ extern /* const */ _Dconst _FNan = {INIT((_FMAX << _FOFF) | (1 << (_FOFF - 1) extern /* const */ _Dconst _FSnan = {INIT2(_FMAX << _FOFF, 1)}; extern const _Dconst _FRteps = {INIT((_FBIAS - NBITS / 2) << _FOFF)}; -extern const float _FXbig = (NBITS + 1) * 347L / 1000; +extern const float _FXbig = (NBITS + 2) * 0.347f; _END_EXTERN_C_UNLESS_PURE diff --git a/stl/src/xlvalues.cpp b/stl/src/xlvalues.cpp index c2720fe8d16..7ec133738c2 100644 --- a/stl/src/xlvalues.cpp +++ b/stl/src/xlvalues.cpp @@ -26,4 +26,4 @@ extern /* const */ _Dconst _LNan = {INIT((_DMAX << _DOFF) | (1 << (_DOFF - 1) extern /* const */ _Dconst _LSnan = {INIT2(_DMAX << _DOFF, 1)}; extern const _Dconst _LRteps = {INIT((_DBIAS - NBITS / 2) << _DOFF)}; -extern const long double _LXbig = (NBITS + 1) * 347L / 1000; +extern const long double _LXbig = (NBITS + 2) * 0.347L; diff --git a/stl/src/xvalues.cpp b/stl/src/xvalues.cpp index e48d493d42c..1d9a1fb1e30 100644 --- a/stl/src/xvalues.cpp +++ b/stl/src/xvalues.cpp @@ -28,4 +28,4 @@ extern /* const */ _Dconst _Nan = {INIT((_DMAX << _DOFF) | (1 << (_DOFF - 1) extern /* const */ _Dconst _Snan = {INIT2(_DMAX << _DOFF, 1)}; extern const _Dconst _Rteps = {INIT((_DBIAS - NBITS / 2) << _DOFF)}; -extern const double _Xbig = (NBITS + 1) * 347L / 1000; +extern const double _Xbig = (NBITS + 2) * 0.347; diff --git a/tests/std/test.lst b/tests/std/test.lst index 0e60c21053b..34b48abda6f 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -164,6 +164,7 @@ tests\GH_000890_pow_template tests\GH_000940_missing_valarray_copy tests\GH_001010_filesystem_error_encoding tests\GH_001017_discrete_distribution_out_of_range +tests\GH_001059_hyperbolic_truncation tests\GH_001086_partial_sort_copy tests\GH_001103_countl_zero_correctness tests\LWG2597_complex_branch_cut diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/env.lst b/tests/std/tests/GH_001059_hyperbolic_truncation/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp new file mode 100644 index 00000000000..2f2a34cb087 --- /dev/null +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// GH-1059: "Incorrect const float values in xvalues.cpp files" +// The _Xbig constants, used to determine when the exp(-x) terms in +// cosh and sinh can be ignored, have off-by-one and integer +// truncation errors. + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +void Test(T x) { + const complex z{x}; + const T exp_over_2 = T{0.5} * real(exp(z)); + + const T cosh_expected = exp_over_2 + T{0.25} / exp_over_2; + const T cosh_calc = real(cosh(z)); + if (cosh_expected != cosh_calc) { + cout.precision(numeric_limits::digits10 + 2); + cout << "x = " << x << '\n' + << "cosh (expected) = " << cosh_expected << '\n' + << "cosh (calculated) = " << cosh_calc << endl; + assert(cosh_expected == cosh_calc); + } + + const T sinh_expected = exp_over_2 - T{0.25} / exp_over_2; + const T sinh_calc = real(sinh(z)); + if (sinh_expected != sinh_calc) { + cout.precision(numeric_limits::digits10 + 2); + cout << "x = " << x << '\n' + << "sinh (expected) = " << sinh_expected << '\n' + << "sinh (calculated) = " << sinh_calc << endl; + assert(sinh_expected == sinh_calc); + } +} + +template +constexpr array GenerateValues() { + // {old crossover, difference ~ 1 ulp, difference ~ ulp/2} + constexpr int DIG = numeric_limits::digits; + return {DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347)}; +} + +int main() { + constexpr auto fValues{GenerateValues()}; + for (auto x : fValues) + Test(x); + + constexpr auto dValues{GenerateValues()}; + for (auto x : dValues) + Test(x); + + return 0; +} \ No newline at end of file From ecdfab4afd6f481dc641ff1424fecd1dec526ebd Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Wed, 19 Aug 2020 17:32:09 -0700 Subject: [PATCH 2/4] clang-format --- .../GH_001059_hyperbolic_truncation/test.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index 2f2a34cb087..3988831ce9f 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -18,26 +18,26 @@ using namespace std; template void Test(T x) { - const complex z{x}; - const T exp_over_2 = T{0.5} * real(exp(z)); + const complex z{ x }; + const T exp_over_2 = T{ 0.5 } *real(exp(z)); - const T cosh_expected = exp_over_2 + T{0.25} / exp_over_2; - const T cosh_calc = real(cosh(z)); + const T cosh_expected = exp_over_2 + T{ 0.25 } / exp_over_2; + const T cosh_calc = real(cosh(z)); if (cosh_expected != cosh_calc) { cout.precision(numeric_limits::digits10 + 2); cout << "x = " << x << '\n' - << "cosh (expected) = " << cosh_expected << '\n' - << "cosh (calculated) = " << cosh_calc << endl; + << "cosh (expected) = " << cosh_expected << '\n' + << "cosh (calculated) = " << cosh_calc << endl; assert(cosh_expected == cosh_calc); } - const T sinh_expected = exp_over_2 - T{0.25} / exp_over_2; - const T sinh_calc = real(sinh(z)); + const T sinh_expected = exp_over_2 - T{ 0.25 } / exp_over_2; + const T sinh_calc = real(sinh(z)); if (sinh_expected != sinh_calc) { cout.precision(numeric_limits::digits10 + 2); cout << "x = " << x << '\n' - << "sinh (expected) = " << sinh_expected << '\n' - << "sinh (calculated) = " << sinh_calc << endl; + << "sinh (expected) = " << sinh_expected << '\n' + << "sinh (calculated) = " << sinh_calc << endl; assert(sinh_expected == sinh_calc); } } @@ -46,17 +46,17 @@ template constexpr array GenerateValues() { // {old crossover, difference ~ 1 ulp, difference ~ ulp/2} constexpr int DIG = numeric_limits::digits; - return {DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347)}; + return { DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347) }; } int main() { - constexpr auto fValues{GenerateValues()}; + constexpr auto fValues{ GenerateValues() }; for (auto x : fValues) Test(x); - constexpr auto dValues{GenerateValues()}; + constexpr auto dValues{ GenerateValues() }; for (auto x : dValues) Test(x); return 0; -} \ No newline at end of file +} From cb38c344a446ce6f262e07517a1b648dad42ad1b Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Wed, 19 Aug 2020 17:38:40 -0700 Subject: [PATCH 3/4] clang-format --- .../GH_001059_hyperbolic_truncation/test.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index 3988831ce9f..8aee8556437 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -18,26 +18,26 @@ using namespace std; template void Test(T x) { - const complex z{ x }; - const T exp_over_2 = T{ 0.5 } *real(exp(z)); + const complex z{x}; + const T exp_over_2 = T{0.5} * real(exp(z)); - const T cosh_expected = exp_over_2 + T{ 0.25 } / exp_over_2; - const T cosh_calc = real(cosh(z)); + const T cosh_expected = exp_over_2 + T{0.25} / exp_over_2; + const T cosh_calc = real(cosh(z)); if (cosh_expected != cosh_calc) { cout.precision(numeric_limits::digits10 + 2); cout << "x = " << x << '\n' - << "cosh (expected) = " << cosh_expected << '\n' - << "cosh (calculated) = " << cosh_calc << endl; + << "cosh (expected) = " << cosh_expected << '\n' + << "cosh (calculated) = " << cosh_calc << endl; assert(cosh_expected == cosh_calc); } - const T sinh_expected = exp_over_2 - T{ 0.25 } / exp_over_2; - const T sinh_calc = real(sinh(z)); + const T sinh_expected = exp_over_2 - T{0.25} / exp_over_2; + const T sinh_calc = real(sinh(z)); if (sinh_expected != sinh_calc) { cout.precision(numeric_limits::digits10 + 2); cout << "x = " << x << '\n' - << "sinh (expected) = " << sinh_expected << '\n' - << "sinh (calculated) = " << sinh_calc << endl; + << "sinh (expected) = " << sinh_expected << '\n' + << "sinh (calculated) = " << sinh_calc << endl; assert(sinh_expected == sinh_calc); } } @@ -46,15 +46,15 @@ template constexpr array GenerateValues() { // {old crossover, difference ~ 1 ulp, difference ~ ulp/2} constexpr int DIG = numeric_limits::digits; - return { DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347) }; + return {DIG * 347L / 1000L, DIG * static_cast(0.347), (DIG + 1) * static_cast(0.347)}; } int main() { - constexpr auto fValues{ GenerateValues() }; + constexpr auto fValues{GenerateValues()}; for (auto x : fValues) Test(x); - constexpr auto dValues{ GenerateValues() }; + constexpr auto dValues{GenerateValues()}; for (auto x : dValues) Test(x); From b1ac8b2c9c870cc701fb2dcccf2621cc725a232a Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Thu, 20 Aug 2020 18:35:06 -0700 Subject: [PATCH 4/4] Apply suggestions from code review --- tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp index 8aee8556437..67d69e1bb9a 100644 --- a/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp +++ b/tests/std/tests/GH_001059_hyperbolic_truncation/test.cpp @@ -12,7 +12,6 @@ #include #include #include -#include using namespace std; @@ -51,12 +50,14 @@ constexpr array GenerateValues() { int main() { constexpr auto fValues{GenerateValues()}; - for (auto x : fValues) + for (const auto& x : fValues) { Test(x); + } constexpr auto dValues{GenerateValues()}; - for (auto x : dValues) + for (const auto& x : dValues) { Test(x); + } return 0; }